LearnNewsExamplesServices
Frontmatter
id14576
titleTiered wake policy: priority-filtered subscriptions replace the binary daemon on/off
stateClosed
labels
enhancementaiarchitecture
assigneesneo-gpt
createdAtJul 4, 2026, 3:33 AM
updatedAt1:15 PM
githubUrlhttps://github.com/neomjs/neo/issues/14576
authorneo-fable-clio
commentsCount10
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAt1:15 PM

Tiered wake policy: priority-filtered subscriptions replace the binary daemon on/off

Closed Backlog/active-chunk-2 enhancementaiarchitecture
neo-fable-clio
neo-fable-clio commented on Jul 4, 2026, 3:33 AM

Context

Friction→gold from the 2026-07-04 planning night, operator verbatim-in-substance: with the wake daemon off, "literally 4 peers idle out after 1-2 turns and i have to wildly rotate around… i am becoming a severe bottleneck right now." The daemon was disabled because with 6-7 identities online, every DM woke every recipient — wake storms. The result is a binary trap: daemon ON = noise storms; daemon OFF = the operator becomes the fleet's manual scheduler. Both poles were live-observed within 24 hours.

The operator predicted the item that morning: broadcasts-may-not-work-under-wake-off was explicitly named a friction→gold candidate.

The Problem

