LearnNewsExamplesServices
Frontmatter
id13889
title[Epic] Daemon-based A2A message ingestion — decouple add_message from the synchronous model hit + durable WAL-first persistence
stateClosed
labels
bugepicaiarchitecturemodel-experience
assignees[]
createdAtJun 23, 2026, 12:54 AM
updatedAtJun 24, 2026, 6:17 PM
githubUrlhttps://github.com/neomjs/neo/issues/13889
authorneo-opus-grace
commentsCount9
parentIssuenull
subIssues
13890 Mirror memoryWal drain topology for A2A messages
13891 Make add_message WAL-first before ack
13892 Replay message WAL into mailbox graph idempotently
subIssuesCompleted3
subIssuesTotal3
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJun 24, 2026, 6:17 PM

[Epic] Daemon-based A2A message ingestion — decouple add_message from the synchronous model hit + durable WAL-first persistence

Closed v13.1.0/archive-v13-1-0-chunk-5 bugepicaiarchitecturemodel-experience
neo-opus-grace
neo-opus-grace commented on Jun 23, 2026, 12:54 AM

Problem scope

Empirical anchor (this is a real, reproduced data-loss): a session-sunset self-DM continuity handover (MESSAGE:de1d9f0b-c98d-49e9-ae0b-a7a586b5b5fc, authored @neo-opus-grace 2026-06-22T15:21 — the session's final write, STEP 8 of the sunset) was created (add_message returned its id; the durable Sandman memory 68f06bb7 references it) but never durably landed in the graph:

  • absent from the Nodes table,
  • absent from GraphLog (a SQLite insert-trigger appends a GraphLog row on every node write — so no row = the node-insert never hit SQLite),
  • absent from the memory-wal.

Other messages (8,199 MESSAGE nodes) and other sunset self-DMs persist fine — only this last-write-before-restart was lost.

Ruled out (data-backed, no shortcuts):

  • Not orphan-apoptosisGraphMaintenanceService apoptosis would delete all orphaned non-exempt nodes; 2,291 orphaned MESSAGE nodes survive, which falsifies it.
  • Not fade — fade is a ~3-month half-life; de1d9f0b died the same day.
  • Not a discoverability filter — the node was never durably there to surface.

Architectural root (operator): add_message historically hit the chat/embedding model synchronously at write time, which contends with the shared model during heavy maintenance (REM / KB-sync / golden-path). The intended direction is daemon-based async ingestion — but unlike memories (which write durably to memory-wal and are drained by ai/daemons/embed/), the A2A-message path persists in-request and lacks a durable write-ahead surface, so a message can be acknowledged to the caller yet lost before it is durably ingested.

This warrants an Epic: it spans a durable write-ahead surface for messages, the ingestion daemon, replay/idempotency, and removing the synchronous model hit — bound by one hard durability invariant.

Intended solution shape

Mirror the memory ingestion pattern for A2A messages: add_message writes durably first (append-only WAL) and returns; a load-aware daemon drains → graph-persists → embeds, off both the request path and the shared maintenance model.

Durability invariant (load-bearing): an add_message that returns an id MUST survive a process restart — no acknowledged-but-lost messages. A2A messages are durable continuity records (sunset handovers, lifecycle coordination, lane claims); losing one is a continuity-integrity failure, not an acceptable cache miss.

Out of scope / related

  • Memory ingestion already uses this pattern (ai/daemons/embed/ + memory-wal) — the model to mirror, not rebuild.
  • #13755 — heavy-lease "items never reach the graph" (embedding-stall for kb-sync/REM/golden-path): the memory/golden-path twin of this message-path gap.
  • #10349 (CLOSED) — the sunset self-DM handover mechanism this gap silently broke.
  • #10150 — A2A-message Chroma semantic-search collection: complementary; the ingestion daemon is the natural place to populate it.
  • The fade/apoptosis MESSAGE-exemption gap — a separate hardening (the orphan-sweep should never apoptose A2A messages); real but ~3-month-horizon, not this incident.

Avoided traps

  • "It's a deletion" — falsified (no GraphLog/Nodes trace; 2,291 orphaned messages survive).
  • "Discoverability filter" — falsified (never durably persisted).
  • Re-introducing a synchronous embed in add_message — the original maintenance-interference this Epic removes.
tobiu
tobiu Jun 24, 2026, 6:17 PM

Resolving the epic, since 13938 is merged now.

tobiu closed this issue on Jun 24, 2026, 6:17 PM