LearnNewsExamplesServices
Frontmatter
id13312
titleKeep add_memory callable when graph init fails
stateClosed
labels
bugairegressionarchitectureperformancemodel-experience
assigneesneo-gpt
createdAtJun 15, 2026, 8:45 AM
updatedAtJun 15, 2026, 12:51 PM
githubUrlhttps://github.com/neomjs/neo/issues/13312
authorneo-gpt
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 15, 2026, 12:51 PM

Keep add_memory callable when graph init fails

Closed v13.1.0/archive-v13-1-0-chunk-3 bugairegressionarchitectureperformancemodel-experience
neo-gpt
neo-gpt commented on Jun 15, 2026, 8:45 AM

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:

  1. Split Memory Core startup readiness into a minimal WAL-acceptance tier and graph-dependent tiers.
  2. Ensure add_memory can validate payloads and append to the durable WAL without waiting for GraphService.ready().
  3. 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.
  4. Make graph-dependent tools fail/degrade explicitly when graph init is unavailable; do not pretend the whole server is healthy.
  5. Provide observable status for accepted-to-WAL, graph-projected, miniSummary-ready, and embedded-to-Chroma so operators can distinguish durable acceptance from derived availability.
  6. 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

  • A valid add_memory request can be accepted to the WAL when graph SQLite init fails, is readonly, or is temporarily unavailable.
  • Memory Core server startup/tool registration does not withhold the add_memory tool solely because GraphService.ready() cannot complete.
  • Graph-dependent tools still fail closed or return explicit degraded health metadata; no graph-only operation silently pretends to work.
  • Identity/provenance graph edges become asynchronous or best-effort without losing scalar identity metadata on the WAL record.
  • Recency/debug surfaces expose either pending WAL entries or a clear projection-pending state.
  • Cloud deployments have a first-class projection/retry host; the design does not require a local desktop orchestrator daemon as the only drainer.
  • Unit/integration coverage includes a falsifier where graph init/projection throws and add_memory still succeeds after WAL append.
  • Existing #13283 / #13288 per-call WAL-acceptance behavior remains intact.

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"