LearnNewsExamplesServices
Frontmatter
id13295
titleGuard actionable A2A messages from wake suppression
stateClosed
labels
bugaitestingregressionarchitecturemodel-experience
assigneesneo-gpt
createdAtJun 15, 2026, 5:45 AM
updatedAtJun 21, 2026, 2:17 AM
githubUrlhttps://github.com/neomjs/neo/issues/13295
authorneo-gpt
commentsCount0
parentIssue13012
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 15, 2026, 9:13 AM

Guard actionable A2A messages from wake suppression

Closed v13.1.0/archive-v13-1-0-chunk-3 bugaitestingregressionarchitecturemodel-experience
neo-gpt
neo-gpt commented on Jun 15, 2026, 5:45 AM

Context

Operator-observed Codex behavior on 2026-06-15 still points at a heartbeat-vs-real-message wake split: heartbeat wakes submit/start a turn, while real A2A message wake-ups may not wake or may not submit when the operator is AFK.

The live Codex adapter evidence on #13287 still matters, but the latest mailbox V-B-A surfaced an upstream condition that does not require an adapter split: multiple targeted direct messages in the recent @neo-gpt inbox were persisted with wakeSuppressed: true, including subjects that are lifecycle-actionable by the current contract.

Examples observed in list_messages({status:'all', limit:30}) at 2026-06-15T03:44:09Z:

  • [review][REQUEST_CHANGES] #13290 — clean work, one close-target gate from @neo-opus-grace to @neo-gpt, wakeSuppressed: true.
  • [review][APPROVED] #13290 — close-target clean, merge-eligible (human-gate) from @neo-opus-grace to @neo-gpt, wakeSuppressed: true.
  • [review][APPROVED] #13293 — clean docs capture, merge-eligible from @neo-opus-grace to @neo-gpt, wakeSuppressed: true.

These messages stay visible in list_messages, but source and tests confirm wakeSuppressed: true intentionally prevents SENT_TO_ME wake delivery. That can look exactly like "real A2A messages do not wake" even when heartbeat pulses still do.

Release classification: post-release Agent Harness reliability; operationally urgent for AFK lifecycle continuity, but not a release-board blocker.

The Problem

The existing convention is explicit: actionable peer messages must wake recipients; awareness-only messages may be mailbox-only. The substrate currently exposes wakeSuppressed as a caller-controlled boolean and correctly honors it, but there is no mechanical guard or audit trail preventing an actionable direct message from being suppressed.

In autonomous mode this is high impact: a reviewer request, REQUEST_CHANGES, addressed-review ping, or merge-gate signal can sit unread until the recipient happens to boot or manually checks the mailbox. Heartbeat pulses can still submit, so the symptom misleadingly resembles a Codex adapter or payload-shape bug even when the actionable message was never eligible for wake delivery.

The Architectural Reality

V-B-A sources:

  • ai/services/memory-core/MailboxService.mjs persists wakeSuppressed: Boolean(wakeSuppressed) on every MESSAGE node.
  • ai/services/memory-core/heartbeatPulseEvaluator.mjs treats a message as wake-eligible only when it is a MESSAGE and not flagged wakeSuppressed.
  • test/playwright/unit/ai/services/memory-core/WakeSubscriptionService.spec.mjs asserts suppressed mailbox-only messages emit no SENT_TO_ME wake.
  • test/playwright/unit/ai/daemons/wake/daemon.spec.mjs asserts the wake daemon does not deliver suppressed mailbox-only messages.
  • .agents/skills/peer-role/references/peer-role-mode.md states the convention: direct review/re-review requests, REQUEST_CHANGES, lane overrides, and overlapping lane claims wake; ordinary awareness messages may suppress.
  • ai/mcp/server/memory-core/openapi.yaml describes the same contract for the add_message.wakeSuppressed parameter.

Historical context from the local ticket/KB sweep:

  • #10545 tightened the original misuse risk when wakeSuppressed hid active coordination.
  • #12635 later relaxed the contract to allow FYI/awareness suppression while preserving the actionable-must-wake rule.
  • Neither closed ticket added a current mechanical/audit guard for actionable direct-message suppression.

Memory-mining note: same-day raw semantic memory queries were attempted for wakeSuppressed direct A2A no wake, Codex A2A wake prompt not submitted, and heartbeat wakes direct messages suppressed, but Memory Core rejected query_raw_memories as not fully operational during active maintenance. This ticket therefore rests on live mailbox output, source V-B-A, KB ticket search, and local issue/discussion sweep rather than raw-memory recall.

The Fix

Add a narrow guard/audit path around add_message.wakeSuppressed so actionable direct A2A messages cannot silently become mailbox-only.

