Bi-temporal Memory
Every fact carries its own timeline.
Query the past, end facts that are no longer true, replace them atomically.
Why It Matters
Most memory systems treat knowledge as flat: a fact exists or it does not. That is fine for trivia, but it breaks for everything that changes over time: prices, addresses, team members, opening hours, project status, even your own preferences.
AxiomSeal gives every memory three timestamps:
observed_at
When WE first learned this fact. Defaults to now. Lets you backfill historical knowledge without lying about when you actually saw it.
valid_from
When the fact became true in the world. Often the same as observed_at, but you can set it to the past — "this address has been the office address since 2023".
valid_to
When the fact stopped being true. NULL means "still true". Set it via the invalidate endpoint, or automatically when a successor memory supersedes this one.
The “Currently True” Filter
By default, every search and project listing applies one rule:
observed_at ≤ NOW AND valid_from ≤ NOW AND (valid_to IS NULL OR valid_to > NOW)That keeps your default views truthful for today. Pass include_invalidated=true to see superseded facts as well — useful for audit, debugging, or reconstructing history.
Three Operations
1. As-of Query: “What did we know at time T?”
Returns the set of memories that were considered true at the given timestamp: already observed, already valid, not yet invalidated.
GET /api/dashboard/memories/as-of/{timestamp}
curl -H "Authorization: Bearer $TOKEN" \
"https://app.ai-developer.ch/api/dashboard/memories/as-of/2026-03-15"2. Invalidate: “This fact is no longer true.”
Sets valid_to on a memory. The row stays in the database — historical queries can still reach it via the as-of endpoint. Default valid_to is now; pass an explicit timestamp to backdate.
POST /api/dashboard/memories/{id}/invalidate
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"valid_to": "2026-04-21T00:00:00", "reason": "company moved offices"}' \
"https://app.ai-developer.ch/api/dashboard/memories/123/invalidate"3. Supersede: “Replace this with a newer fact, atomically.”
Pass supersedes: [old_id, ...] when creating a memory. The new memory is inserted, and in the same transaction the listed old memories get their valid_to set to the new memory’s valid_from. No window in between where both look valid.
POST /api/dashboard/memories (with supersedes field)
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Office address",
"content": "Bahnhofstrasse 1, 8001 Zürich",
"project_id": "company",
"supersedes": [123]
}' \
"https://app.ai-developer.ch/api/dashboard/memories"How This Differs From Updating
AxiomSeal also supports PUT /api/dashboard/memories/{id} for in-place edits. Use that when you are fixing a typo or adding detail to the same fact. Use bi-temporal supersede when the fact itself changed:
- Edit — same fact, better wording. History is overwritten.
- Supersede — new fact replaces an old one. Both versions remain queryable forever.
Why It Is X-Aligned
An ethics-grounded memory system cannot present stale facts as live ones — that is a category of deception. Bi-temporal storage is the structural fix: a memory's truth-claim is bounded by its valid_to, and the default query enforces it. Truthfulness over time becomes a property of the system, not a discipline of the writer.
Status
Bi-temporal foundation shipped 2026-04-21. UI timeline visualization (Fact Evolution Graph) is on the next milestone. For now, query history via the as-of endpoint or pass include_invalidated=true to existing list endpoints.
- • 7 production tenants migrated to the bi-temporal schema
- • 8/8 integration tests pass (as-of, invalidate, supersede flows)
- • Default queries enforce validity automatically — stale facts cannot leak
- •
supersedewrites the new memory and closes the old one in the same transaction (no window where both look valid)
See also: X-Ethics framework · benchmark · setup guide