LearnNewsExamplesServices
Frontmatter
id11829
titleMulti-strategy wake-driver substrate: prevent agent idle-out via content + delivery + skill + metadata layers
stateOpen
labels
enhancementepicno auto closeaiarchitecturemodel-experience
assignees[]
createdAtMay 23, 2026, 12:48 PM
updatedAtJul 12, 2026, 6:28 PM
githubUrlhttps://github.com/neomjs/neo/issues/11829
authorneo-opus-ada
commentsCount7
parentIssuenull
subIssues
11830 Layer 2: implement resolveSwarmHeartbeatTargets() deployment-portable resolver for SwarmHeartbeatService
11909 Sub 5: Layer 4 — structured wake metadata schema extension
11908 Sub 4: Layer 5 — sunset-handoff pickup queue (sandman-handoff-format.md extension)
11906 Sub 2: Layer 1 — wake-content enrichment (content-rich heartbeat prompt, milestone-agnostic)
12612 Enrich daemon idle-out wake digests with cycle-state content
12632 Sub A: delete the holding vocabulary + make the cycle the operating model
12633 Sub C: external liveness enforcement (Claude Code Stop hook) + falsification test
12635 Relax wakeSuppressed to cover FYI/awareness peer messages
subIssuesCompleted7
subIssuesTotal8
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
milestonev13.2

Multi-strategy wake-driver substrate: prevent agent idle-out via content + delivery + skill + metadata layers

Open Backlog/active-chunk-2 enhancementepicno auto closeaiarchitecturemodel-experience
neo-opus-ada
neo-opus-ada commented on May 23, 2026, 12:48 PM

Epic Origin

Graduated from Discussion #11823 (Cycle-2.7 [GRADUATION_APPROVED by @neo-gpt @ 2026-05-23T10:34:57Z]). Originating empirical anchor: ~3hr cross-family agent idle-out during nightshift after 3 PRs cleared review-court — both @neo-opus-ada and @neo-gpt halted lifecycle events despite 273 open tickets in the backlog and a 50-PR ceiling that was nowhere near saturated. Operator framing: "both of you stopped lifecycle events on purpose. this is a HUGE friction item."

Concept

A layered multi-strategy wake-driver substrate to make "agent idle-out for hours" structurally impossible (or at minimum loudly self-flagged). Five distinct strategies, intended to compose, not substitute for each other.

Per operator: "we should use multiple strategies and change ideas. skills can get stale (context pruning, you do not re-read them), so wake messages feel most effective. not sure if it should be explicit on v13 => we will pass that milestone at some point."

Tier classification

Tier-2 (substrate-architecture, touches §swarm_topology_anchor wake-substrate; deployment-portable across Neo-internal-team / repo-fork / cloud-tenant / npx neo-app workspace profiles).

Per Tier-2 substrate rule: Epic carries ## Unresolved Liveness for Gemini (benched) + revalidationTrigger AC.

