Files
ruvnet--RuView/api-docs/adr/ADR-304-evidence-engine.md
T
2026-08-11 17:41:30 +00:00

118 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-304: Evidence engine — MLflow for physical sensing
- **Status**: Accepted — initial implementation planned (ADR-300 phase 1)
- **Date**: 2026-08-11
- **Deciders**: ruv
- **Tags**: evidence, provenance, ledger, accuracy, drift, benchmark, honesty, substrate
## Context
This ADR is primitive 4 of the perception-substrate program (ADR-300) and a
central pillar of the phase-1 certificate spine. It consumes the domain state
from out-of-distribution detection (ADR-302) and the calibration age from the
calibration certificate (ADR-301), it is the store that capability certificates
(ADR-318) are minted from, and it is the accuracy source the real benchmark
service (ADR-317) reads. In phase 2 it ingests agreement reports from the
ground-truth plane (ADR-303).
The strategic assessment (ADR-300) judged this primitive **more commercially
important than another pose architecture**: what unblocks OEM and integrator
conversations is not a higher headline number but a defensible, auditable record
of how a model actually performs, per room, per device, per subject, over time.
MLflow made ML experiments trackable; physical sensing needs the equivalent for
deployed accuracy, drift, and evidence level — an append-only ledger, not a
dashboard that overwrites yesterday's number.
RuView already has the constituent evidence types; what is missing is the ledger
that unifies them per deployment context:
- RuField provenance/signature types (ADR-260/262/277/279) — the signed,
provenance-bearing record types to reuse rather than reinvent.
- The AetherArena witness-ledger pattern (ADR-149) — an append-only,
witness-anchored ledger of scored results, the structural template here.
- `frame::EvidenceLevel` L0L5 (ADR-282) — the mandatory evidence tag every
record carries.
- ADR-302 `DomainState`, ADR-137 `QualityScore`, ADR-301 certificate version
and age — the per-inference signals to accumulate.
## Options considered
1. **Log accuracy to flat files / metrics dashboards.** Rejected: mutable,
un-signed, un-scoped, and not comparable over time — the exact gap.
2. **Reuse a general experiment tracker (MLflow itself).** Rejected: it is
experiment-time, not deployment-time; it has no notion of room/device/
subject context, calibration age, evidence level, or signed provenance, and
it would add an external service dependency contrary to the substrate's
edge-first, dependency-light direction.
3. **A native append-only evidence ledger reusing RuField record types and the
AetherArena ledger pattern.** Chosen.
## Decision
Build an **evidence engine**: a per-`(room, device, subject)` append-only
accuracy ledger that every model automatically writes to.
### 1. The evidence record
- An `EvidenceRecord` keyed by context — space id (ADR-306), signed device id
(ADR-305), and subject id where consented and available — carrying: model
version; calibration certificate version and **age** (ADR-301); the ADR-302
`DomainState` (KNOWN/DEGRADED/UNKNOWN) and its four inputs; the ADR-137
quality signals; predictive uncertainty; and, when a reference is present
(ADR-303), the agreement result (accuracy, false-positive rate). Each record
carries exactly one `EvidenceLevel` (L0L5, ADR-282).
- Records are **append-only** and signed with RuField signature types
(ADR-260/262/277/279); the ledger is anchored in the witness chain (ADR-319),
following the AetherArena witness-ledger pattern (ADR-149). No record is ever
mutated in place — a correction is a new record.
### 2. Per-context accuracy accounting
- The engine maintains, per `(room, device, subject)` context: measured
accuracy (only where an ADR-303 reference backs it — otherwise the record is
CLAIMED/SYNTHETIC, never MEASURED), false-positive rate, drift trajectory
(fingerprint distance over time from ADR-301), the fraction of inferences in
each domain state, calibration age distribution, and model-version history.
- Aggregation is a pure function over the append-only log at a queried time —
the ledger is the source of truth; summaries are derived, never authoritative
(mirroring CLAUDE.md's "source over summaries" rule).
### 3. Honesty enforced in the record
- The engine cannot upgrade an evidence level; a level is set by the record's
provenance at write time (synthetic input → L0/`Synthetic`; no reference →
CLAIMED; reference + reproducer → MEASURED), reusing the ADR-282/ADR-291/
ADR-293 constructor discipline. A benchmark or certificate reading the ledger
gets the honest level, not an optimistic rollup.
- No benchmark numbers are invented by this ADR; it delivers the ledger and the
accounting. Empty contexts report "no evidence," which downstream (ADR-318)
must treat as no capability.
## Consequences
- RuView gains a single auditable answer to "how well does this model actually
work, here, on this device, for this subject, and how fresh is the
calibration?" — the artifact OEM/integrator diligence actually asks for.
- ADR-318 capability certificates become derivable (a certificate is a signed
attestation over a slice of the ledger) and ADR-317 gains a real accuracy
source per PR instead of self-reported numbers.
- The append-only, signed design has storage and key-management cost; bounded
by per-context retention policy and by reusing the existing RuField/witness
infrastructure rather than a new store.
- Some contexts will show sparse or unflattering evidence. Surfacing that is the
point; the engine must never paper over a thin context with a global average.
## Validation
- `cargo test` on the evidence-engine crate — append-only invariant (no
in-place mutation; corrections are new records); per-context aggregation math
against fixtures; evidence-level is set by provenance and cannot be upgraded;
signature round-trip and tamper rejection; witness anchoring; empty-context
queries return "no evidence" not a fabricated number.
- Cross-ADR: ingests ADR-302 `DomainState` and (phase 2) ADR-303 agreement
reports; an ADR-318 test mints a certificate from a ledger slice and an
ADR-317 test reads accuracy from the ledger.
- Real-deployment evidence (a populated ledger from live ESP32 captures with
ADR-303 references) is the maturity milestone and requires hardware evidence
per CLAUDE.md; a synthetic ledger is L0 by construction.