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:

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.

See also: X-Ethics framework · benchmark · setup guide