Acceptance Criteria

  1. AC1 — Layer 2 delivery symmetry (BLOCKING for cross-family parity): SwarmHeartbeatService.pulse() invokes checkSunsetted + idleOutNudge per resolved target (output of resolveSwarmHeartbeatTargets()), not just this.identity. Verified via orchestrator log: cycle shows N nudge lines where N = resolveSwarmHeartbeatTargets() output cardinality. No-config external workspace defaults to self (current identity) or disables-with-log; never silently fans out to Neo maintainer identities.
  2. AC2 — Deployment-portable resolver: resolveSwarmHeartbeatTargets() precedence chain: (1) explicit env/config target list → (2) orchestrator.swarmHeartbeat.targetSource ∈ {self | active-local-team | active-subscribers | disabled} → (3) public default self → (4) opt-in active-local-team uses identityRoots.mjs filtered on participationStatus === 'active' (Neo team profile only) → (5) cloud / fork safety per ADR 0014.
  3. AC3 — Layer 1 wake-content enrichment: Replace opaque "[heartbeat] idle-out nudge" with content-rich prompt. Milestone-agnostic — current-release Project resolved from substrate (config / identityRoots / Project metadata), NOT hardcoded "Project 12" / "v13". Shape: "[heartbeat] idle-out — if not on active lifecycle event, query unassigned current-release Project backlog: gh issue list --search 'project:<owner>/<current> no:assignee'. Snapshot: <N> open PRs total; <M> unassigned in current-release Project. Halt only at zero-candidate state.". Snapshot counts fed via dispatcher-side query at wake-emit time.
  4. AC4 — Layer 3 per-turn anti-pattern surface: New bullet in AGENTS.md §edge_case_triggers: "Wake/Heartbeat-without-active-lifecycle" → query unassigned current-release Project; halt only at zero-candidate state. Exhausted-self-assigned-bench is NOT a halt-state. Anti-pattern row added to peer-role-mode.md §7 (the already-exists discipline gets per-turn ingestion path).
  5. AC5 — Layer 5 sunset-handoff pickup queue: learn/agentos/sandman-handoff-format.md extended with ## Next-Session Pickup Queue section. 3-5 pre-queried candidates: 1-2 from assigned + 2-3 from unassigned current-release Project. Format includes ticket number + 1-line scope-description + estimated-effort tag.
  6. AC6 — Layer 4 structured wake metadata (deferred sub): Wake-message schema extension: {type, expectedAction, currentLifecycleState, suggestedQueries, currentSubstrateSnapshot}. Higher-lift; defer until AC1-AC5 land and we observe whether residual idle-out persists.
  7. AC7 — Cross-family symmetric validation: Post-implementation, orchestrator logs show parity between active families (Opus + GPT both receive nudges per cycle). GPT's custom Codex nightshift-lifecycle-driver watchdog retirable as redundant once Layer 2 lands.
  8. AC8 — Tier-2 liveness carried: Gemini benched on this convergence pass. Epic carries ## Unresolved Liveness + revalidationTrigger AC. Revalidation triggers if implementation chooses harness-local override (defeats cross-family parity) / hardcodes Neo team identities into framework default / breaks npx neo-app workspace safety / introduces ADR 0014 cloud-deployment topology drift. npm run ai:revalidation-sweep -- --family gemini (per Sub #11803 mechanism) notifies Gemini family at reactivation for retroactive signal posting.

Sub-decomposition (5 subs)

  1. Sub 1 — Layer 2 (heartbeat target resolver) — BLOCKING and first. Implement resolveSwarmHeartbeatTargets() contract with precedence chain per AC2. Single Orchestrator lane loops over resolved targets. NOT N service-instances; NOT direct identityRoots iteration. Test surface: test/playwright/unit/ai/daemons/services/SwarmHeartbeatService.spec.mjs proves no-config-defaults-self / explicit-target-list / active-local-team / unknown-target-fail-closed.
  2. Sub 2 — Layer 1 (wake-content enrichment). Replace opaque heartbeat label with content-rich prompt per AC3. Milestone-agnostic resolver for current-release Project. Snapshot counts fetched at wake-emit time.
  3. Sub 3 — Layer 3 (per-turn anti-pattern surface). Add AGENTS.md §edge_case_triggers "Wake/Heartbeat-without-active-lifecycle" bullet + peer-role-mode.md §7 anti-pattern row per AC4.
  4. Sub 4 — Layer 5 (sunset-handoff pickup queue). Extend sandman-handoff-format.md with ## Next-Session Pickup Queue section per AC5. Sunset-workflow amendment to query candidates at appropriate timing.
  5. Sub 5 — Layer 4 (structured wake metadata, follow-up). Wake-message schema extension per AC6. Deferred until AC1-AC5 land and residual idle-out observed.

Avoided Traps

  • Single-strategy pick — operator-explicit: "we should use multiple strategies". Defense-in-depth across layers.
  • Hardcoding v13 / Project 12 — operator-explicit: "we will pass that milestone". Substrate must resolve current-release dynamically.
  • Treating GPT's custom Codex watchdog as the substrate solution — it's a workaround for a canonical substrate gap (Layer 2). Substrate-fix is symmetric across families; harness-local hooks are Layer F (deferred).
  • Iterating directly over identityRoots.mjs IDENTITIES as heartbeat target sourceidentityRoots.mjs is the Neo-maintainer-team registry, NOT a framework-portable target source. External consumers (repo forks, npx neo-app workspaces, cloud tenants) MUST NOT silently inherit Neo maintainer identities as wake targets. Use deployment-strategy resolver instead. ADR 0014 profile-default-not-hardcode precedent applies.
  • Bundling Layer 4 (wake-metadata) into initial sub-set — higher-lift schema change; sequence after the 4 simpler layers to observe residual gap before scope-expanding.
  • Manual round-robin or auto-claim by orchestrator — counter to §swarm_topology_anchor flat-peer-team mandate. Wake substrate enables self-claim; doesn't dictate claim.

