ADR-027: Bitemporal facts: valid-time + supersession
Date: 2026-06-12 Status: Accepted (owner-delegated review, 2026-06-12) Author: Rômulo Febasi
Context
Synapse facts are atemporal. The system already has transaction-time for
free: git commit time plus the x-ai-history chain and audit.ndjson form an
append-only “known-to-system” log, and syn at <ref> already time-travels along
it. What is missing is valid-time (when a fact was true in the world,
which is independent of when Synapse learned it) and an explicit way to record
that one fact superseded another.
This is the half of bitemporality that the frontier (Zep/Graphiti) owns and that mem0/basic-memory lack; combined with Synapse’s signed provenance it becomes something even Graphiti cannot do: prove what was believed true, and when. The constraint: Markdown frontmatter is the source of truth, the SQLite index is disposable, and the design must stay deterministic and small. Extends ADR-012.
Decision
Store valid-time only; derive transaction-time from git. Add to a fact’s
frontmatter, closed-open [from, until) per the SQL:2011 convention:
x-valid-from: 2024-03-01 # world-time the fact became true (required)
x-valid-until: 2025-06-01 # exclusive; omitted/null = open ("still true")
x-supersedes: <fact-id-or-hash> # optional: this fact replaces that one
Transaction-time is not stored in frontmatter; it is recovered from git
(syn at <ref>) and x-ai-*/audit.ndjson. Storing it twice would duplicate
the source of truth and risk drift (XTDB’s invariant: transaction-time is
system-assigned and immutable; git already provides exactly that).
Supersession = invalidation, not deletion (Graphiti’s rule). When a new
fact F2 contradicts F1: write x-supersedes: F1 on F2 and set F1’s
x-valid-until to F2’s x-valid-from. F1 is never deleted or edited
destructively: closing its interval is itself a new append. A pure
retraction (the fact was never true) is an empty interval
(x-valid-until == x-valid-from) plus an x-ai-history note. x-supersedes is
the world-time analogue of what x-ai-history already does in system-time.
Two orthogonal time axes, each reusing an existing mechanism:
| Axis | Mechanism | Surface |
|---|---|---|
| Transaction-time (“what did we know at ref R”) | git ref (existing) | syn at <ref> -- … (unchanged) |
| Valid-time (“what was true in the world at date D”) | x-valid-* filter in the index | new --as-of <date> |
They compose: syn at <ref> -- search --as-of <date> = “using only what we knew
at R, what was true at D”: the full bitemporal query, nearly free because each
axis is a separate, already-existing filter. The index gains valid_from,
valid_until, supersedes columns (a pure reindex: no stored-data migration).
The default query predicate becomes the SQL:2011 “current row” filter, hand-coded:
valid_from <= now AND (valid_until IS NULL OR valid_until > now) at the
supersession-chain tip.
audit replay stays correct because valid-time lives in the frontmatter
payload it already replays: provided two code invariants hold: replay
reconstructs frontmatter fields generically, and supersession edits (closing
F1’s interval) are appended as ordinary mutations, never written in place.
Migration is deterministic and lazy: existing facts get x-valid-from =
their first git-commit date, open-ended (the only honest default: world-validity
isn’t knowable retroactively); x-supersedes absent; a one-shot syn reindex
populates the new columns; frontmatter is stamped lazily on next mutation (no
bulk rewrite of Markdown). Implemented in SYN-223 (split: schema+migration /
write+supersession / time-aware replay+at).
Consequences
- Improves: matches Graphiti’s strongest feature locally and with
per-fact signed provenance it lacks; enables a “belief-lineage” view (walk
x-supersedes); the minimal shape is 2 interval fields + 1 pointer (AeonG reports ~10% overhead for full bitemporal); the index stays 100% rebuildable. - Worsens:
audit replayandatmust become time-aware (the hard part, gated by the append-only-supersession invariant); the migration default (valid_from= first-commit-date) is an approximation of world-validity. - Open: free-text contradiction detection is deferred to SYN-242
(structured fields first, NLI later); decay (SYN-224/ADR-029) must operate on
the valid-time axis as a derived salience score and must never delete
superseded facts or touch transaction-time; the belief-lineage edge surfaces in
the live graph (SYN-244). Verify before building: that
audit replayreconstructs arbitrary frontmatter fields generically today.
Alternatives considered
- Full TSQL2 / a temporal query algebra. TSQL2 was never adopted; SQL:2011
won by stripping to two columns +
PERIOD FOR. Sequenced/non-sequenced semantics and coalescing are months of work the single-user case never exercises. Copy the column convention, not the algebra. - An Allen interval-algebra reasoning engine. Full-algebra satisfiability is NP-complete (Vilain & Kautz; only ORD-Horn-style subclasses are polynomial). Synapse needs the 13 relations as vocabulary for point-in-time filters (two comparisons), not constraint propagation. Borrow the words, refuse the engine.
- Store transaction-time in frontmatter. Duplicates git, invites drift,
violates “one place per fact.” Derive from
<ref>/audit instead. - JUXT “bitemporality must live in the DB engine.” That targets multi-writer RDBMS whose planners can’t see temporal columns. Our index is single-writer and hand-queried: we can hand-roll correctly. Take JUXT’s failure-mode list as a checklist, reject its conclusion.
- Closed-closed intervals / a custom Period datatype. Exactly what SQL:2011 removed from TSQL2. Use closed-open ISO strings.
- Datomic-style retraction datoms. Redundant with
x-ai-history; encode retraction as an empty valid interval instead.
Research grounding
Snodgrass/Jensen TSQL2; SQL:2011 application-time + system-versioned tables;
Allen’s interval algebra + Vilain & Kautz / Nebel & Bürckert (NP-completeness);
Fowler, Bitemporal History; Datomic (transaction-time only); XTDB/Crux
(immutable transaction-time); Zep/Graphiti t_valid/t_invalid invalidation
(arXiv 2501.13956); AeonG bitemporal extension (ADBIS 2025, ~10% overhead);
temporal/bitemporal RDF; AGM belief revision (Gärdenfors & Makinson).