How Supersession Tracking Preserves Page Version History in ai-memory

Supersession tracking preserves page version history by inserting a new SQLite row for every distinct edit and linking each row to the previous version through a supersession ID, creating an immutable, backwards-traversable chain.

The ai-memory wiki engine stores every page modification as an append-only event rather than performing an in-place update. By maintaining each version as a distinct row and threading them together through supersession metadata, the system guarantees a complete, queryable audit trail for every wiki page. This architecture is implemented across the Rust crates ai-memory-wiki and ai-memory-store with strict transactional boundaries.

How New Page Versions Are Created

When a user edits a page, Wiki::write_page delegates to Writer::upsert_page inside crates/ai-memory-wiki/src/wiki.rs. Before persisting anything, the system computes a SHA-256 hash of the new body and compares it against the latest stored hash. If the content is unchanged, the write is a no-op; if the hash differs, a new version row is inserted. The inline comment spanning lines 1245–1629 explicitly describes this behavior as the “sha256 short-circuit + supersession dance.”

// Write a page – creates a new version if the body changed
let page_id = wiki
    .write_page(ws, proj, "notes/todo.md".into(), "My Todo", "First version")
    .await?;

// Later edit – a new row is inserted; the old row gets is_latest = 0
let new_id = wiki
    .write_page(ws, proj, "notes/todo.md".into(), "My Todo", "Second version")
    .await?;

The is_latest Flag and the Supersession Chain

Every row in the pages table carries an is_latest integer flag. As noted in crates/ai-memory-store/src/reader.rs at lines 819–820, the current version is marked with is_latest = 1, while all older rows hold is_latest = 0. Each newer row also stores the ID of the row it supersedes, forming a linked list that can be walked from the newest version back to the original.

The architecture documentation in docs/lifecycle-ops.md (lines 327–329) and the project README.md (lines 379–380) both describe this structure as the versioned supersession chain that mirrors the Git history of the wiki.

Decay Tombstones vs. Regular Supersession

Ordinary edits never delete or overwrite data, but the system does support soft-deletion through a decay sweep. When a page is evicted by decay logic, the superseded_at column is populated with a timestamp, acting as a “decay-tombstone” marker. This mechanism is implemented in crates/ai-memory-store/src/ops.rs at lines 1627–1630. In contrast, standard supersession rows retain superseded_at IS NULL; only the decay process triggers this tombstone state, distinguishing routine version history from reclaimed storage.

Atomic Updates for Chain Consistency

To prevent a broken supersession chain during concurrent writes, all flag updates and insertions happen inside a single SQLite transaction. The ops::upsert_page routine in crates/ai-memory-store/src/ops.rs (lines 1881–1884) performs the atomic steps of clearing is_latest on the previous row and inserting the new version with is_latest = 1 and the correct supersession pointer. This guarantees that readers always see a consistent latest version and that the historical chain remains intact.

Querying Page History in Practice

Because every version is preserved and linked, client code can traverse the entire edit history by following supersession IDs. The example below demonstrates fetching the current page and then walking the chain backwards:

// Query the current version
let latest = store
    .reader
    .get_page_by_path(ws, proj, "notes/todo.md")
    .await?; // latest.is_latest == true

// Walk the supersession chain backwards
let mut cur = latest.id;
while let Some(prev) = store.reader.get_superseded_by(cur)? {
    println!("previous version id: {}", prev);
    cur = prev;
}

Summary

  • Append-only edits: Wiki::write_page inserts a new SQLite row for every content change instead of overwriting the existing record.
  • SHA-256 short-circuit: Identical content is detected via hash comparison, preventing unnecessary version rows.
  • is_latest flag: The current version is flagged with is_latest = 1; historical rows are marked 0.
  • Linked chain: Each version stores the ID of the row it supersedes, enabling backwards traversal of the full history.
  • Decay tombstones: The superseded_at column is set only by the decay sweep, separating normal versioning from soft-deletion.
  • Transactional safety: ops::upsert_page wraps flag updates and inserts in one SQLite transaction to keep the chain consistent.

Frequently Asked Questions

What triggers a new version row in ai-memory?

A new row is created only when Wiki::write_page detects a different SHA-256 hash from the latest stored version. If the submitted body matches the existing hash, the write is skipped entirely, making the operation a no-op.

How does ai-memory distinguish the current page version from older ones?

The system relies on the is_latest column in the SQLite table. The newest version carries is_latest = 1, while every prior version in the supersession chain is set to 0. This convention is documented in crates/ai-memory-store/src/reader.rs.

What is the difference between supersession and soft-deletion by decay?

Standard supersession links a new version to its predecessor while leaving superseded_at as NULL. Soft-deletion occurs only when the decay sweep evicts a page, at which point superseded_at is filled to mark the row as a decay tombstone.

Are page version updates in ai-memory atomic?

Yes. The ops::upsert_page function in crates/ai-memory-store/src/ops.rs executes the update to the previous row’s is_latest flag and the insertion of the new version inside a single SQLite transaction, ensuring the supersession chain never becomes inconsistent.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →