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.