Skip to content

ADR-0016: Evidence assembled on demand, no materialized store

Status: Accepted — 003-governance-depth (2026-07) Principles served: III, IV Source: specs/003-governance-depth/research.md G-4

Context

Every app's full history — prompts, model versions, tests, approvals, deployments, declared scopes, and per-app data access — must be queryable per app, within a 10-second budget (SC-003). The facts live in five places already: the App CR, Gitea, Harbor, the data gateway's access log, and Argo CD-driven promotion records. Principle IV forbids a second authoritative store, so the question is whether to index those sources or read them live.

Decision

The evidence index (in services/evidence-estate-api) is a parallel fan-out assembler behind the existing EvidenceRecord shape. Sources, each with a roughly 5-second timeout, are fanned out concurrently and merged:

  • the App CR (authoritative core: scopes, purpose, promotion status),
  • the Gitea API (commit history with builder-recorded prompt hashes, plus promotion PR metadata),
  • the Harbor API (artifact list and attestation digests, corroborating the CR's attestation refs; test results come from the Chains-recorded attestation predicates via Harbor),
  • the data gateway's query API (per-app access records, allows and denials).

Assembly is on demand with a short TTL cache (60 seconds). There is no materialized store: no incremental indexer means no second authoritative store to keep honest (Principle IV). Degradation is explicit — each unreachable source marks its categories in the response's per-category completeness map (complete/partial/unavailable), with a provenance map naming the source behind each category, so partial answers are labeled, never silently missing. (The research phase sketched this as a flat incomplete list; the shipped contract carries the richer per-category maps — see the evidence API reference.)

Alternatives considered

  • Background incremental indexer with a materialized store — rejected for now: a second store to keep honest; revisit if app count or audit-query latency breaks SC-003.
  • Webhook-driven event log — rejected: replay/backfill complexity without a scale need.

Consequences

At tens of apps, a handful of parallel HTTP calls comfortably beat the 10-second budget (proven at ~0.3 s against fakes at realistic latency), and evidence is always as fresh as its sources. Auditors get honesty by construction: a degraded source yields a labeled gap, not a fabricated blank. The recorded revisit trigger is growth — if app count or audit-query latency ever breaks SC-003, the indexer alternative is reconsidered.