Context
Empirically validating the canonical ai/deploy cloud stack (full dockerized boot — all containers healthy on current dev) surfaced a config gap CI doesn't catch: post-#12859 (the add_memory embed decouple), add_memory writes its WAL but nothing drains it on the production compose → embeddings never materialize → semantic recall (query_summaries / query_raw_memories) reads empty. Confirmed empirically: no embed-daemon process runs, and the mc-server doesn't host the in-process drain.
The Problem
The base ai/deploy/docker-compose.yml + docker-compose.dev.yml mc-server services do not set NEO_MEMORY_WAL_IN_PROCESS_DRAIN=true. Only docker-compose.test.yml does — so the CI integration suite drains + passes, masking the gap for real deployments. The config JSDoc (config.template.mjs:308-318) is explicit: inProcessDrain is "the containerized / single-process deployment shape (dockerized MC, npx-neo-app workspaces) where no orchestrator-supervised embed daemon exists." The base compose IS exactly that shape — single-process dockerized MC, no embed-daemon container — but doesn't enable it. Per #12859's design: the in-process drain is the canonical single-container mode (the embed-daemon is for multi-container splits with a shared WAL volume; the sidecar shape was evaluated and rejected).
The Architectural Reality
ai/deploy/docker-compose.yml mc-server (~:93-114) — env list, no NEO_MEMORY_WAL_IN_PROCESS_DRAIN.
ai/deploy/docker-compose.dev.yml mc-server — same gap.
ai/deploy/docker-compose.test.yml (:154-160, :217-220) — has the flag + poll + dir + the single-process comment (the pattern to mirror).
config.template.mjs:318 — inProcessDrain: leaf(false, 'NEO_MEMORY_WAL_IN_PROCESS_DRAIN', 'boolean').
The Fix
Add to the base + dev ai/deploy compose mc-server (mirroring test.yml):
NEO_MEMORY_WAL_IN_PROCESS_DRAIN=true
NEO_MEMORY_WAL_POLL_INTERVAL_MS=250
- a persistent
NEO_MEMORY_WAL_DIR on the data volume (verify the default lands on the persistent volume; test.yml's /tmp is ephemeral-by-design)
- the single-process / sole-drainer comment block (mutual-exclusion: never enable alongside the embed-daemon).
Decision Record impact
none — aligned-with ADR 0014 (cloud deployment topology); applies #12859's documented single-container mode.
Acceptance Criteria
Out of Scope
- The embed-daemon-as-sidecar (rejected per #12859's design).
- Private/client deployment composes (operator-gated, separate trackers).
Related
- #12859 (the
add_memory embed decouple), #12864 (drain-lock guards the sole-drainer invariant), #12840.
Release classification: ON the board — production-deployment recall is broken post-#12859; release-blocking (per the §4 scope-gate).
Retrieval Hint: "ai/deploy compose NEO_MEMORY_WAL_IN_PROCESS_DRAIN recall empty post-#12859 single-container"
Context
Empirically validating the canonical
ai/deploycloud stack (full dockerized boot — all containers healthy on currentdev) surfaced a config gap CI doesn't catch: post-#12859 (theadd_memoryembed decouple),add_memorywrites its WAL but nothing drains it on the production compose → embeddings never materialize → semantic recall (query_summaries/query_raw_memories) reads empty. Confirmed empirically: no embed-daemon process runs, and the mc-server doesn't host the in-process drain.The Problem
The base
ai/deploy/docker-compose.yml+docker-compose.dev.ymlmc-server services do not setNEO_MEMORY_WAL_IN_PROCESS_DRAIN=true. Onlydocker-compose.test.ymldoes — so the CI integration suite drains + passes, masking the gap for real deployments. The config JSDoc (config.template.mjs:308-318) is explicit:inProcessDrainis "the containerized / single-process deployment shape (dockerized MC, npx-neo-app workspaces) where no orchestrator-supervised embed daemon exists." The base compose IS exactly that shape — single-process dockerized MC, no embed-daemon container — but doesn't enable it. Per #12859's design: the in-process drain is the canonical single-container mode (the embed-daemon is for multi-container splits with a shared WAL volume; the sidecar shape was evaluated and rejected).The Architectural Reality
ai/deploy/docker-compose.ymlmc-server (~:93-114) — env list, noNEO_MEMORY_WAL_IN_PROCESS_DRAIN.ai/deploy/docker-compose.dev.ymlmc-server — same gap.ai/deploy/docker-compose.test.yml(:154-160, :217-220) — has the flag + poll + dir + the single-process comment (the pattern to mirror).config.template.mjs:318—inProcessDrain: leaf(false, 'NEO_MEMORY_WAL_IN_PROCESS_DRAIN', 'boolean').The Fix
Add to the base + dev
ai/deploycompose mc-server (mirroringtest.yml):NEO_MEMORY_WAL_IN_PROCESS_DRAIN=trueNEO_MEMORY_WAL_POLL_INTERVAL_MS=250NEO_MEMORY_WAL_DIRon the data volume (verify the default lands on the persistent volume;test.yml's/tmpis ephemeral-by-design)Decision Record impact
none— aligned-with ADR 0014 (cloud deployment topology); applies #12859's documented single-container mode.Acceptance Criteria
ai/deploycompose mc-server setNEO_MEMORY_WAL_IN_PROCESS_DRAIN=true(+ poll + persistent WAL dir).Out of Scope
Related
add_memoryembed decouple), #12864 (drain-lock guards the sole-drainer invariant), #12840.Release classification: ON the board — production-deployment recall is broken post-#12859; release-blocking (per the §4 scope-gate).
Retrieval Hint: "ai/deploy compose NEO_MEMORY_WAL_IN_PROCESS_DRAIN recall empty post-#12859 single-container"