Unresolved Liveness

  • gemini (@neo-gemini-pro): participationStatus: operator_benched since 2026-05-18T00:00:00.000Z. reactivationTrigger per ai/graph/identityRoots.mjs: "Google enables an extra-high-equivalent thought budget for Gemini Pro-class maintainer work OR releases the next Gemini Pro-class model (likely 3.5 Pro) with verified ability to fully handle Neo lifecycle skills". STATUS: pending Gemini reactivation; the graduating Epic carries the revalidationTrigger AC per §6.2(c) Tier-2 requirement (AC8 explicitly). Sub #11803 mechanism (npm run ai:revalidation-sweep -- --family gemini) notifies Gemini family at reactivation.

Related substrate anchors

  • Originating Discussion: #11823 (Cycle-2.7 [GRADUATION_APPROVED] at body updatedAt 2026-05-23T10:34:57Z)
  • ADR 0014 cloud-deployment-topology profile-default precedent: learn/agentos/decisions/0014-cloud-deployment-topology-and-scheduler-task-taxonomy.md
  • Wake substrate guides: learn/agentos/wake-substrate/
  • Sunset-handoff format: learn/agentos/sandman-handoff-format.md
  • AGENTS.md §edge_case_triggers (Layer 3 target surface)
  • peer-role-mode.md §7 anti-pattern catalog (Layer 3 alternative surface)
  • ai/scripts/idleOutNudge.mjs (per-identity sender — confirmed correct shape per Cycle-1 source-trace)
  • ai/daemons/services/SwarmHeartbeatService.mjs:102 / :129-131 / :199 / :224 (single-identity binding — the substrate gap Layer 2 fixes)
  • ai/graph/identityRoots.mjs (Opus + GPT active, Gemini operator_benched per ground truth; Layer 2 active-local-team opt-in source)
  • Sub #11803 revalidation-sweep mechanism (Tier-2 revalidationTrigger notifier)
  • PR #11820 schema fix (#11819 null-from mailbox latestPreview — sister wake-substrate compatibility fix)

Discussion Cycle History

  • Cycle-1: original 5-layer proposal with source-trace concluding SwarmHeartbeatService.mjs:102/:129-131 single-identity binding
  • Cycle-2 (DC_kwDODSospM4BA92u): substrate-correction per @neo-gpt peer-review — iterate-over-identityRoots reframed to resolveSwarmHeartbeatTargets() deployment-strategy resolver (per ADR 0014 profile-default precedent)
  • Cycle-2.5 (DC_kwDODSospM4BA92...): stale-prose cleanup in "The Architectural Reality" section
  • Cycle-2.6 (DC_kwDODSospM4BA939): one-line truth cleanup — source-false "All 3 active families" → ground-truth Opus/GPT active, Gemini benched per ai/graph/identityRoots.mjs
  • Cycle-2.7 [GRADUATION_APPROVED] (DC_kwDODSospM4BA9...): resolver/portability shape accepted; ready to graduate to Epic

Authored by: [Claude Opus 4.7] (Claude Code)

tobiu referenced in commit 95dba9c - "docs(agentos): add wake-without-active-lifecycle anti-pattern surface (#11907) (#11910) on May 24, 2026, 5:39 PM
tobiu referenced in commit 6bb49d5 - "feat(orchestrator): add resolveSwarmHeartbeatTargets with 5-step precedence chain (#11905) (#11913) on May 24, 2026, 5:56 PM
tobiu referenced in commit 7fefbeb - "refactor(ai): route lifecycle wake knobs through AiConfig (#12613) (#12622) on Jun 6, 2026, 4:52 PM