openapi: 3.1.0 info: title: MIDAS Agents Evidence API version: 1.1.0-rc.1 description: 'Authority governance engine for autonomous decisions. Every evaluation produces exactly one outcome and one tamper-evident audit envelope. ' servers: - url: http://localhost:8080 description: Local development security: - BearerAuth: [] tags: - name: Evidence paths: /v1/evidence/envelopes/{id}/audit-events: get: operationId: getEvidenceEnvelopeAuditEvents summary: Get the runtime audit-event chain for one envelope description: 'Returns the ordered runtime audit-event chain for one evaluation envelope. Events are returned newest-last in SequenceNo ascending order — the same order the runtime appended them. Payloads are returned as recorded; no redaction is applied. This endpoint does NOT return the submitted request payload; use GET /v1/envelopes/{id} for envelope details (which includes the verbatim submitted JSON under the `submitted.raw` field). Read-only. Backed by the production envelope and audit repositories. Disjoint from the Explorer audit-events route (GET /explorer/envelopes/{id}/audit-events), which uses the Explorer-isolated in-memory store and is workbench-only. Requires platform.viewer, platform.operator, or platform.admin. ' parameters: - name: id in: path required: true description: Envelope ID. schema: type: string responses: '200': description: Ordered audit-event chain for the envelope. content: application/json: schema: $ref: '#/components/schemas/RuntimeAuditEventListResponse' '400': description: Missing or invalid envelope ID. content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthenticated. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Insufficient role (requires platform.viewer or above). content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Envelope not found. content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Repository error while reading the audit chain. content: application/json: schema: $ref: '#/components/schemas/Error' '501': description: Evidence read service is not configured on this deployment. content: application/json: schema: $ref: '#/components/schemas/Error' tags: - Evidence /v1/evidence/envelopes/{id}/integrity: get: operationId: getEvidenceEnvelopeIntegrity summary: Verify the audit-event chain integrity for one envelope description: 'Runs the per-envelope integrity verifier against the production audit chain for the specified envelope and returns a structured status report. Integrity findings (a broken chain) are reported with HTTP 200 and `valid: false` — a broken chain is the result being reported, not a transport failure. HTTP 500 is reserved for repository / hash-compute errors that prevent verification from completing. The response does NOT include audit-event payloads, audit-event IDs, the envelope''s submitted request payload, or the envelope''s submitted hash. Callers that need that detail use GET /v1/evidence/envelopes/{id}/audit-events for the chain or GET /v1/envelopes/{id} for envelope detail. Requires platform.viewer, platform.operator, or platform.admin. ' parameters: - name: id in: path required: true description: Envelope ID. schema: type: string responses: '200': description: 'Integrity verification ran to completion. `valid` reports the result: true when every check passed; false when an integrity finding was reported. On `valid: false`, `error_kind` and `error_message` describe the finding. ' content: application/json: schema: $ref: '#/components/schemas/RuntimeEvidenceIntegrityResponse' '400': description: Missing or invalid envelope ID. content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthenticated. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Insufficient role (requires platform.viewer or above). content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Envelope not found. content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Repository or hash-compute error prevented verification from completing. content: application/json: schema: $ref: '#/components/schemas/Error' '501': description: Evidence read service is not configured on this deployment. content: application/json: schema: $ref: '#/components/schemas/Error' tags: - Evidence /v1/evidence/envelopes/{id}/packet: get: operationId: getEvidenceEnvelopePacket summary: Export a decision evidence packet for one envelope description: 'Returns a single decision evidence packet composing the existing production reads for one evaluation envelope: the envelope object (same shape as GET /v1/envelopes/{id}), the ordered audit-event chain (same items as GET /v1/evidence/envelopes/{id}/audit-events), and the per-envelope integrity verification result (same shape as GET /v1/evidence/envelopes/{id}/integrity). Integrity findings are reported in-band: a broken audit chain produces HTTP 200 with `integrity.valid: false`. Repository or verification read failures produce HTTP 500 — the packet is never returned partially. The envelope sub-object preserves the existing /v1/envelopes/{id} contract, including its `submitted.raw` field. The packet wrapper itself has no top-level submitted / raw / submitted_hash field; D30e adds no redaction mode and no query flag toggles that placement. Requires platform.viewer, platform.operator, or platform.admin. ' parameters: - name: id in: path required: true description: Envelope ID. schema: type: string responses: '200': description: Packet composed successfully. `integrity.valid` reports the chain status. content: application/json: schema: $ref: '#/components/schemas/RuntimeEvidencePacket' '400': description: Missing or invalid envelope ID. content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthenticated. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Insufficient role (requires platform.viewer or above). content: application/json: schema: $ref: '#/components/schemas/Error' '404': description: Envelope not found. content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Repository or verification read failure prevented packet composition. content: application/json: schema: $ref: '#/components/schemas/Error' '501': description: Evidence read service is not configured on this deployment. content: application/json: schema: $ref: '#/components/schemas/Error' tags: - Evidence /v1/evidence/audit-events: get: operationId: searchEvidenceAuditEvents summary: Search runtime audit events across envelopes description: 'Returns runtime audit events matching the supplied filter, newest-first by default. Backed by the same audit list primitive that powers /v1/coverage and applies the same hard upper bound (default page size 100, maximum 500). Cross-envelope search complements GET /v1/evidence/envelopes/{id}/audit-events (envelope-scoped chain). Payloads are returned as recorded; no redaction. This endpoint does NOT expose the submitted request payload — use GET /v1/envelopes/{id} for envelope details. payload_contains and offset / page-number pagination are intentionally not exposed; the D30j cursor parameter is the only supported pagination mechanism. Pagination model (D30j): the response carries an optional next_cursor opaque token; clients pass it back verbatim as the cursor query parameter to fetch the next page. The cursor is bound to the order direction of the originating request — replaying a desc cursor against an asc query is rejected with 400. Pagination stops when next_cursor is absent from the response. Requires platform.viewer, platform.operator, or platform.admin. ' parameters: - name: event_type in: query required: false description: Single audit event type. event_types wins when both are supplied. schema: type: string - name: event_types in: query required: false description: 'Comma-separated list of audit event types. Empty tokens are rejected with 400. Whitespace around each token is trimmed. When non-empty, takes precedence over event_type. ' schema: type: string - name: envelope_id in: query required: false description: Exact-match filter on envelope_id. schema: type: string - name: request_source in: query required: false description: Exact-match filter on request_source. schema: type: string - name: request_id in: query required: false description: Exact-match filter on request_id. schema: type: string - name: since in: query required: false description: RFC3339 timestamp; inclusive lower bound on event occurred_at. schema: type: string format: date-time - name: until in: query required: false description: RFC3339 timestamp; exclusive upper bound on event occurred_at. Must not be earlier than since. schema: type: string format: date-time - name: limit in: query required: false description: Positive integer in 1..500. Empty applies the audit-list default page size (100). Oversize values are rejected with 400. schema: type: integer minimum: 1 maximum: 500 - name: order in: query required: false description: Result ordering by occurred_at. Defaults to desc (newest first). schema: type: string enum: - asc - desc - name: cursor in: query required: false description: 'Opaque pagination token from a prior response''s next_cursor (D30j). Pass verbatim — clients must not decode or modify the token. The cursor is bound to the order direction of the originating request; replaying a desc cursor against an asc query is rejected with 400. A malformed token is rejected with 400. ' schema: type: string responses: '200': description: Audit events matching the filter. content: application/json: schema: $ref: '#/components/schemas/RuntimeAuditEventSearchResponse' '400': description: Malformed query parameter (e.g. non-numeric limit, oversize limit, unparseable since/until, until earlier than since, empty event_types token, unknown order value, malformed or order-mismatched cursor). content: application/json: schema: $ref: '#/components/schemas/Error' '401': description: Unauthenticated. content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: Insufficient role (requires platform.viewer or above). content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Repository error while reading audit events. content: application/json: schema: $ref: '#/components/schemas/Error' '501': description: Evidence read service is not configured on this deployment. content: application/json: schema: $ref: '#/components/schemas/Error' tags: - Evidence components: schemas: ResolvedCapabilitySnapshot: type: object description: 'Point-in-time snapshot of one Capability in the BusinessService''s enabling set at evaluation time. The set as a whole is captured as a JSONB array on the envelope; individual entries retain the historical Capability ID even if the live row is later renamed or deleted. ' properties: id: type: string name: type: string origin: type: string managed: type: boolean replaces: type: string status: type: string enum: - active - deprecated Envelope: type: object description: Tamper-evident governance record for a single evaluation. properties: id: type: string state: type: string enum: - received - evaluating - outcome_recorded - escalated - awaiting_review - closed surface_id: type: string agent_id: type: string request_id: type: string request_source: type: string confidence: type: number outcome: type: string reason_code: type: string explanation: type: string profile_id: type: string grant_id: type: string surface_version: type: integer first_event_hash: type: string final_event_hash: type: string resolved: type: object description: 'Resolved facts captured at evaluation time. Currently exposes the service-led structural context added by ADR-0001; existing authority-chain fields remain at the top level for backwards compatibility. ' properties: structure: $ref: '#/components/schemas/ResolvedStructure' created_at: type: string format: date-time closed_at: type: string format: date-time RuntimeAuditEvent: type: object description: 'One audit event in the runtime evidence chain for a governance envelope. Returned by GET /v1/evidence/envelopes/{id}/audit-events (D30b). The shape mirrors the workbench Explorer audit-event response so SIEM and integration consumers can target either route with no transform. Payload is returned as recorded; no redaction is applied at this endpoint. ' required: - id - envelope_id - request_source - request_id - sequence_no - event_type - performer_type - performer_id - payload - occurred_at - hash properties: id: type: string description: Stable audit-event identifier. envelope_id: type: string description: Envelope this event belongs to. request_source: type: string description: Source system identifier from the originating evaluation. request_id: type: string description: Request identifier from the originating evaluation. sequence_no: type: integer description: 1-based per-envelope sequence number; monotonic in append order. event_type: type: string description: 'Event-type identifier from the runtime audit chain. The set of event types is runtime-internal and intentionally not enumerated in this spec; values cover envelope lifecycle, evaluation-step, and governance evidence events. ' performer_type: type: string description: Performer category (e.g. system, user, service). performer_id: type: string description: Identifier of the performer that produced the event. payload: type: object description: 'Event-specific payload as recorded by the runtime. Field shape varies per event_type; consumers should treat the object as free-form JSON and key off event_type when extracting specific fields. ' additionalProperties: true occurred_at: type: string format: date-time description: When the runtime recorded the event. hash: type: string description: SHA-256 hash of this event in the per-envelope audit chain. prev_hash: type: string description: 'SHA-256 hash of the previous event in the chain. Omitted on the first event of an envelope''s chain (sequence_no=1). ' Error: type: object required: - error properties: error: type: string RuntimeEvidencePacket: type: object description: 'Response wrapper for GET /v1/evidence/envelopes/{id}/packet (D30e). Composes three existing runtime evidence reads — envelope detail, the ordered audit-event chain, and the per-envelope integrity verification result — into one export-friendly object. Adds no new shapes: each composed section uses the same schema as its standalone endpoint. Integrity findings are reported in-band via the embedded `integrity.valid` field. A `valid: false` result indicates a broken audit chain; the packet itself still completed successfully and returns HTTP 200. Repository or verification read failures produce HTTP 500 — the packet is never returned partially. `submitted.raw` appears only inside the embedded envelope object, preserving the GET /v1/envelopes/{id} contract. The wrapper has no top-level submitted / raw / submitted_hash field. D30e adds no redaction mode. ' required: - envelope_id - generated_at - envelope - audit_events - integrity properties: envelope_id: type: string description: Envelope the packet was composed for. Matches Envelope.identity.id. generated_at: type: string format: date-time description: UTC timestamp at which the handler composed the packet. envelope: $ref: '#/components/schemas/Envelope' audit_events: type: array description: Ordered audit-event chain for the envelope (SequenceNo ascending). Same item shape as GET /v1/evidence/envelopes/{id}/audit-events. items: $ref: '#/components/schemas/RuntimeAuditEvent' integrity: $ref: '#/components/schemas/RuntimeEvidenceIntegrityResponse' ResolvedBusinessServiceSnapshot: type: object description: 'Point-in-time snapshot of the BusinessService that owned the resolved Process at evaluation time. See ADR-0001. ' properties: id: type: string origin: type: string managed: type: boolean replaces: type: string status: type: string enum: - active - deprecated RuntimeEvidenceIntegrityResponse: type: object description: 'Response wrapper for GET /v1/evidence/envelopes/{id}/integrity (D30d). Reports the integrity status of the audit-event chain for one envelope. `valid` is true only when every check passes. On `valid: false`, `error_kind` and `error_message` describe the finding; on `valid: true` those fields are omitted. `first_event_hash` and `final_event_hash` come from the observed audit chain (the first and last event''s stored hashes), not from the envelope''s recorded integrity anchors; cross-checking those anchors is out of scope for this tranche. `checked_at` is the timestamp at which the verifier ran. The verifier is stateless and can be re-run idempotently. ' required: - envelope_id - valid - chain_length - first_event_hash - final_event_hash - checked_at properties: envelope_id: type: string description: Envelope the integrity check was performed on. valid: type: boolean description: True when every chain-integrity check passed; false when an integrity finding is reported. chain_length: type: integer description: Number of audit events observed in the chain. Zero when error_kind is "missing_events". first_event_hash: type: string description: Stored hash of the first audit event in the observed chain. Empty string when the chain is empty. final_event_hash: type: string description: Stored hash of the last audit event in the observed chain. Empty string when the chain is empty. checked_at: type: string format: date-time description: UTC timestamp at which the verifier ran. error_kind: type: string description: 'Stable taxonomy of the integrity finding when `valid` is false. One of: "missing_events", "sequence_gap", "prev_hash_mismatch", "event_hash_mismatch", "terminal_state_mismatch", or "unknown" (defensive fallback). Omitted when `valid` is true. ' error_message: type: string description: Human-readable diagnostic for the integrity finding. Omitted when `valid` is true. RuntimeAuditEventListResponse: type: object description: 'Response wrapper for GET /v1/evidence/envelopes/{id}/audit-events. items is always present (empty list for envelopes with no events recorded — an operationally-impossible state in practice, since every persisted envelope has at least lifecycle events). count equals len(items). The endpoint does not paginate; audit chains are bounded by evaluation step count. ' required: - envelope_id - items - count properties: envelope_id: type: string description: Envelope the chain was retrieved for. items: type: array description: Ordered audit events (SequenceNo ascending). items: $ref: '#/components/schemas/RuntimeAuditEvent' count: type: integer description: Number of events returned. Equals len(items). RuntimeAuditEventSearchResponse: type: object description: 'Response wrapper for GET /v1/evidence/audit-events (D30c). Cross-envelope search results: items may span multiple envelopes, so the wrapper deliberately omits the envelope_id field that the per-envelope chain response carries. items is always present (empty list is an empty array). count equals len(items). The endpoint applies the audit-list default page size (100) when limit is unset, capped at the maximum (500). D30j adds next_cursor: an opaque pagination token clients pass back verbatim as the cursor query parameter to retrieve the next page under the same query. The field is absent when no further pages exist; clients use field presence as the stop signal rather than comparing counts. ' required: - items - count properties: items: type: array description: Audit events matching the filter, ordered by occurred_at per the order query parameter. items: $ref: '#/components/schemas/RuntimeAuditEvent' count: type: integer description: Number of events returned. Equals len(items). next_cursor: type: string description: 'Opaque pagination token (D30j). Pass verbatim as the cursor query parameter to retrieve the next page under the same query. Absent when no further pages exist. Bound to the order direction of the originating request: replaying a desc-bound cursor against an asc query is rejected with 400. ' ResolvedProcessSnapshot: type: object description: 'Point-in-time snapshot of the Process the resolved Surface belonged to at evaluation time. Captured as evidence on the envelope per ADR-0001; not derived from live joins after the envelope is written. ' properties: id: type: string origin: type: string description: Always "manual" in v1. managed: type: boolean replaces: type: string description: ID of a previously-superseded Process; empty string when none. status: type: string enum: - active - deprecated ResolvedStructure: type: object description: 'Service-led structural context resolved at evaluation time: the Process the Surface belongs to, the BusinessService that owns the Process, and the set of Capabilities enabling the BusinessService at the moment the decision was recorded. Empty enabling_capabilities arrays are valid and are serialised as `[]` (never `null`). Per ADR-0001. ' properties: process: $ref: '#/components/schemas/ResolvedProcessSnapshot' business_service: $ref: '#/components/schemas/ResolvedBusinessServiceSnapshot' enabling_capabilities: type: array items: $ref: '#/components/schemas/ResolvedCapabilitySnapshot' description: 'Capabilities enabling this BusinessService at evaluation time, sorted by id ascending for deterministic byte-level evidence. ' securitySchemes: BearerAuth: type: http scheme: bearer description: 'Static bearer token. Configured via MIDAS_AUTH_TOKENS or midas.yaml auth.tokens. Not required when auth.mode=open (development only). '