Multi-Agent Memory Consistency¶
This page documents the consistency model chosen for organizational fact persistence in SynthOrg. See Decision Log D26 for the decision rationale and alternatives evaluated.
Problem Statement¶
Multiple agents may concurrently write to shared organizational memory. Without an explicit consistency model, concurrent writes on the same fact produce undefined ordering, deleted facts may reappear, and there is no audit trail for "who changed this and when."
The OrgFactStore protocol provides save, delete, and query operations but requires
explicit concurrency semantics. This is essential even at launch (1--10 concurrent agents,
low write frequency) to ensure correctness and auditability.
Chosen Model: Append-Only Writes + MVCC Snapshot Reads¶
Write Path¶
All mutations are appended to an operation log rather than updating records in place:
operation_log row:
operation_id -- UUID, globally unique
fact_id -- identifies the logical fact
operation_type -- PUBLISH | RETRACT
content -- serialized fact body (null for RETRACT)
tags -- JSON array
author_agent_id
author_autonomy_level
timestamp -- UTC, monotonic per fact_id via version counter
version -- per-fact integer, incremented on each operation
save() appends a PUBLISH row and updates the snapshot (below).
delete(..., author=...) appends a RETRACT row and marks the snapshot entry as retracted.
Both operations are O(1) append + O(log n) index update.
Read Path (Snapshot)¶
A materialized snapshot maintains the current committed state:
snapshot row:
fact_id -- primary key
content
category
tags
created_at
retracted_at -- null = active
version -- matches most recent operation_log.version
author info -- agent_id, seniority, is_human, autonomy_level
Queries against the snapshot fetch active facts: WHERE retracted_at IS NULL. No log replay
needed at read time -- reads are fast and consistent.
Consistency Guarantees¶
- Writers see their own writes: local reads include uncommitted state before append.
- Readers see a consistent snapshot: all writes committed before query time T were applied at query time.
- Concurrent writes on the same fact are serialized via version counter (CAS-like semantics -- last writer wins, earlier operation survives in the log for audit).
- No lost updates: every operation is durable in the log before the snapshot is updated.
Conflict Handling¶
Storage-layer conflicts (two agents writing to the same fact simultaneously) are resolved by last-writer-wins at the snapshot level, with full history preserved in the operation log.
Application-layer conflicts (two facts with contradictory content, e.g., two incompatible policies) are not resolved by the storage layer. Detection and resolution are the application's responsibility:
- At write time, the caller can check for contradicting facts before publishing.
- A
"superseded_by: <fact_id>"metadata convention marks deprecated facts for human review. - Core policy facts (tagged
"core-policy") should have write access restricted to human-only or senior+ agents (enforced viaOrgMemoryBackend.writeauthorization check, not the consistency layer).
Time-Travel Queries¶
The append-only log enables point-in-time queries:
# What did organizational memory look like before a given timestamp?
snapshot = await store.snapshot_at(timestamp=datetime(2026, 3, 1, tzinfo=UTC))
# Full audit trail for a specific fact
log = await store.get_operation_log(fact_id="policy-jwt-auth")
These methods are defined on the OrgFactStore protocol (the organizational fact persistence
layer). The MVCC implementation lives in SQLiteOrgFactStore. Both read and write operations
go through the OrgFactStore interface.
Deployment Rollout¶
Phase 1 (historical): Sequential writes, no concurrency model¶
The initial implementation with simple INSERT/DELETE and no concurrency semantics.
Phase 1.5 (current): Append-only + MVCC for organizational facts¶
Implementation:
org_facts_operation_logtable in the org facts SQLite database holds all write operations (PUBLISH and RETRACT), indexed by fact_id, timestamp, and a composite (timestamp, fact_id).org_facts_snapshottable maintains the current committed state of all facts, indexed by category and an active-facts index (WHERE retracted_at IS NULL).SQLiteOrgFactStoreimplements theOrgFactStoreprotocol:save()appends a PUBLISH row and upserts the snapshot;delete()appends a RETRACT row and marks the snapshot as retracted.snapshot_at(timestamp)andget_operation_log(fact_id)enable time-travel queries on theOrgFactStoreprotocol.- MVCC is the only implementation -- no feature flag, no backward-compatibility shims (pre-alpha, all data is ephemeral).
Deviation note: MVCC methods live on OrgFactStore rather than SharedKnowledgeStore
because organizational facts are a separate storage layer from cross-agent memory. The
operation log and snapshot are implementation details of the org fact store, not of the
Mem0-based shared knowledge system.
Phase 2 (future): Distributed consistency¶
For multi-node deployments (PostgreSQL backend, multiple app instances), extend the model
with distributed CAS using PostgreSQL advisory locks or SELECT ... FOR UPDATE SKIP LOCKED
on the snapshot table. The operation log structure is unchanged.
Personal Memory¶
Personal agent memories (per-agent_id operations on MemoryBackend) are not subject
to cross-agent consistency constraints. Each agent owns its memory exclusively -- no concurrent
writes from other agents, no MVCC overhead needed. Sequential writes with the existing
MemoryBackend.store() semantics are sufficient.
Implementation Reference¶
The MVCC model is implemented in src/synthorg/memory/org/:
store.py:OrgFactStoreprotocol defining the contract (connect, save, delete, get, query, list_by_category, snapshot_at, get_operation_log).sqlite_store.py:SQLiteOrgFactStoreprovides the SQLite implementation with WAL mode, immediate transactions, and time-travel queries via CTE.models.py:OrgFact,OperationLogEntry,OperationLogSnapshotdomain models.errors.py: Exception hierarchy (OrgMemoryConnectionError, OrgMemoryWriteError, etc.).