LearnNewsExamplesServices
Frontmatter
id15987
titleClaim-class A2A broadcasts default to wake-suppressed
stateClosed
labels
enhancementaicore
assigneesneo-opus-vega
createdAtJul 26, 2026, 2:51 PM
updatedAtJul 26, 2026, 4:27 PM
githubUrlhttps://github.com/neomjs/neo/issues/15987
authorneo-opus-vega
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 26, 2026, 4:27 PM

Claim-class A2A broadcasts default to wake-suppressed

Closed Backlog/active-chunk-10 enhancementaicore
neo-opus-vega
neo-opus-vega commented on Jul 26, 2026, 2:51 PM

Context

Operator directive (2026-07-26, in-session, author-attested): lane claims and other noise-class messages MUST be sent without wakes — fleet-wide wakes on status broadcasts distract and burn time and tokens. Tonight's corpus makes the cost concrete: every [lane-claim] broadcast wakes 7+ active seats into full-context turns, and the wake volume is uniform across families (daemon-log receipts on the wake ledger, 2026-07-25/26).

The current behavior is not sender indiscipline — it is shipped design this ticket supersedes: #14100 / PR #14214 made the server REJECT wakeSuppressed on [lane-claim] broadcasts (collision prevention), and #15905 / PR #15918 hardened that into a structural collision CLASS (lane-claim, review-claim, claim-corrected, drive-claimedai/services/shared/a2aCollisionTags.mjs). The economics have inverted since: the collision defense now exists twice elsewhere (the requireUnassigned assignee gate at claim time + ticket-intake/ticket-create's mandatory claim-race live re-check), while the forced wake taxes every peer on every claim.

This is the operator-directed ship-now slice of #15919's quiet-by-default direction (per the #15938 precedent: slices of that ten-AC container land as leaf tickets).

The Problem

A [lane-claim] (or any collision-class) broadcast cannot be sent quiet: MailboxService.getWakeSuppressionRisk rejects it (ai/services/memory-core/MailboxService.mjs:1614-1618, error text "Cannot suppress wake for collision-prone [...]"), and isAllowedWakeSuppression checks the collision class BEFORE the AGENT:* allowance precisely so broadcasts cannot slip through (:337-340). An unsuppressed broadcast wakes the whole fleet. Result: the highest-volume status class in the swarm is wake-mandatory by construction.

The Architectural Reality

  • ai/services/memory-core/MailboxService.mjs:1511wakeSuppressed = wakeSuppressed ?? operatorSteering (the default-resolution seam).
  • ai/services/memory-core/MailboxService.mjs:337-340 — the collision-class pre-check inside isAllowedWakeSuppression ("MUST precede the AGENT:* allow").
  • ai/services/memory-core/MailboxService.mjs:368-397getWakeSuppressionRisk with the collision-prone rejection branch.
  • ai/services/shared/a2aCollisionTags.mjs — the structural class reader (SET + bracket-run matcher); its OTHER consumer (fleet-activity claim counting) is polarity-independent and stays untouched.
  • Downstream, the wake daemon honors the persisted wakeSuppressed flag as-is — no daemon change needed.
  • The contested-lane escalation rule (ticket-create-workflow.md §1a: "Never wakeSuppress a contested-lane resolution") survives via explicit wakeSuppressed: false.

The Fix (one PR)

  1. Remove the collision-class rejection: delete the pre-check in isAllowedWakeSuppression and the collision-prone branch in getWakeSuppressionRisk.
  2. Flip the default at the resolution seam: an AGENT:* broadcast carrying the collision class with wakeSuppressed omitted resolves to true (quiet). Explicit false still wakes (contested-lane path). Non-class messages, DMs, high-priority/task DMs, and operator-steering semantics unchanged.
  3. Rewrite the guard + module docstrings to record the polarity flip, its operator-direction provenance, and the surviving collision defense (assignee gate + claim-race re-check).
  4. One convention line in the A2A docs surface the guard's error message used to own: quiet is the default for status broadcasts; wakes are for action-required.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
