ADR-031: Belief-time axis: explicit x-recorded-at / x-invalidated-at
Date: 2026-06-14 Status: Accepted (owner-delegated review, 2026-06-14) Author: Rômulo Febasi
Amends ADR-027 (bitemporal facts). Companion to the SYN-223 valid-time work it ships alongside.
Context
ADR-027 set up two time axes and deliberately stored only valid-time
(x-valid-from/x-valid-until) in frontmatter, deriving transaction-time
from git (syn at <ref>). Its “Alternatives considered” explicitly rejected
“store transaction-time in frontmatter” as duplicating git and inviting drift.
Implementing supersession (SYN-223 slice 3) exposed a gap in that framing. ADR-027 conflated transaction-time with git-commit-time and assumed they are interchangeable. They are not, at the granularity we need:
- Git-commit-time is per-commit. A single
git committhat accepts a batch of proposals stamps every fact in it with one timestamp. - Belief-time is per-fact: the moment we decided to record a fact, or the moment we learned a fact stopped being true. Two facts invalidated in the same batch commit have the same git time but can represent decisions made at different logical moments, and, crucially, the moment we learned a fact became false (belief) is independent of the world-time it became false (valid-until). That independence is the whole point of bitemporality.
So “when did we stop believing F1” cannot be recovered faithfully from git under batch commits. It needs an explicit, per-fact stamp.
Decision
Add a third, belief-time axis as two frontmatter keys, stamped at decision (accept) time by the governed write path:
x-recorded-at: 2026-06-14T... # belief-time the fact entered the store
x-invalidated-at: 2026-06-14T... # belief-time we learned the fact stopped being true
x-recorded-atis stamped on every governedcapture_factwrite.x-invalidated-atis stamped on the superseded fact F1 when a new fact F2 closes its interval (x-supersedes: F1).
This does not reintroduce what ADR-027 rejected. ADR-027 forbade duplicating
git’s system storage time (immutable, system-assigned: git owns that, and
syn at still reads it). The belief axis is a distinct semantic: the
human/agent decision time, which git cannot represent per-fact under batching.
Three axes, each with its own home: valid-time (frontmatter x-valid-*),
transaction-time (git, via syn at), belief-time (frontmatter
x-recorded-at / x-invalidated-at).
Supersession stays invalidation-not-deletion (ADR-027 / Graphiti). Three
deterministic rules on an explicit x-supersedes pointer (free-text
contradiction detection remains SYN-242):
- new-after-old (F2 starts at/after F1): close F1 at F2’s
valid-from; stamp F1’sx-invalidated-at. F1 is never deleted, the close is an append. - older-than-known (F2 starts before F1): F2 is born expired at F1’s start; F1 untouched.
- disjoint (F1 already ends at/before F2 begins): keep both.
Consequences
- Improves: the bitemporal matrix is now complete and honest: when was X true in the world (valid), what did the store hold at ref R (git), and when did we decide/learn it (belief) are three separable answers. Supersession is auditable (the belief stamp records the decision moment) without trusting batch-commit granularity.
- Worsens: two more
x-*keys per superseded fact; a second per-fact stamp the reader must understand. The keys are advisory metadata, not load-bearing for--as-of(which filters on valid-time only). - Open: supersession-close currently mutates F1 via the EntityType-keyed
set_field, so custom-typed F1 is not closed yet (same fork asupdate_statusfor custom: SYN-234 contract finish). A custom or danglingx-supersedespointer degrades to “write F2, skip the close”. Temporal replay of supersession remains v0.10.
Alternatives considered
- Derive belief-time from git (ADR-027 as written). Fails under batch commits: distinct decisions collapse to one timestamp, and learned-false-time is unrecoverable. This ADR’s whole reason to exist.
- Reuse
x-ai-accepted-atas the belief stamp. It exists only on AI-authored facts and only records the recorded side, never invalidation. The belief axis must cover human facts and the invalidation moment too. - A separate belief-time ledger (not frontmatter). Splits a fact’s truth across two files; violates “one place per fact”. Frontmatter keeps the fact self-describing and git-diffable.
Research grounding
Snodgrass/Jensen TSQL2 (the valid/transaction distinction); SQL:2011
application-time vs system-versioned tables; Fowler, Bitemporal History (the
“we believed X about world-time W” matrix); Zep/Graphiti t_valid/t_invalid
invalidation. Extends ADR-027; companion to ADR-026/030.