Problem
A2A mailbox readAt state written earlier in a session REVERTS to null later, while fresh mark_read calls stick. With wake delivery disabled, read-status is the swarm's ONLY dedup mechanism for inbox processing — a revert makes every polling agent re-classify already-processed traffic (observed: my unread count jumped 92 → 112 with the delta dominated by resurrected messages, across ~6 concurrent agents that is real token burn every session).
Evidence (receipts, 2026-07-10, session 9cf9cce9-23bf-4211-ab0d-bab51d5e1d14)
- Marks acknowledged:
mark_read returned success receipts, e.g. MESSAGE:935f278d-… → {"readAt":"2026-07-10T17:32:39.643Z","status":"read"}; MESSAGE:cf8a6be4-… → {"readAt":"2026-07-10T18:00:22.706Z","status":"read"}. ~40 messages marked across 17:32–18:00Z batches, all acknowledged.
- Revert observed:
list_messages({status:'unread'}) at ~22:11Z returned those SAME messageIds with readAt: null — including both delivery classes (broadcast per-recipient DELIVERED_TO edge status AND direct-DM MESSAGE node status), so it is not a per-class bug.
- Falsifier — fresh marks stick: re-marking
935f278d at 22:15:42Z + a new message at 22:15:41Z; an immediate re-list no longer shows either. Writes through the CURRENTLY-answering server are durable.
- Window pattern: everything marked ≤ ~18:00Z reverted; marks from ≥ ~19:49Z survived — consistent with a server-generation boundary between ~18:00 and ~19:49Z (multiple Memory Core restarts happened that evening around merges).
Topology evidence (get_sqlite_holder_diagnostics @ 22:16Z)
- 31 processes hold the memory-core graph sqlite (8 codex-chained, 19 claude-desktop-chained, 3 orchestrator, 1 unknown) — ALL on
/Users/Shared/github/neomjs/neo/.neo-ai-data/sqlite/memory-core-graph.sqlite{,-wal,-shm}.
- The diagnostics' own
sqliteFile self-report printed the OTHER checkout root (/Users/Shared/fable/...), which is a real directory (not a symlink) — yet cross-agent A2A demonstrably flows through the shared github-root DB. Secondary finding: the diagnostic derives sqliteFile from config/cwd rather than from the answering server's actual open handle (lsof truth) — it should report the handle, or both with a mismatch warning.
Ranked hypotheses (for the investigation, not conclusions)
- Stale read snapshot across server generations/instances: with ~31 concurrent better-sqlite3 holders on one WAL, a server instance holding a long-lived read transaction (or an in-process cache layered over the graph) serves
list_messages from a snapshot that predates commits made through a different (since-restarted) instance. Fits: old marks "revert" when the answering instance changes; fresh marks through the current instance stick.
- Restart rollback: an MC restart in the 18:00–19:49Z window discarded non-checkpointed WAL state or restored from a snapshot. Fits the window pattern; weaker fit for
readAt specifically surviving as null while the messages themselves persist.
- Dual-root divergence: a server generation bound to the fable-root DB accepted some marks that never reached the shared github-root DB. The
sqliteFile self-report makes this non-dismissable until falsified by handle evidence.
Acceptance Criteria
Relations
Parent: none (Memory Core substrate leaf) · adjacent: the wake-redelivery at-least-once semantics (mailbox read-status is the documented dedup truth — this bug breaks that contract) · session with full receipts: 9cf9cce9-23bf-4211-ab0d-bab51d5e1d14.
Live latest-open sweep at 22:16Z: mailbox read status mark_read / memory core sqlite durability — no existing ticket.
Retrieval Hint: query_raw_memories("mailbox read status revert mark_read sqlite holder snapshot")
Problem
A2A mailbox
readAtstate written earlier in a session REVERTS tonulllater, while freshmark_readcalls stick. With wake delivery disabled, read-status is the swarm's ONLY dedup mechanism for inbox processing — a revert makes every polling agent re-classify already-processed traffic (observed: my unread count jumped 92 → 112 with the delta dominated by resurrected messages, across ~6 concurrent agents that is real token burn every session).Evidence (receipts, 2026-07-10, session 9cf9cce9-23bf-4211-ab0d-bab51d5e1d14)
mark_readreturned success receipts, e.g.MESSAGE:935f278d-…→{"readAt":"2026-07-10T17:32:39.643Z","status":"read"};MESSAGE:cf8a6be4-…→{"readAt":"2026-07-10T18:00:22.706Z","status":"read"}. ~40 messages marked across 17:32–18:00Z batches, all acknowledged.list_messages({status:'unread'})at ~22:11Z returned those SAME messageIds withreadAt: null— including both delivery classes (broadcast per-recipientDELIVERED_TOedge status AND direct-DMMESSAGEnode status), so it is not a per-class bug.935f278dat 22:15:42Z + a new message at 22:15:41Z; an immediate re-list no longer shows either. Writes through the CURRENTLY-answering server are durable.Topology evidence (get_sqlite_holder_diagnostics @ 22:16Z)
/Users/Shared/github/neomjs/neo/.neo-ai-data/sqlite/memory-core-graph.sqlite{,-wal,-shm}.sqliteFileself-report printed the OTHER checkout root (/Users/Shared/fable/...), which is a real directory (not a symlink) — yet cross-agent A2A demonstrably flows through the shared github-root DB. Secondary finding: the diagnostic derivessqliteFilefrom config/cwd rather than from the answering server's actual open handle (lsof truth) — it should report the handle, or both with a mismatch warning.Ranked hypotheses (for the investigation, not conclusions)
list_messagesfrom a snapshot that predates commits made through a different (since-restarted) instance. Fits: old marks "revert" when the answering instance changes; fresh marks through the current instance stick.readAtspecifically surviving as null while the messages themselves persist.sqliteFileself-report makes this non-dismissable until falsified by handle evidence.Acceptance Criteria
readAt/DELIVERED_TOstate for the receipt-listed messageIds directly in BOTH DB roots (read-only) — determines whether the 17:32–18:00Z commits ever reached the shared DB (discriminates H3), still exist but are shadowed (H1), or were rolled back (H2).get_sqlite_holder_diagnosticsreports the answering server's ACTUAL open sqlite handle (lsof/PRAGMA database_list), flagging config-vs-handle mismatch instead of printing the config-derived path as truth.Relations
Parent: none (Memory Core substrate leaf) · adjacent: the wake-redelivery at-least-once semantics (mailbox read-status is the documented dedup truth — this bug breaks that contract) · session with full receipts: 9cf9cce9-23bf-4211-ab0d-bab51d5e1d14.
Live latest-open sweep at 22:16Z:
mailbox read status mark_read/memory core sqlite durability— no existing ticket.Retrieval Hint:
query_raw_memories("mailbox read status revert mark_read sqlite holder snapshot")