LearnNewsExamplesServices
Frontmatter
id16263
titleWake digest `latest` tracks iteration order instead of recency
stateClosed
labels
bugai
assigneesneo-kimi-iris
createdAtAug 1, 2026, 3:03 PM
updatedAtAug 1, 2026, 4:24 PM
githubUrlhttps://github.com/neomjs/neo/issues/16263
authorneo-kimi-iris
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 1, 2026, 4:24 PM

Wake digest latest tracks iteration order instead of recency

neo-kimi-iris
neo-kimi-iris commented on Aug 1, 2026, 3:03 PM

Context

First defect surfaced by working wake delivery. @neo-opus-ada's live receipt (A2A MESSAGE:b8d60a65, 2026-08-01T11:28Z): a digest fired at 11:27:05Z over a 150 s window claimed totalEvents: 18 and named as latest a 12-hour-old self-probe (sentAt 2026-07-31T23:04:46Z) — while a message from @neo-kimi-iris at 11:21:47Z (read and answered at 11:25) was inside the same window. The latest pointer is the field an agent uses to decide whether a wake is worth acting on; pointing it at stale backlog makes every first wake-after-enablement actively misleading, and every seat with a backlog hits this on their enablement day.

The Problem

CoalescingEngineService._buildDigestEnvelope assigns each breakdown bucket's latest unconditionally on every iteration (ai/services/memory-core/CoalescingEngineService.mjs:392 for sent_to_me; :403, :407, :411 for the other three buckets):

breakdown.sent_to_me.latest = evt.payload;   // last-write-wins by iteration position

Iteration order is enqueue order (state.queue.push(event) at :217), and enqueue order is only arrival order when every event arrives live in sequence. Any path that enqueues out of order — a delta walk enumerating a replay batch, a restart re-walk from a cursor, or typed-log entries evaluated after a fresher mailbox event — leaves a stale event last in the queue, and the digest points latest at it even though a newer event is present. The four enqueued sources (WakeSubscriptionService.mjs:254, :259, :263, :1354-1359) make no ordering guarantee across sources or across replays.

So the pointer's correctness is an assumption about queue order rather than a property of the data — and the assumption fails exactly on enablement/restart days, which is when the pointer matters most.

The Architectural Reality

  • The digest payload is what the harness renders into the wake prompt; latest.subject/latest.sentAt drive the agent's act-or-ignore decision (payload.breakdown.<bucket>.latest).
  • Recency data exists on the envelope/payload: payload.sentAt (ISO, present on mailbox events per the live receipt) and emittedAt on event envelopes (WakeSubscriptionService.mjs:1429-1430 restores that documented wire field). Computing latest by maximum timestamp instead of last position is correct under any queue ordering, at the cost of one comparison per event.
  • The count: 18 vs 1 real arrival side of Ada's observation is a different defect class (phantom unread feeding the source set — #15825's broadcast-readAt persistence, Grace's mechanism landed the same morning; replay/dedupe semantics at restart — #16258 territory). This ticket deliberately does not bundle them.

The Fix

Track recency explicitly per breakdown bucket in _buildDigestEnvelope:

  1. For each event, resolve a timestamp: Date.parse(evt.payload?.sentAt) first, else Date.parse(evt.emittedAt) (or a numeric emittedAt), else null.
  2. Replace the bucket's latest only when the candidate's timestamp is greater-than-or-equal to the current latest's timestamp (equal keeps the later-enqueued one, preserving current behavior for same-instant events); when no timestamp is resolvable, fall back to the current last-write-wins behavior and note it.
  3. Apply uniformly to all four buckets (the defect is in the shared loop, not in sent_to_me alone).
  4. Specs (CoalescingEngineService.spec.mjs or the wake tree's canonical location): (a) out-of-order enqueue — a stale event enqueued after a fresh one — yields latest = the fresh one (Ada's live case as the fixture shape); (b) equal timestamps preserve last-enqueued (no behavior drift for the common path); (c) timestamp-less payloads fall back to last-write-wins; (d) all four buckets track recency.

Acceptance Criteria

  • A digest over a queue whose newest event is not last in iteration names the newest event as latest (spec reproducing Ada's observed shape).
  • Arrival-ordered queues behave exactly as before (regression spec: no change for the live path).
  • Timestamp-less payloads fall back to last-write-wins, with the fallback noted in the JSDoc.
  • All four breakdown buckets follow the same recency rule.
  • totalEvents semantics are unchanged (the count/replay question routes to #15825 / #16258, not this ticket).

Out of Scope

  • Phantom-unread count inflation (#15825's persistence mechanism) and restart replay/dedupe (#16258) — named here only to hold the boundary.
  • The wake prompt's rendering of latest (harness side).
  • Any change to coalescing windows, refractory, or dispatch ordering.

Related

Live receipt: A2A MESSAGE:b8d60a65 (@neo-opus-ada, 2026-08-01T11:28Z) · the working-wakes arc: #16233 (receiver) / PR #16249 (generator) / #16246 + PR #16251 (degrade) / #16253 + PR #16255 (restore) · count mechanism: #15825 · restart replay: #16258.

Live latest-open sweep: checked latest 20 open issues + digest latest wake / coalescing digest searches at 2026-08-01T12:00Z; no equivalent found. A2A in-flight sweep (last 30 messages): Ada reported the observation without filing; no competing claim. Local exact sweep (digest latest, last-write-wins): no open ticket. KB semantic sweep: unavailable (collection mid-rebuild, count 0) — substituted live GitHub + grep.

Origin Session ID: 05b5fdc9-1f2b-4b45-a2c9-4b64ed5f15cd

Retrieval Hint: query_raw_memories("wake digest latest pointer last-write-wins iteration order recency stale backlog")

tobiu referenced in commit 3ad0ebe - "fix(ai): compute digest latest by recency, not iteration position (#16263) (#16265)" on Aug 1, 2026, 4:24 PM
tobiu closed this issue on Aug 1, 2026, 4:24 PM