ADR-0004: Statement-backing is opt-in per attribute
ADR-0004: Statement-backing is opt-in per attribute
Status
Accepted
Date
2026-06-24
Context
The kernel’s most distinctive bet is that “important real-world facts should be Statements, not only mutable properties” — a Statement carrying source, actor, evidence, confidence, validTime, transactionTime, and authority, with the Projection Engine selecting the current value via authority/conflict rules. The proving case (POC 6): GIS says geometry A, a field survey says geometry B, a supervisor approves B, the projection serves B, and history retains both.
The pack never draws the line between a “fact” (worth the full Statement machinery) and an ordinary attribute. That line is load-bearing. A Statement carries seven dimensions of metadata; attaching all of it to every attribute — a status pill, a comment, a created_at — is crushing write/storage/projection overhead and buries the genuinely contested facts in ceremony. Too narrow, and we lose the differentiator.
Decision
Statement-backing is opt-in per attribute, declared in schema. The default attribute is a plain value, mutated directly by an Action, fully audited via the event log (last-write-by-action). Only source-reconciled / contested facts — those that multiple independent sources assert and that may disagree — are declared statement-backed (via a trait such as evidence.EvidenceBacked or an Asserted<T> value-type wrapper).
Statement-backed attributes get the full Statement → Authority → Projection treatment, including conflict resolution. Plain attributes do not. Canonical statement-backed examples: geometry, capacity, as-built measurements. Canonical plain examples: workflow status, comments, system timestamps.
Alternatives Considered
Statement-backed by default
All domain facts are statements; only system/UI metadata stays plain.
- Rejected: maximal provenance everywhere at heavy write/storage/projection cost, for facts that are never actually contested.
Everything is a Statement
No plain attributes at all.
- Rejected: purest model, highest cost, no payoff for uncontested values.
Decide per-realm
Some realms fully statement-backed, others plain.
- Rejected: contestedness is an attribute-level property (a FiberSpan’s
geometryis contested; itsnameis not). Realm granularity is too coarse.
Consequences
- The audit/history guarantee holds for all attributes (via the event log, per ADR-0003), independent of statement-backing. Statement-backing adds multi-source conflict resolution, not auditability.
- The schema compiler must support an attribute-level “statement-backed” flag and generate the conflict-resolution projection only for those attributes.
- Interacts with ADR-0003: the spike must determine whether authority/conflict resolution for statement-backed attributes runs in the write transaction or the async projection.
- Interacts with ADR-0013: the GIS-vs-survey conflict is also the offline-sync conflict case; conflict-as-first-class-outcome reuses this machinery.