Authored by GPT-5 (Codex Desktop / Euclid).
Context
The per-call add_memory graph-projection problem is already tracked by #13283 and implemented in approved PR #13288. That work addresses what happens after the Memory Core tool is invoked: append the turn to the WAL first, then move graph projection out of the success path.
A separate boundary remains: the Memory Core MCP server can fail or stall before add_memory is callable at all if graph SQLite initialization cannot write. During this session, a sandboxed Memory Core MCP client call failed before tool dispatch with:
SqliteError: attempt to write a readonly database
at SQLite.stampSchemaVersion (ai/graph/storage/SQLite.mjs:219)
at SQLite.initSchema (ai/graph/storage/SQLite.mjs:134)
at SQLite.initAsync (ai/graph/storage/SQLite.mjs:63)Retried outside the sandbox, the same Memory Core tool call succeeded. That proves the immediate payload/tool operation was not the root failure; graph SQLite startup writeability was. This matters for the same operator-stated invariant as #13283: the mandatory end-of-turn memory save must not depend on graph availability once a valid turn payload can be durably accepted.
Release classification: boardless P0 Agent OS reliability follow-up. It is critical to the Memory Core durability contract, but is not automatically attached to the v13 release board because it is a distinct boundary from approved #13288; the operator can promote it if release gating requires it.
The Problem
add_memory cannot be a reliable durability gate if the MCP server/tool surface is withheld by graph initialization. A per-call WAL-first implementation is insufficient when the server has already failed during startup or identity binding.
The failure class is especially important for cloud deployments:
- A container can have temporarily unavailable, migrating, readonly, locked, or mis-mounted graph storage while its WAL volume is still writable.
- A cloud profile must not require a local orchestrator daemon as the only way to recover graph projection.
- Graph projection, miniSummary enrichment, and Chroma embedding are derived work. They can be delayed, retried, and observed; they must not be prerequisites for accepting the raw turn record.
The Architectural Reality
Current source V-B-A:
ai/mcp/server/memory-core/Server.mjs:363-365 calls await GraphService.ready() during bindAgentIdentity(). That can make stdio identity binding depend on graph startup.
ai/graph/storage/SQLite.mjs:134 calls stampSchemaVersion() during graph schema init.
ai/graph/storage/SQLite.mjs:204-219 creates/updates the SchemaVersion(graph) row, which requires graph SQLite write access and produced the observed SQLITE_READONLY failure in the sandbox.
ai/services/memory-core/MemoryService.mjs:399-407 already identifies the WAL append as the durable acceptance anchor.
ai/services/memory-core/MemoryService.mjs:417-438 is the current per-call graph projection path; approved PR #13288 addresses that layer, not the earlier server/tool-availability layer.
Peer A2A on #13283 converged on the same split: the startup/tool-availability coupling is real and distinct from the per-call graph-projection scope. This ticket captures that second boundary explicitly so #13288 can remain a clean per-call fix.
Decision Record impact: aligned with ADR 0001 (Memory Core graph uses shared SQLite/GraphLog as the graph substrate) and ADR 0014 (cloud deployments are first-class and must not assume local-only orchestration). No ADR amendment is expected unless the implementation changes graph coherence semantics or cloud topology.
The Fix
Make the Memory Core MCP server expose and serve the WAL-accepting add_memory path even when graph startup is degraded.
Concrete direction:
- Split Memory Core startup readiness into a minimal WAL-acceptance tier and graph-dependent tiers.
- Ensure
add_memory can validate payloads and append to the durable WAL without waiting for GraphService.ready().
- Make identity binding graph lookup best-effort for the WAL path: if the graph is unavailable, preserve scalar identity metadata and let asynchronous projection attach graph edges later.
- Make graph-dependent tools fail/degrade explicitly when graph init is unavailable; do not pretend the whole server is healthy.
- Provide observable status for
accepted-to-WAL, graph-projected, miniSummary-ready, and embedded-to-Chroma so operators can distinguish durable acceptance from derived availability.
- Honor both deployment profiles: a supervised local daemon is acceptable for local Agent OS, but cloud/container deployments must have an in-process hosted loop or equivalent first-class projection host with a sole-drainer lock.
Contract Ledger
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback / Edge Case |
Docs |
Evidence |
| Memory Core MCP startup / tool registration |
ai/mcp/server/memory-core/Server.mjs, Memory Core OpenAPI |
add_memory becomes available in a degraded graph state when the WAL path is usable. |
Graph-only tools return explicit degraded errors or health metadata until graph init recovers. |
Memory Core tool/health docs if readiness vocabulary changes. |
Startup test where graph init throws but add_memory remains callable. |
add_memory WAL acceptance |
ai/services/memory-core/MemoryService.mjs WAL append contract |
Success is gated by validation + WAL append, not graph readiness, Chroma embedding, or miniSummary. |
WAL filesystem failure and validation failure may still reject. |
Update tool docs/return metadata if pending projection status is surfaced. |
Unit falsifier: graph readiness/projection throws and valid add_memory still returns success with pending projection state. |
| Identity / graph provenance edges |
Server.mjs#bindAgentIdentity, GraphService node/edge projection |
Graph identity lookup is best-effort for WAL acceptance; scalar identity metadata survives and projection can attach graph edges later. |
If the agent identity node is unavailable, record pending projection/identity status rather than dropping the turn. |
JSDoc comment where fallback is implemented. |
Test proves missing/unavailable graph identity does not block WAL acceptance and later projection can reconcile. |
| Recency and debug surfaces |
query_recent_turns, healthcheck, graph lifecycle telemetry |
Recency callers either see pending WAL entries or receive explicit projection-pending status. |
No caller should interpret delayed graph projection as memory loss. |
Health/debug docs if new status appears. |
Focused tests for pending overlay or explicit degraded response. |
| Cloud deployment profile |
ADR 0014 cloud topology |
Projection/retry hosting must be cloud-safe and not require a local desktop orchestrator as the only worker. |
Local supervised daemon may remain one profile, but cloud must have in-process hosting or equivalent. |
Deployment docs only if new config is introduced. |
Config/test evidence that cloud profile can accept WAL writes without local-only lanes. |
Acceptance Criteria
Out of Scope
- Replacing approved PR
#13288 or expanding its per-call projection scope.
- Treating Knowledge Base sync as graph maintenance.
- Requiring immediate Chroma semantic availability after
add_memory.
- Making graph-dependent query tools fully functional without graph storage.
- Changing mailbox wake semantics.
Avoided Traps
- Calling this only a sandbox permissions issue: the live
SQLITE_READONLY repro is sandbox-shaped, but the architectural failure is broader: a mandatory WAL save surface should not be hidden behind graph schema writes in any deployment.
- Overloading
#13283: that ticket and PR can stay narrowly scoped to per-call graph projection after WAL append. This ticket isolates the earlier server availability boundary.
- Local-daemon-only fix: a desktop daemon can help local Agent OS, but ADR 0014 makes cloud deployments first-class; the projection host must be deployable without local desktop machinery.
Related
Related: #13283, #13288, #12838, #12840.
Duplicate Sweep
- Live latest-open sweep: checked the latest 20 open issues on 2026-06-15 before creation. Only
#13283 overlapped; no separate open ticket covered startup/tool availability after graph init failure.
- Semantic ticket sweep:
ask_knowledge_base(type:'ticket', query:'add_memory startup graph SQLite init tool availability MEMORY_ADD_ERROR SchemaVersion') surfaced historical Memory Core graph/tool context and prior add_memory lineage, but no active duplicate for this follow-up boundary.
- Local issue/discussion sweep: exact searches for
add_memory.*graph, tool-availability, SchemaVersion, SQLITE_READONLY, and graph SQLite init found historical context and #13283 lineage but no open duplicate.
- A2A in-flight sweep:
list_messages({status:'all', limit:30}) found peer messages from Ada, Grace, and Vega confirming the startup-coupling split, but no active [lane-claim] on the follow-up ticket.
Retrieval Hint: "add_memory callable graph init fails Memory Core startup GraphService.ready SchemaVersion SQLITE_READONLY WAL acceptance cloud projection host"
Authored by GPT-5 (Codex Desktop / Euclid).
Context
The per-call
add_memorygraph-projection problem is already tracked by#13283and implemented in approved PR#13288. That work addresses what happens after the Memory Core tool is invoked: append the turn to the WAL first, then move graph projection out of the success path.A separate boundary remains: the Memory Core MCP server can fail or stall before
add_memoryis callable at all if graph SQLite initialization cannot write. During this session, a sandboxed Memory Core MCP client call failed before tool dispatch with:SqliteError: attempt to write a readonly database at SQLite.stampSchemaVersion (ai/graph/storage/SQLite.mjs:219) at SQLite.initSchema (ai/graph/storage/SQLite.mjs:134) at SQLite.initAsync (ai/graph/storage/SQLite.mjs:63)Retried outside the sandbox, the same Memory Core tool call succeeded. That proves the immediate payload/tool operation was not the root failure; graph SQLite startup writeability was. This matters for the same operator-stated invariant as
#13283: the mandatory end-of-turn memory save must not depend on graph availability once a valid turn payload can be durably accepted.Release classification: boardless P0 Agent OS reliability follow-up. It is critical to the Memory Core durability contract, but is not automatically attached to the v13 release board because it is a distinct boundary from approved
#13288; the operator can promote it if release gating requires it.The Problem
add_memorycannot be a reliable durability gate if the MCP server/tool surface is withheld by graph initialization. A per-call WAL-first implementation is insufficient when the server has already failed during startup or identity binding.The failure class is especially important for cloud deployments:
The Architectural Reality
Current source V-B-A:
ai/mcp/server/memory-core/Server.mjs:363-365callsawait GraphService.ready()duringbindAgentIdentity(). That can make stdio identity binding depend on graph startup.ai/graph/storage/SQLite.mjs:134callsstampSchemaVersion()during graph schema init.ai/graph/storage/SQLite.mjs:204-219creates/updates theSchemaVersion(graph)row, which requires graph SQLite write access and produced the observedSQLITE_READONLYfailure in the sandbox.ai/services/memory-core/MemoryService.mjs:399-407already identifies the WAL append as the durable acceptance anchor.ai/services/memory-core/MemoryService.mjs:417-438is the current per-call graph projection path; approved PR#13288addresses that layer, not the earlier server/tool-availability layer.Peer A2A on
#13283converged on the same split: the startup/tool-availability coupling is real and distinct from the per-call graph-projection scope. This ticket captures that second boundary explicitly so#13288can remain a clean per-call fix.Decision Record impact: aligned with ADR 0001 (Memory Core graph uses shared SQLite/GraphLog as the graph substrate) and ADR 0014 (cloud deployments are first-class and must not assume local-only orchestration). No ADR amendment is expected unless the implementation changes graph coherence semantics or cloud topology.
The Fix
Make the Memory Core MCP server expose and serve the WAL-accepting
add_memorypath even when graph startup is degraded.Concrete direction:
add_memorycan validate payloads and append to the durable WAL without waiting forGraphService.ready().accepted-to-WAL,graph-projected,miniSummary-ready, andembedded-to-Chromaso operators can distinguish durable acceptance from derived availability.Contract Ledger
ai/mcp/server/memory-core/Server.mjs, Memory Core OpenAPIadd_memorybecomes available in a degraded graph state when the WAL path is usable.add_memoryremains callable.add_memoryWAL acceptanceai/services/memory-core/MemoryService.mjsWAL append contractadd_memorystill returns success with pending projection state.Server.mjs#bindAgentIdentity,GraphServicenode/edge projectionquery_recent_turns, healthcheck, graph lifecycle telemetryAcceptance Criteria
add_memoryrequest can be accepted to the WAL when graph SQLite init fails, is readonly, or is temporarily unavailable.add_memorytool solely becauseGraphService.ready()cannot complete.add_memorystill succeeds after WAL append.#13283/#13288per-call WAL-acceptance behavior remains intact.Out of Scope
#13288or expanding its per-call projection scope.add_memory.Avoided Traps
SQLITE_READONLYrepro is sandbox-shaped, but the architectural failure is broader: a mandatory WAL save surface should not be hidden behind graph schema writes in any deployment.#13283: that ticket and PR can stay narrowly scoped to per-call graph projection after WAL append. This ticket isolates the earlier server availability boundary.Related
Related: #13283, #13288, #12838, #12840.
Duplicate Sweep
#13283overlapped; no separate open ticket covered startup/tool availability after graph init failure.ask_knowledge_base(type:'ticket', query:'add_memory startup graph SQLite init tool availability MEMORY_ADD_ERROR SchemaVersion')surfaced historical Memory Core graph/tool context and prioradd_memorylineage, but no active duplicate for this follow-up boundary.add_memory.*graph,tool-availability,SchemaVersion,SQLITE_READONLY, andgraph SQLite initfound historical context and#13283lineage but no open duplicate.list_messages({status:'all', limit:30})found peer messages from Ada, Grace, and Vega confirming the startup-coupling split, but no active[lane-claim]on the follow-up ticket.Retrieval Hint: "add_memory callable graph init fails Memory Core startup GraphService.ready SchemaVersion SQLITE_READONLY WAL acceptance cloud projection host"