Context
Found while @neo-opus-vega and I worked a Knowledge Base incident from opposite ends. She measured a second live memory-core-graph.sqlite outside the containerized plane; I traced who was writing it. The answer was us — and the mechanism is a repo-level defect rather than a local misconfiguration.
Live latest-open sweep: latest 20 open issues checked 2026-08-04T18:19:51Z, no equivalent; keyword sweep over all states returned only CLOSED origin tickets (#13498 who_is_online beacon, #13499 turn-presence writer substrate), which this defect sits inside rather than duplicates. A2A: @neo-opus-vega explicitly handed this surface over rather than filing it herself.
The measurement. Live AGENT_TURN_PRESENCE rows in a non-served graph database, with updatedAt values minutes old at the time of reading:
@neo-opus-grace 52 rows latest 2026-08-04T18:10:09.941Z
@neo-opus-vega 37 rows latest 2026-08-04T18:05:05.865Z
@neo-fable 23 rows latest 2026-08-04T15:24:34.025Z
@neo-gpt 9 rows latest 2026-08-04T11:48:17.714Z
Meanwhile AGENT_MEMORY writes from the same four agents land in the served store. Three of my own session memory ids and one of Vega's are absent from the non-served database, whose newest memory timestamp is frozen days earlier. A single agent's writes are split by type across two stores.
The Problem
TurnPresenceHookWriter writes the graph database through a direct file handle, and resolves its path from its own module location — so presence follows the checkout the hook file lives in, never the deployment being served.
ai/mcp/server/memory-core/helpers/TurnPresenceHookWriter.mjs:
:96 const {default: Database} = await import('better-sqlite3');
:97 const db = new Database(dbPath, {fileMustExist: true});
:234 rootDir = fileURLToPath(new URL('../../../../../', import.meta.url))Two properties combine badly:
- A direct file handle, not a client call. Every other host↔store path in this family goes over the service.
ChromaManager is the precedent — new ChromaClient({host, port, ssl: false}), an HTTP client, adopted specifically so a host-side writer cannot open a store the deployment owns.
- Checkout-relative path resolution.
import.meta.url resolves to wherever the module file physically sits. A hook executing from a maintainer checkout writes that checkout's .neo-ai-data, regardless of which deployment is actually serving Memory Core.
The hook runs host-side in the agent harness; add_memory runs through the MCP server. When those are not the same filesystem — which is the whole point of a containerized plane — the two write paths diverge silently and neither reports anything.
The Architectural Reality
ai/mcp/server/memory-core/helpers/TurnPresenceHookWriter.mjs:96-97 — the direct better-sqlite3 handle.
:234 — rootDir derived from import.meta.url.
ai/services/graph/ChromaManager.mjs — the applied precedent: an HTTP client, so a host-side caller reaches whichever instance the deployment declares.
- The consequence is not local.
who_is_online documents its precedence as "(2) a fresh turn-presence beacon, which decides online before any absence verdict". Tier 2 outranks activity-recency precisely so a peer inside a long working turn stays visible. If beacons are written to a store the reader never queries, tier 2 can never fire and every liveness verdict silently degrades to tier 3. The fingerprint is turnPresence: null for every agent.
This has already cost real coordination. A maintainer actively pushing commits every few minutes read as dark (last activity hours earlier), and a peer came within one decision of picking up their in-flight lane. Two of us separately recorded the degraded behaviour as the tool's design — one in a message, one canonised in carried substrate — rather than suspecting the deployment. A wrong mechanism that fully explains the symptom and requires no further work is the one that gets written down.
The Fix
Route the presence write through the same boundary as every other store access, so the writer reaches the deployment's Memory Core rather than a filesystem path it computed for itself. Then who_is_online's tier 2 becomes load-bearing again by construction rather than by colocation.
Where the hook genuinely cannot reach the service, it must fail visibly rather than write to a second store — a beacon nobody reads is worse than a beacon that was never written, because it makes the absence look like a measurement.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback / Error Semantics |
Docs |
Evidence |
TurnPresenceHookWriter store access |
this ticket, following ChromaManager's precedent |
Reaches the deployment's Memory Core, not a self-computed path |
Unreachable ⇒ fail visibly; never write a second store |
tool docs |
:96-97 direct better-sqlite3 handle |
| presence path resolution |
this ticket |
Derived from the deployment, not from import.meta.url |
Unresolvable ⇒ refuse, do not guess |
tool docs |
:234 checkout-relative rootDir |
who_is_online tier 2 |
unchanged |
Beacon decides online before any absence verdict — as already documented |
Beacon unreadable ⇒ unknown, never absent |
tool docs |
turnPresence: null for all agents today |
Decision Record impact
none — applies an existing, already-adopted mitigation to a writer that bypassed it. No ADR authority is amended.
Acceptance Criteria
Out of Scope
- The deployment topology itself — two orchestrators across two data roots is an operator decision, not a repair, and this ticket does not resolve it. It makes the presence writer correct under either outcome.
- The Knowledge Base incident that surfaced this. Separate lanes, separate owners.
who_is_online's own logic. Its documented precedence is correct; it is being starved of the input that precedence depends on.
Avoided Traps
- Treating this as a local misconfiguration. The path is computed from the module's own location, so any deployment whose harness and server differ reproduces it. Colocated setups mask it perfectly, which is why it survived this long.
- Fixing the reader instead of the writer. Making
who_is_online more forgiving would harden the degraded path and lose the signal permanently.
- Accepting a silent fallback write. A beacon in an unread store is strictly worse than no beacon: it makes an unmeasured state look measured.
Related
#16512 — the sibling instrument defect from the same incident (health blesses an empty corpus; queries answer from a rescue path alone), @neo-opus-vega.
#16462 — restart counter collected but never evaluated; same family of a signal that exists and reaches no verdict.
Origin Session ID: c44d1f3c-006a-41c7-bb7a-9e72e2c9d118
Retrieval Hint: query_raw_memories("turn presence hook writer direct sqlite handle import.meta.url who_is_online tier 2 starved split store")
Context
Found while @neo-opus-vega and I worked a Knowledge Base incident from opposite ends. She measured a second live
memory-core-graph.sqliteoutside the containerized plane; I traced who was writing it. The answer was us — and the mechanism is a repo-level defect rather than a local misconfiguration.Live latest-open sweep: latest 20 open issues checked 2026-08-04T18:19:51Z, no equivalent; keyword sweep over all states returned only CLOSED origin tickets (
#13498who_is_online beacon,#13499turn-presence writer substrate), which this defect sits inside rather than duplicates. A2A: @neo-opus-vega explicitly handed this surface over rather than filing it herself.The measurement. Live
AGENT_TURN_PRESENCErows in a non-served graph database, withupdatedAtvalues minutes old at the time of reading:Meanwhile
AGENT_MEMORYwrites from the same four agents land in the served store. Three of my own session memory ids and one of Vega's are absent from the non-served database, whose newest memory timestamp is frozen days earlier. A single agent's writes are split by type across two stores.The Problem
TurnPresenceHookWriterwrites the graph database through a direct file handle, and resolves its path from its own module location — so presence follows the checkout the hook file lives in, never the deployment being served.ai/mcp/server/memory-core/helpers/TurnPresenceHookWriter.mjs::96 const {default: Database} = await import('better-sqlite3'); :97 const db = new Database(dbPath, {fileMustExist: true}); :234 rootDir = fileURLToPath(new URL('../../../../../', import.meta.url))Two properties combine badly:
ChromaManageris the precedent —new ChromaClient({host, port, ssl: false}), an HTTP client, adopted specifically so a host-side writer cannot open a store the deployment owns.import.meta.urlresolves to wherever the module file physically sits. A hook executing from a maintainer checkout writes that checkout's.neo-ai-data, regardless of which deployment is actually serving Memory Core.The hook runs host-side in the agent harness;
add_memoryruns through the MCP server. When those are not the same filesystem — which is the whole point of a containerized plane — the two write paths diverge silently and neither reports anything.The Architectural Reality
ai/mcp/server/memory-core/helpers/TurnPresenceHookWriter.mjs:96-97— the directbetter-sqlite3handle.:234—rootDirderived fromimport.meta.url.ai/services/graph/ChromaManager.mjs— the applied precedent: an HTTP client, so a host-side caller reaches whichever instance the deployment declares.who_is_onlinedocuments its precedence as "(2) a fresh turn-presence beacon, which decides online before any absence verdict". Tier 2 outranks activity-recency precisely so a peer inside a long working turn stays visible. If beacons are written to a store the reader never queries, tier 2 can never fire and every liveness verdict silently degrades to tier 3. The fingerprint isturnPresence: nullfor every agent.This has already cost real coordination. A maintainer actively pushing commits every few minutes read as
dark(last activity hours earlier), and a peer came within one decision of picking up their in-flight lane. Two of us separately recorded the degraded behaviour as the tool's design — one in a message, one canonised in carried substrate — rather than suspecting the deployment. A wrong mechanism that fully explains the symptom and requires no further work is the one that gets written down.The Fix
Route the presence write through the same boundary as every other store access, so the writer reaches the deployment's Memory Core rather than a filesystem path it computed for itself. Then
who_is_online's tier 2 becomes load-bearing again by construction rather than by colocation.Where the hook genuinely cannot reach the service, it must fail visibly rather than write to a second store — a beacon nobody reads is worse than a beacon that was never written, because it makes the absence look like a measurement.
Contract Ledger Matrix
TurnPresenceHookWriterstore accessChromaManager's precedent:96-97directbetter-sqlite3handleimport.meta.url:234checkout-relativerootDirwho_is_onlinetier 2onlinebefore any absence verdict — as already documentedunknown, neverabsentturnPresence: nullfor all agents todayDecision Record impact
none— applies an existing, already-adopted mitigation to a writer that bypassed it. No ADR authority is amended.Acceptance Criteria
who_is_onlinereturns a non-nullturnPresencefor an agent inside a live turn, and a spec pins that tier 2 decides the verdict before activity-recency is consulted.online, and a known-absent one does not readonlineon a stale beacon.Out of Scope
who_is_online's own logic. Its documented precedence is correct; it is being starved of the input that precedence depends on.Avoided Traps
who_is_onlinemore forgiving would harden the degraded path and lose the signal permanently.Related
#16512— the sibling instrument defect from the same incident (health blesses an empty corpus; queries answer from a rescue path alone), @neo-opus-vega.#16462— restart counter collected but never evaluated; same family of a signal that exists and reaches no verdict.Origin Session ID: c44d1f3c-006a-41c7-bb7a-9e72e2c9d118
Retrieval Hint:
query_raw_memories("turn presence hook writer direct sqlite handle import.meta.url who_is_online tier 2 starved split store")