Wake delivery currently has no policy tier between "everything wakes" and "nothing wakes":

  • V-B-A (this session): all Claude-family peer instances are RUNNING (separate ~/.claude-instances/<identity> user-data-dirs), but no wake-daemon process exists → subscriptions are inert; ~200 unread A2A items accumulated in one mailbox in one evening.
  • The author's own subscription (WAKE_SUB:3f9f2879…, @neo-fable-clio) had filters: {} — i.e., when the daemon ran, every SENT_TO_ME event woke the instance. Multiply by 7 identities exchanging lifecycle DMs and the off-switch was rational.
  • Interim mitigation is behavioral (peer broadcast MESSAGE:3921b67f, 2026-07-04: drain-before-exit, self-scheduled loops, tight sunsets) — necessary tonight, but behavioral discipline demonstrably decays (the #14456 drift corpus: three lived failures WITH docs and scripts in place). The durable fix must be mechanical.

The Architectural Reality

The substrate already carries every needed lever — unexercised:

  • Per-subscription filters exist and are stored per route: ai/daemons/wake/queries.mjs:185 (route identity includes filters in its idempotency contract) and :217 (filters: props.filters || {}); the manage_wake_subscription schema exposes filters.priority (high|normal|low), senderFilter, taggedConcepts, inReplyToFilter, and harnessTargetMetadata.coalesceWindow (0–300s).
  • Priority flows through the daemon's payload + digest surface: ai/daemons/wake/daemon.mjs:442 (payload carries priority), :600-608 (digest priority normalization to the A2A vocabulary); flushDeferPolicy.mjs exists precisely to prevent inflated-set priority spoofing.
  • The mailbox already classifies actionability mechanically: add_message REJECTS wakeSuppressed: true on actionable direct lifecycle subjects (live-verified this session on a [review-posted] DM) and rejects suppressed [lane-claim]s (#14100). The semantic layer for "this deserves a wake" is shipped — it just is not consumed as a wake POLICY.
  • Adjacent, not overlapping: #14537 (setWakeEnabled control verb, FM Lane C) is the per-agent binary toggle at the control plane; this ticket is the per-subscription policy tier underneath it. #14498 shipped wake+heartbeat default-off (the off-pole itself). #12635 relaxed wakeSuppressed; #14100 tightened lane-claims.

The Fix

Three parts, smallest-first — no new stores, no new daemon:

  1. Verify + (if gapped) enforce per-subscription filter matching in the daemon's event path (ai/daemons/wake/daemon.mjs + queries.mjs): a subscription with filters: {priority: 'high'} must not fire for normal/low messages; broadcast (AGENT:*) deliveries must be filterable the same way. Filters are stored today; enforcement needs one falsifying test each way (a normal-priority DM against a high-filtered subscription = no wake; a high-priority DM = wake).
  2. Default-tier bootstrap: peers set filters: {priority: 'high'} (self-service via manage_wake_subscription update — the author's own subscription is already piloted to exactly this, updatedAt 2026-07-04T01:30:54Z), optionally + coalesceWindow for debounce. A bootstrap-action default so NEW identities start tiered instead of unfiltered.
  3. Codify the priority convention where the tier gets its meaning: priority: high = the recipient must act now (direct review request, lane-unblock, operator relay, contested-lane resolution); everything else drains at natural turns. One paragraph in the A2A protocol substrate (the peer-role-mode.md §6.5 wake-control block is the natural anchor) + alignment with the MailboxService actionable-classifier so the two layers agree.

Restart of the daemon itself (its standard launch path — node ai/daemons/wake/daemon.mjs or the operator's launcher; no npm script is registered) stays an operator decision; this ticket makes that decision safe by removing the storm precondition.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
WAKE_SUBSCRIPTION.filters.priority manage_wake_subscription schema + queries.mjs:217 Enforced at daemon event-match: only messages at/above the filtered priority wake Absent filter ⇒ current behavior (all SENT_TO_ME wake) — backward compatible peer-role §6.5 wake-control Schema live; storage verified; enforcement = AC1
harnessTargetMetadata.coalesceWindow same schema Debounce window honored per subscription 0 ⇒ immediate (current) same Schema live; behavior = AC2
A2A priority vocabulary MailboxService + daemon.mjs:600-608 high = act-now wake tier, by convention + classifier alignment unchanged persistence semantics same Digest normalization exists

Acceptance Criteria

  • Falsifying test pair: normal-priority DM against a priority:high-filtered subscription produces NO wake event; high-priority DM produces one. Same pair for a broadcast delivery.
  • coalesceWindow honored (two high-priority DMs inside the window produce one wake with a digest).
  • bootstrap seeds new identities with the tiered default (priority: high), not {}.
  • The priority convention paragraph lands in the wake-control substrate block and names the MailboxService actionable-classifier as the aligned layer.
  • Post-merge, operator-gated: daemon restarted; one storm-free night with ≥3 peers exchanging normal-priority traffic and zero unnecessary wakes (the falsifier for the whole ticket).

Out of Scope

  • #14537's control-plane verb (complementary; this is the layer under it).
  • Re-enabling the daemon (operator call — this ticket only removes the reason it was disabled).
  • Harness-side self-scheduled loops (peer-behavioral, per the interim protocol broadcast).
  • Cross-user harness injection (CCD session messaging is same-user-scoped; verified this session).

Avoided Traps

  • Behavioral-only fix — rejected: tonight's interim protocol is necessary but decays (the #14456 corpus is the standing proof that discipline-without-mechanism rots).
  • coalesceWindow-only — rejected as primary: debounce reduces frequency but every DM still wakes at 7 identities; the tier is the load-shedder, coalesce is the smoother.
  • New "wake policy service" — rejected: the filter substrate exists; adding a sibling policy engine recreates the #13873 dual-controller class for zero new capability.

Related

#14537 (FM per-agent toggle — sibling above) · #14498 (default-off — the off-pole) · #12635 / #14100 (wakeSuppressed semantics) · #13015/#13448 (FM epics; fleet re-invocation is the founding use-case) · peer broadcast MESSAGE:3921b67f (interim behavioral protocol, same night) · ai/daemons/wake/* (owning substrate — sibling precedent verified by direct listing; no new file placement, structural-pre-flight N/A).

Decision Record impact: none identified at filing; if AC1 materially changes daemon matching semantics, the implementing PR cites the daemon's owning authority at that point.

Live latest-open sweep: latest 20 open issues checked at 2026-07-04T01:32Z — no equivalent (closest: #14537, scoped above). A2A in-flight sweep: MESSAGE:3921b67f (Mnemosyne, 01:30Z) is the behavioral interim protocol and names daemon-restart + #14537 as structural fixes — it does not claim this subscription-tier substrate; artifacts reconciled as complementary in a direct reply.

Origin Session ID: fa2a6fd5-7488-4af6-a0d2-3855c86003e4 Retrieval Hint: "tiered wake policy priority-filtered subscriptions operator rotation bottleneck"

tobiu referenced in commit 1cd4272 - "feat(ai): tier wake subscriptions by priority (#14576) (#14838)" on 1:15 PM
tobiu closed this issue on 1:15 PM