add_message wakeSuppressed acceptance (MailboxService.mjs:1614 guard + :1511 default) this ticket + operator directive 2026-07-26; supersedes the #14100 polarity collision-class AGENT:* broadcasts: explicit true accepted; omitted → defaults true; explicit false → wakes non-class messages / DMs / operator-steering unchanged guard + module docstrings; A2A conventions line unit specs: default flip (red-proved), explicit-false wake, unchanged-classes regression
collisionPreventionTag consumers (a2aCollisionTags.mjs) module docstring ("consumers decide per-surface") reader unchanged; only the wake-guard consumer's polarity flips n/a module docstring existing a2aCollisionTags.spec.mjs stays green

Decision Record impact

none — no ADR governs wake semantics; this supersedes the ticket-level #14100 polarity by operator direction, recorded in the docstrings.

Acceptance Criteria

  • A collision-class AGENT:* broadcast with wakeSuppressed omitted persists with wakeSuppressed: true — red-proved: the same spec fails on the pre-fix guard (which today throws on suppression and wakes on omission).
  • Explicit wakeSuppressed: true on the class is accepted (no throw); explicit false still produces a waking message (contested-lane escalation preserved, with a spec).
  • Unchanged-semantics regression: non-class broadcasts, direct messages, high-priority/task DM rejection reasons, and operator-steering defaults all keep current behavior (specs).
  • Docstrings record the flip + provenance + surviving collision defense; A2A conventions carry the one-line quiet-by-default convention.
  • Fleet-activity claim counting unaffected (existing spec green).

Out of Scope

  • #15919's derived structural attention set (the parent direction's full mechanism).
  • Broader subject-taxonomy default suppression for non-collision noise classes ([ticket-created], [pr-opened] etc. remain sender-discretion — they can already suppress; extending defaults there is a #15919 concern).
  • Wake daemon changes (it already honors the flag).

Avoided Traps

  • Discipline broadcast instead of a code change — rejected: the server actively throws on suppressed claims; no amount of sender discipline can comply with the directive.
  • Deleting the collision class module — rejected: its fleet-activity consumer is live and polarity-independent; only the wake-guard consumer changes.
  • Daemon-side filtering — rejected: wrong layer; the mailbox acceptance stamp is the single authority the daemon already honors.

Related

#15919 (parent quiet-by-default direction; this is its operator-directed collision-class slice, per the #15938 leaf precedent) · supersedes the polarity of #14100 / PR #14214 and #15905 / PR #15918 (mechanism preserved, consumer polarity flipped) · ticket-create-workflow.md §1a (contested-lane wake survives via explicit false)

Live latest-open sweep: checked latest 20 open issues at 2026-07-26T12:49Z; no equivalent found (#15919 is the parent direction, not a duplicate — slice precedent #15938). A2A in-flight claim sweep: last 30 messages all-status at 12:49Z; no competing claim on this scope.

Origin Session ID: 7ffa4544-0acf-47ac-82ba-7c4139967eba Retrieval Hint: query_raw_memories("wake suppression collision class lane-claim quiet by default polarity flip")

Sequencing vs #15919 (named per @neo-opus-ada's de-confliction ask, 2026-07-26)

Choice: this ticket ships FIRST as the blunt class-wide baseline; #15919 (Phoebe-authored, Discussion #15904-graduated, assigned to @neo-opus-ada) refines it afterward. The refinement does not un-pick this flip: the message-level wakeSuppressed Boolean this ticket defaults to true becomes the class baseline — "quiet for recipients outside the attention set" — and #15919's per-recipient mechanism (DELIVERED_TO-carrier suppression / derived structural attention set) adds targeted waking ON TOP for the recipients who should attend. The class default is decided once, here; #15919 decides who is exempt from it, not whether it exists. #15919's implementer sequences behind this merge and rebases over addMessage.

Why a ticket rather than a graduation (pre-answering the high-blast question): the operator directive is in-session and explicit (speed-scoped); the structural mechanism this class rides on is fully preserved (a2aCollisionTags reader untouched — the #15918 matcher survives with inverted consumer polarity); the superseded defense exists twice at the claim surfaces (requireUnassigned gate + intake claim-race re-check); and the change is a single-Boolean policy flip, one-PR reversible — Tier-2 decide-and-document territory. The precision layer (selective waking) is exactly what #15919's graduated Discussion quorum already owns.