Skip to content

ADR-0003: Source-of-truth and consistency model

ADR-0003: Source-of-truth and consistency model

Status

Proposed — gated on a spike (POC 4 Projection Engine / POC 5 Serving Store). Must not be marked Accepted until the spike runs and its result is recorded here.

Date

2026-06-24

Context

This is the decision the entire kernel rests on, and the source pack is internally ambiguous about it. Three of its claims cannot all be true under a naive design:

  • “The Serving Store is a projection, not the sole truth … disposable / rebuildable from data products + statements + events + authority rules” → implies pure derivation.
  • “Read-your-write: immediate or < 1s” and “simple action execution p95 < 250ms” → implies synchronous current state.
  • “Projection lag normal < 5s” → implies asynchronous projection.

If the Serving Store is purely derived asynchronously from an event log, read-your-write is not immediate. Pure event-sourcing of an operational transactional store is the classic trap that sinks systems of this kind. Notably, Palantir’s actual Object Storage v2 is not pure event-sourcing — it is a transactional current-state store with a separate history/lineage path.

This decision interacts with: ADR-0004 (statement-backed attributes need conflict resolution at projection time), ADR-0011 (precomputed topology projections), and ADR-0013 (offline conflict-as-outcome relies on expected-version against current state).

Decision (proposed)

Hypothesis to test: an Action commits the event/statement log and the authoritative current-state row in one transaction (Postgres). Read-your-write is served immediately off current state. Only secondary indexes — search, topology materializations, spatial, scenario overlays — are asynchronous projections with measurable lag. “Rebuildable from the log” is a recovery and audit property, not the steady-state read path.

Falsification bar: if a synchronous event-log + current-state dual-write cannot hold p95 < 250 ms at 1M entities and 1K actions/min, fall back to CQRS with an explicit read-from-log (or session-pinned) path for read-your-write.

The spike must also answer: for statement-backed attributes (ADR-0004), does authority/conflict resolution run inside the write transaction or in the async projection, and what is the read-your-write guarantee for those specifically?

Alternatives Considered

Pure event-sourcing / CQRS

Truth = log only; Serving Store 100% derived async; read-your-write faked.

  • Cons: maximal flexibility, maximal operational complexity, hardest to keep read-your-write honest.
  • Held as the fallback, not the default.

State-primary, log-as-audit

Truth = current-state store; log is an audit side-effect, not the rebuild source.

  • Cons: weakens “rebuildable from log” and statement-replay guarantees that ADR-0004 and history features depend on.
  • Rejected as the default because it gives up replay/rebuild, but it is effectively what the hypothesis degrades to if rebuild is never exercised — the spike must keep rebuild real and tested.

Consequences

  • Until the spike runs, downstream work assumes the hypothesis (sync state + async secondary indexes) but must not hard-code assumptions that only hold under it without flagging them.
  • The spike is a freeze gate: no architecture freeze while this is Proposed.
  • Whichever way it resolves, the resolution is recorded by editing this ADR’s Status to Accepted and appending a “Spike result” section — or by superseding it if the result invalidates the framing.