Audit API
Table of Contents
upsquad/audit/v1/audit.proto
ActorIdentity
ActorIdentity is the resolved actor for an audit event.
| Field | Type | Label | Description |
|---|---|---|---|
| agent_id | string | agent_id mirrors event.agent_id for client convenience. | |
| name | string | name is the agent's human-readable name (agents.name). | |
| team_id | string | team_id is the agent's team UUID (agents.team_id). | |
| clearance | int32 | clearance is the agent's clearance level (agents.clearance, 1..5). |
AuditEvent
AuditEvent represents a single row from the agent_audit_log table.
| Field | Type | Label | Description |
|---|---|---|---|
| event_id | string | event_id is the primary key (UUID). | |
| timestamp | google.protobuf.Timestamp | timestamp is when the event was created. | |
| agent_id | string | agent_id is the agent that performed the action. | |
| session_id | string | session_id is the session in which the action occurred. | |
| action_type | string | action_type is the type of action (e.g. "tool_call", "llm_call"). | |
| input_hash | string | input_hash is the hash of the action input. | |
| output_hash | string | output_hash is the hash of the action output. | |
| detail | string | detail is the JSONB detail column serialised as a JSON string. | |
| duration_ms | int32 | duration_ms is the action duration in milliseconds. | |
| token_usage | string | token_usage is the JSONB token usage column serialised as a JSON string. |
DeleteViewRequest
DeleteViewRequest soft-deletes a saved view by id.
| Field | Type | Label | Description |
|---|---|---|---|
| id | string | id is the saved-view UUID to delete. Must match an undeleted row in the calling auditor's tenant. NotFound otherwise. |
DeleteViewResponse
DeleteViewResponse is intentionally empty — the soft-delete is the success signal.
ExplainEventRequest
ExplainEventRequest selects a single audit event by id. org_id is taken from the gateway-injected metadata; request-body org_id is ignored. GAP-15.
| Field | Type | Label | Description |
|---|---|---|---|
| event_id | string | event_id is the agent_audit_log row id to explain. Required. | |
| related_window | int32 | related_window caps the number of preceding + following session events returned in related_events. Clamped to [1, 25]; default 10 (5 before + 5 after, when available). |
ExplainEventResponse
ExplainEventResponse bundles the structured breakdown of an audit event for the redesigned drawer. Every field is server-rendered: the client portal does no further enrichment beyond presentation. GAP-15.
| Field | Type | Label | Description |
|---|---|---|---|
| event | AuditEvent | event is the verbatim audit row (matches the AuditEvent message returned by ListAuditEvents). | |
| actor | ActorIdentity | actor is the resolved agent identity (name, team, clearance) for event.agent_id. Nil for gateway-plane events whose agent_id is empty. | |
| resource | ResourceRef | resource is the affected target inferred from the event detail (tool name, model id, etc.). Nil when the event has no obvious target (e.g. session_started). | |
| payload_pretty | string | payload_pretty is event.detail re-marshalled with sorted keys and 2-space indentation for direct rendering in the drawer's <pre> panel. Empty when detail is empty. | |
| related_events | AuditEvent | repeated | related_events is the preceding + following slice of the same session ordered by created_at ASC. Includes the requested event itself for client-side highlight by event_id. Capped by ExplainEventRequest.related_window. |
| narrative | string | narrative is a deterministic one-line plain-English summary of the event (e.g. "An AI agent on the Customer Support team called tool Stripe.refundCreate. The action was scoped to standard clearance and the system returned ALLOWED."). Server-rendered so every client gets the same wording. Always non-empty. | |
| narrative_source | NarrativeSource | narrative_source documents how the narrative was produced. Today only DETERMINISTIC is emitted; the field exists so a future wave can swap in an LLM-cached narrative without a wire break. |
ListAuditEventsRequest
ListAuditEventsRequest carries optional filters and pagination for querying the agent_audit_log table. All filters are optional; omitting a filter means "match all" for that dimension. Results are returned newest-first.
| Field | Type | Label | Description |
|---|---|---|---|
| start_time | google.protobuf.Timestamp | optional | start_time lower-bounds the created_at filter (inclusive). |
| end_time | google.protobuf.Timestamp | optional | end_time upper-bounds the created_at filter (exclusive). |
| agent_id | string | optional | agent_id filters events to a single agent. |
| action_type | string | optional | action_type filters events by action type (e.g. "tool_call", "llm_call"). |
| page | int32 | page is the 1-based page number. Defaults to 1. | |
| page_size | int32 | page_size is the number of events per page. Max 100, default 50. | |
| verdict | string | repeated | verdict filters events by UI-level verdict bucket. Accepted values: "PASS" |
| clearance | int32 | repeated | clearance filters events to those produced by agents whose clearance level is in the given set (1..5). Multiple values are OR-ed; an empty list is treated as "match all". Events with NULL agent_id (gateway-plane config events) are excluded when this filter is non-empty. |
| query | string | query is a free-text needle matched case-insensitively against agent_id, session_id, action_type, and the JSONB detail blob. An empty string is treated as "match all". |
ListAuditEventsResponse
ListAuditEventsResponse carries a page of audit events plus total count.
| Field | Type | Label | Description |
|---|---|---|---|
| events | AuditEvent | repeated | events is the list of audit events for the requested page. |
| total_count | int32 | total_count is the total number of events matching the filters. |
ListSavedViewsRequest
ListSavedViewsRequest is owner-scoped by construction; no filters yet.
ListSavedViewsResponse
ListSavedViewsResponse carries the calling auditor's saved view rail, sorted by last_used_at DESC NULLS LAST, then created_at DESC.
| Field | Type | Label | Description |
|---|---|---|---|
| views | SavedView | repeated | views is the calling auditor's saved view rail. Empty when the auditor has not persisted any views yet. |
OrgDateScope
OrgDateScope verifies every chained session for org in [since, until). Empty since / until disables that bound.
| Field | Type | Label | Description |
|---|---|---|---|
| org_id | string | org_id is populated from gateway claims (see SessionScope.org_id). | |
| since | google.protobuf.Timestamp | since lower-bounds the walk (inclusive). Empty = no lower bound. | |
| until | google.protobuf.Timestamp | until upper-bounds the walk (exclusive). Empty = no upper bound. |
ResourceRef
ResourceRef is a best-effort reference to the target the action touched. Inferred from event.detail; not authoritative.
| Field | Type | Label | Description |
|---|---|---|---|
| kind | string | kind is a short string ("tool", "model", "approval", "session", "config", "subagent"). Empty when no target was inferable. | |
| name | string | name is the human-readable identifier ("github.create_pr", "claude-sonnet-4-20250514", session id, …). Empty when not inferable. |
SaveViewRequest
SaveViewRequest persists a new saved view for the calling auditor.
| Field | Type | Label | Description |
|---|---|---|---|
| name | string | name is the human-friendly label (1-120 chars after trim). The (owner, name) pair must be unique within the tenant; collision is mapped to AlreadyExists. | |
| filters | ListAuditEventsRequest | filters is the ListAuditEventsRequest shape to persist. |
SaveViewResponse
SaveViewResponse returns the persisted view — including the server-generated id, created_at, and updated_at.
| Field | Type | Label | Description |
|---|---|---|---|
| view | SavedView | view is the persisted saved view, including the server-generated id, created_at, and updated_at. |
SavedView
SavedView is one row of the audit_saved_views ledger surfaced to the client portal saved-views rail. See migration 088.
| Field | Type | Label | Description |
|---|---|---|---|
| id | string | id is the saved-view UUID. | |
| name | string | name is the human-friendly label (max 120 chars). | |
| filters | ListAuditEventsRequest | filters is the verbatim ListAuditEventsRequest filter shape that gets re-applied when the view is recalled. | |
| owner_member_id | string | owner_member_id is the member id that created the view. The service populates this from the authenticated context — request-body values are ignored. | |
| created_at | google.protobuf.Timestamp | created_at is when the view was first persisted. | |
| updated_at | google.protobuf.Timestamp | updated_at is when the view was last mutated (saved or recalled). | |
| last_used_at | google.protobuf.Timestamp | optional | last_used_at is when the view was most recently materialised back into a ListAuditEvents call. Empty for freshly created views. |
SessionScope
SessionScope verifies the chain for a single (org, session).
| Field | Type | Label | Description |
|---|---|---|---|
| org_id | string | org_id is populated from gateway claims; request-body value is ignored and the claims value always takes precedence. | |
| session_id | string | session_id is the session whose chain to verify. |
TaskScope
TaskScope verifies a single Task's coordinator_audit_log chain (#1248).
| Field | Type | Label | Description |
|---|---|---|---|
| org_id | string | org_id is populated from gateway claims; the request-body value is ignored and the claims value always takes precedence (tenant isolation, mirroring SessionScope.org_id). | |
| task_id | string | task_id is the Task whose coordinator_audit_log chain to verify. |
VerifyChainRequest
VerifyChainRequest selects the scope to verify. Exactly one of the scope oneof variants must be set.
| Field | Type | Label | Description |
|---|---|---|---|
| session | SessionScope | session verifies a single (org, session) chain. | |
| org_range | OrgDateScope | org_range verifies every chained session in an org across a date range. | |
| task | TaskScope | task verifies a single Task's coordinator_audit_log chain — the Coordinator's per-Task hash-chained audit surface (ADR-0015, migration 093), separate from agent_audit_log (session/org). Added for #1248 (D1 audit track): the platform's audit surface now spans two chains and VerifyChain must cover both. |
VerifyChainResponse
VerifyChainResponse reports the outcome of a verifier walk.
| Field | Type | Label | Description |
|---|---|---|---|
| ok | bool | ok is true only when every chain_epoch>=1 row in scope linked correctly (prev_hash / row_hash / content invariants all held). | |
| total_rows | int32 | total_rows is the count of chained rows inspected. | |
| broken_at_row | int32 | broken_at_row is 1-based within the failing session; 0 when ok. | |
| broken_row_id | string | broken_row_id is the id of the first offending row; empty when ok. | |
| session_id | string | session_id echoes the failing session (session scope) or the first broken session (org scope). Empty when ok. | |
| verified_at | google.protobuf.Timestamp | verified_at is the wall-clock time the walk completed. | |
| sessions_verified | int32 | sessions_verified is the number of chained sessions walked (org scope). | |
| sessions_broken | int32 | sessions_broken is the number of sessions that broke (org scope). | |
| broken_reason | string | broken_reason is a human-readable reason for the first break; empty when ok. |
NarrativeSource
NarrativeSource documents how ExplainEventResponse.narrative was produced.
| Name | Number | Description |
|---|---|---|
| NARRATIVE_SOURCE_UNSPECIFIED | 0 | UNSPECIFIED: zero value reserved for unset / unknown. The handler never emits this — every response carries an explicit source. |
| NARRATIVE_SOURCE_DETERMINISTIC | 1 | DETERMINISTIC: server template applied to event fields. No external call. Stable wording across calls. |
| NARRATIVE_SOURCE_LLM_CACHED | 2 | LLM_CACHED: pre-computed via the platform LLM gateway and persisted alongside the row. Reserved for a follow-up wave; not emitted today. |
AuditService
AuditService exposes the tenant-facing audit-log read surface: a paginated event list and the hash-chain verifier. Both RPCs are gated at the gateway by COMPLIANCE_AUDITOR clearance (L4 Director) and RLS-scoped to the caller's org. See LLD §5.
| Method Name | Request Type | Response Type | Description |
|---|---|---|---|
| ListAuditEvents | ListAuditEventsRequest | ListAuditEventsResponse | ListAuditEvents returns a paginated list of audit log entries for the calling tenant, with optional time-range and attribute filters. org_id is injected by the gateway from verified JWT claims — callers MUST NOT supply it in the request body. |
| VerifyChain | VerifyChainRequest | VerifyChainResponse | VerifyChain walks the audit-log hash chain for the requested scope and reports integrity. Scopes: a single session, or an org over a date range. See docs/lld/wave1-item4-audit-hash-chain.md. |
| ListSavedViews | ListSavedViewsRequest | ListSavedViewsResponse | ListSavedViews returns the calling auditor's saved view rail, sorted by recently-used (last_used_at DESC NULLS LAST, then created_at). GAP-14 (#1080). Owner-scoped: an auditor only sees views they created. Soft-deleted views are excluded. |
| SaveView | SaveViewRequest | SaveViewResponse | SaveView persists a new saved view scoped to the calling auditor. The (owner, name) pair must be unique within the tenant — the service maps the conflict to AlreadyExists. GAP-14. |
| DeleteView | DeleteViewRequest | DeleteViewResponse | DeleteView soft-deletes a saved view. The owner can always delete their own view; deletion of someone else's view is rejected PermissionDenied (the AuditService clearance gate already restricts this RPC to COMPLIANCE_AUDITOR + above; a per-row owner check on top of that prevents two L4 auditors from clobbering each other's rails). GAP-14. |
| ExplainEvent | ExplainEventRequest | ExplainEventResponse | ExplainEvent returns a structured breakdown of a single audit event for the redesigned drawer (audit-log.jsx EventDrawer). The response bundles: actor identity (resolved from agents row), full event payload pretty-printed, the related-event chain (preceding + following events sharing the same session), and a deterministic one-line plain-English summary suitable for the drawer's "Plain-English explanation" panel. RLS-scoped via gateway-injected org_id; clearance-gated to COMPLIANCE_AUDITOR + above. GAP-15 (#1081). |
Scalar Value Types
| .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby |
|---|---|---|---|---|---|---|---|---|
| double | double | double | float | float64 | double | float | Float | |
| float | float | float | float | float32 | float | float | Float | |
| int32 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| int64 | Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| uint32 | Uses variable-length encoding. | uint32 | int | int/long | uint32 | uint | integer | Bignum or Fixnum (as required) |
| uint64 | Uses variable-length encoding. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum or Fixnum (as required) |
| sint32 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| sint64 | Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| fixed32 | Always four bytes. More efficient than uint32 if values are often greater than 2^28. | uint32 | int | int | uint32 | uint | integer | Bignum or Fixnum (as required) |
| fixed64 | Always eight bytes. More efficient than uint64 if values are often greater than 2^56. | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum |
| sfixed32 | Always four bytes. | int32 | int | int | int32 | int | integer | Bignum or Fixnum (as required) |
| sfixed64 | Always eight bytes. | int64 | long | int/long | int64 | long | integer/string | Bignum |
| bool | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass | |
| string | A string must always contain UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode | string | string | string | String (UTF-8) |
| bytes | May contain any arbitrary sequence of bytes. | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |