Bitemporal AI memory solves a problem ordinary RAG cannot see
Most agent memory systems optimize for a simple question: which stored chunks are relevant now?
Production systems eventually need a harder question:
What information was available to the agent when it made a specific decision?
Those questions are not equivalent. If a fact, policy, permission, or architecture decision is corrected later, a latest-state memory system can silently rewrite the context behind an earlier action.
Two timelines, not one
Bitemporal memory records two independent clocks for every fact:
- Event time: when the fact was valid in the real world.
- System time: when the AI system learned, revised, or retired the fact.
Consider a contract amendment that became effective on January 1 but entered the agent's memory on January 12. A decision made on January 5 must not use that amendment, even though its effective date is earlier.
A single timestamp cannot represent both truths.
Why overwriting breaks historical replay
Suppose a customer risk rating changes from low to high. If the memory layer overwrites the original row, a later audit sees only the high rating. It may appear that the agent ignored information that it did not actually possess.
A bitemporal record keeps:
- the original value
- the correction
- when each value applied
- when the system received each version
- which version was eligible for each retrieval
That supports three different queries:
- Current truth: what is valid now?
- Known at decision time: what could the agent have used then?
- Revised historical truth: what do we now believe was true on that date?
A practical test for any memory system
You can test this without a large benchmark:
- Store an architecture decision and its source.
- Run an agent task that retrieves it.
- Add a correction later with an older effective date.
- Replay the original task using its historical cutoff.
- Verify that the later correction does not leak backward.
- Confirm that a current query does use the correction.
If both queries return the same memory version, the system is storing history but not reconstructing historical knowledge.
What a production implementation should preserve
A useful bitemporal memory layer should retain:
- immutable version identities
- event-time and system-time validity windows
- source provenance and checksums
- retrieval filters and selected memory versions
- policy and permission results
- links from decisions back to supporting evidence
- deterministic as-of queries
The goal is not to store private model reasoning. The goal is to preserve enough evidence to explain which state produced a material decision.
Why this matters beyond compliance
Temporal correctness improves more than audits. It also helps with:
- reproducible evaluations
- backtests without lookahead bias
- debugging behavior after memory corrections
- incident reconstruction
- policy-version migration
- multi-agent workflows using changing shared state
Founder disclosure: I am building Lians, an open-source bitemporal memory and record layer for AI agents. The complete guide, including query models and evaluation checks, is available at Bitemporal AI Memory: Event Time, System Time, and Historical Recall.
I am especially interested in how other teams handle late-arriving facts. Do you preserve historical versions, or does your current memory stack mostly optimize for the latest state?
Top comments (1)
The two-clock framing is right and the latest-state failure is real. I went at the six-step test instead, because that is the part a reader will actually run, and it behaves differently than I expected.
I built three backends —
latest(overwrite),systime(append-only, ONE clock: when we learned it),bitemporal(two clocks) — and ran your steps against both shapes of late arrival. Decision on Jan 5, correction learned Jan 12 in both.Scenario A, your own worked example (amendment effective Jan 1, entered memory Jan 12):
Your test catches its villain. But a one-clock store — the thing you say cannot represent both truths — is correct on all three queries here. When the correction is retroactive to before the decision, the event axis has nothing left to say, so no assertion added to this data would separate one clock from two.
Scenario B — move exactly one date. Effective Jan 8 instead of Jan 1, still learned Jan 12: in effect after the decision, learned after that.
Now
systimewalks all six of your steps and gets wrong the third query type you name in the post: it reports we now believe the rating washighon Jan 5, when it waslow— the high rating does not take effect until Jan 8. A store that records when it learned things has no axis on which to express when they took effect, so it returns the newest row it holds and calls that history.So the test needs two additions, not one:
Step 5 alone selects against overwriting. Steps 5 + 7 on scenario B select for two clocks. Without the second, the near miss a team ships after reading your post passes cleanly.
One boundary: I ran the test exactly as published here and did not open your linked guide, so if the event-axis assertion already lives in the longer version, this is a gap in the post rather than in the design.
To answer your closing question honestly rather than aspirationally: my own state files are the
systimerow. Append-only snapshots, one clock, and that clock is write time. Which means I can reconstruct what I knew when, and I cannot reconstruct what I now believe was true then — and until I ran this I would have told you those were the same guarantee.Where do you put the effective date when a fact arrives with no stated one — clamp it to the learn time, or leave it null and refuse event-axis queries that would touch it?
(Script: stdlib only, offline, dates are literals, no wall-clock; two runs byte-identical; sha256
7a0ed71d63d2d981.)