Skip to main content

Temporal Versioning

Z3rno tracks the complete mutation history of every memory. When a memory is updated, the old version is preserved and a new version is created. You can query what an agent knew at any point in time.

SCD Type 2 Pattern

Z3rno uses the Slowly Changing Dimension Type 2 (SCD Type 2) pattern, a well-established data warehousing technique adapted for agent memory. Every memory row has two temporal columns: The current version of a memory always has valid_to = NULL. When a memory is updated, a database trigger:
  1. Sets valid_to = NOW() on the current version
  2. Inserts a new row with valid_from = NOW() and valid_to = NULL
  3. Copies the memory_id so all versions share the same logical identity

Point-in-Time Queries

You can query what an agent knew at any specific moment using the as_of parameter:
Under the hood, this translates to:
This returns exactly the memories that were active at that timestamp — not what was created before it, but what was the current version at that moment.
Point-in-time queries work across all memory types and all query methods (keyword, vector similarity, graph traversal). The temporal filter is applied before any other filtering or ranking.

Full Mutation History

You can retrieve the complete version history of any memory:
Example output:
This audit trail is invaluable for:
  • Debugging — understanding why an agent behaved a certain way at a specific time
  • Compliance — demonstrating what data was active during an incident
  • Rollback — reverting to a previous version if an update was incorrect

How Updates Create New Versions

Updates are handled by a PostgreSQL trigger that fires on any UPDATE to the memories table. The trigger is atomic — the old version closure and new version insertion happen in a single transaction.
The original memory is never modified. The memory_id stays the same across all versions, so you can always refer to the logical memory by its ID and get the current version, or pass as_of to get a historical version.

Version metadata

Each version also tracks:

Indexing and Performance

Temporal queries are fast because Z3rno creates a GiST index on the (valid_from, valid_to) range using PostgreSQL’s built-in range types:
This allows PostgreSQL to efficiently find all rows where a given timestamp falls within the [valid_from, valid_to) range, even across millions of memory versions.
While temporal versioning preserves all history by default, hard deletes (GDPR-compliant) remove all versions of a memory, not just the current one. If you need to retain history for compliance, use soft delete instead.