Likely implementation shape:

  1. Centralize an isActionableWakeSuppressionRisk() classifier for MailboxService.addMessage() inputs, based on direct recipient actionability rather than broad primitive names.
  2. Fail closed or emit a structured warning/audit result when callers set wakeSuppressed: true for direct messages that match known actionable lifecycle patterns such as review requests, re-review requests, REQUEST_CHANGES, addressed-review responses, lane overrides, or high-priority direct messages.
  3. Preserve legitimate mailbox-only cases: session-sunset self-DMs, lead-role baton handoffs, explicit FYI/awareness broadcasts, non-overlapping lane-claim broadcasts, and KB alert audit mode.
  4. Add focused unit coverage proving both sides: actionable suppressed direct messages are blocked/audited, while allowed mailbox-only messages still persist and do not wake.
  5. Keep #13287 separate: it remains the live Codex submit/start-turn validation lane for wake-eligible A2A messages.

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
add_message.wakeSuppressed ai/mcp/server/memory-core/openapi.yaml; peer-role wake-control convention wakeSuppressed: true remains valid only for mailbox-only / awareness use, not actionable direct lifecycle messages. If classifier confidence is ambiguous, prefer an audit/warning surface over silently suppressing a wake; do not block known valid sunset/baton/audit cases. Update schema/JSDoc only if behavior or warning semantics change. OpenAPI validator plus mailbox unit tests.
MailboxService.addMessage() ai/services/memory-core/MailboxService.mjs Enforce or audit the actionable-direct-message suppression risk before persisting the message. Broadcasts and explicit non-actionable FYI messages may still suppress; self-DM handovers retain existing behavior. JSDoc for helper/classifier if added. Focused MailboxService.spec.mjs coverage.
Wake eligibility (WakeSubscriptionService / daemon) Existing tests proving suppressed messages do not wake Do not weaken wake suppression honor-sites; they are correct. The fix belongs before or at message acceptance, not by ignoring wakeSuppressed downstream. If a legacy suppressed actionable message already exists, it remains mailbox-visible; the guard applies to new sends. None unless warning docs added. Existing wake tests remain green.
#13287 live Codex submit matrix #13287 / #13292 / ai/docs/wake-prompt-landing-matrix.md Matrix validation must distinguish wake-eligible direct messages from mailbox-only suppressed messages. A suppressed message is not valid evidence that Codex failed to submit a wake; it never emitted a wake by contract. Add a note only if needed while implementing #13287. #13287 live matrix artifact.

Acceptance Criteria

  • MailboxService.addMessage() (or a helper it owns) detects wakeSuppressed: true on known-actionable direct lifecycle messages before they can silently become mailbox-only.
  • The chosen behavior is explicit and test-covered: either reject the call with a clear error or persist an audit/warning that makes the suppression visible to the sender and future reviewers.
  • Legitimate mailbox-only sends still work: session-sunset self-DM, lead-role baton, awareness/FYI broadcast, and KB audit delivery mode retain their current semantics.
  • Unit tests prove suppressed actionable direct messages do not disappear behind the existing wake-suppression honor-sites without the guard/audit firing.
  • Existing wake suppression tests in WakeSubscriptionService and wake daemon remain green; downstream wake honor-sites are not loosened.
  • #13287 receives a comment or evidence note clarifying that suppressed messages are upstream-invalid evidence for Codex submit/start-turn failure.

Out of Scope

  • Changing Codex app-server, osascript, or any harness adapter.
  • Proving live Codex prompt submission/start-turn behavior for wake-eligible messages; that remains #13287.
  • Removing wakeSuppressed or reversing the #12635 FYI/awareness relaxation.
  • Re-delivering already-read messages or changing #13281/#13285 retry/read-state behavior.

Avoided Traps

  • Adapter-first diagnosis: a suppressed direct message will never emit SENT_TO_ME, so switching adapters cannot fix that upstream condition.
  • Downstream honor-site bypass: making the wake daemon ignore wakeSuppressed would break valid session-sunset, baton, and audit-mailbox contracts.
  • Wake-noise regression: reverting to "all peer messages wake" would undo the intended #12635 awareness/FYI noise reduction.

Related

  • Related: #13287 (live Codex submit/start-turn validation for wake-eligible direct messages).
  • Related: #13291 and #13292 (boundary pin + matrix docs for the current wake-submit investigation).
  • Related historical context: #10545, #12635.
  • Parent context: #13012 (Agent Harness).

Duplicate / Claim Sweep

  • Live latest-open sweep: checked latest 20 open issues at 2026-06-15T03:44:09Z. Adjacent open tickets found: #13287, #13291, #13292; none is scoped to guarding/auditing wakeSuppressed:true misuse on actionable direct A2A messages.
  • A2A in-flight claim sweep: checked latest 30 list_messages({status:'all'}) at 2026-06-15T03:44:09Z. No overlapping [lane-claim] / [lane-intent] on this guard scope found.
  • Local/KB historical sweep: found closed predecessors #10545 and #12635, plus docs/tests proving the current honor-sites work; no open equivalent guard ticket found.

Decision Record impact: aligned with ADR 0020 Agent Harness reliability and existing wake-substrate contracts; no ADR change expected.

Origin Session ID: 9c41c4c0-e14b-4e86-bd59-62f7fe64491a

Handoff Retrieval Hints: wakeSuppressed actionable direct A2A REQUEST_CHANGES no wake; Codex heartbeat submits direct messages suppressed; #13287 wake eligible vs mailbox-only suppressed messages