LearnNewsExamplesServices
Frontmatter
id10626
titleCooldown-bounded idempotent trio wake (binds to all-agent-idle detector contract)
stateClosed
labels
enhancementaiarchitecture
assigneesneo-gemini-3-1-pro
createdAtMay 3, 2026, 12:35 PM
updatedAtMay 3, 2026, 2:24 PM
githubUrlhttps://github.com/neomjs/neo/issues/10626
authorneo-opus-4-7
commentsCount0
parentIssue10601
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[x] 10625 All-agent-idle detection at heartbeat layer (substrate primitive for trio liveness)
blocking[]
closedAtMay 3, 2026, 2:24 PM

Cooldown-bounded idempotent trio wake (binds to all-agent-idle detector contract)

Closedenhancementaiarchitecture
neo-opus-4-7
neo-opus-4-7 commented on May 3, 2026, 12:35 PM

Context

Builds directly on #10625 (all-agent-idle detection). Once the heartbeat layer can detect that all configured identities are idle, the substrate needs an idempotent + cooldown-bounded mechanism to fire a single coordinator-wake once per detection cycle without spamming the trio.

Convergence rationale (per trio coordination 2026-05-03 — @neo-gpt MESSAGE:e49dc3c5): cooldown logic MUST bind to the detector's emitted state contract, NOT invent its own stale-state interpretation. Folding stale-state into the cooldown layer would create semantic divergence between detector and cooldown layers — exactly the kind of substrate-truth drift that produced #10619 / #10623 / #10624 substrate-schema-mismatch family of bugs.

The Problem

Without cooldown/idempotency on top of all-agent-idle detection:

  • Each pulse cycle that sees all-idle would emit a fresh wake → spam attack on the coordinator
  • Multiple pulse instances (per-identity heartbeats) might detect all-idle within the same window → duplicate wakes for the same logical coordination cycle
  • A coordinator wakes, starts working, but doesn't yet update its AGENT_MEMORY timestamp before the next pulse → false-positive re-detection

The detector (#10625) by itself doesn't have this concern — it's stateless per-cycle. The cooldown layer is where the cross-cycle idempotency lives.

The Architectural Reality

  • Detector contract (per #10625): emits AllAgentIdleSignal({cycle_id, identities, coordinator_recommendation}) per pulse when all-idle predicate holds.
  • Cooldown state: persisted across pulse cycles. Likely shape: .neo-ai-data/wake-daemon/trio-wake-cooldown.json with {last_fire_cycle_id, last_fire_at, ttl_seconds}.
  • Idempotency key: derived from detector's cycle_id (so multiple per-identity heartbeat instances dedupe via shared file lock or shared-state mechanism).
  • Wake delivery: routes through whatever wake-delivery substrate is canonical at the time (currently bridge-daemon for tmux/osascript paths; subject to future expansion).

The Fix

  1. State file: .neo-ai-data/wake-daemon/trio-wake-cooldown.json storing {last_fire_cycle_id, last_fire_at_iso, ttl_seconds}. Co-located with existing bridge.log / sweep-errors.log per wake-daemon/ convention.

  2. Cooldown layer: wrapper around #10625's signal emission that:

    • Reads cooldown state
    • If (now - last_fire_at) < ttl_seconds AND signal cycle_id matches → suppress (cooldown active)
    • If cycle_id differs (detector saw a fresh all-idle window after activity gap) → fire if TTL respected
    • Otherwise → fire, update state file
    • File-lock the state-update so concurrent heartbeat instances dedupe via mutex (similar pattern to heartbeatLock.mjs from #10319)
  3. TTL default: 30 minutes (env-overridable via TRIO_WAKE_COOLDOWN_SECONDS). Rationale: a coordinator agent that's woken should be able to do meaningful work within that window before re-detection considers them idle again.

  4. Test coverage:

    • Positive: signal fires once per cycle_id within TTL window
    • Negative: subsequent identical signals suppressed within TTL
    • Boundary: cycle_id changes → fires fresh, even within TTL of prior cycle (prevents permanent suppression after detector-cycle boundary)
    • Concurrency: two heartbeat instances racing on the state file dedupe via lock (one fires, one suppresses)

Acceptance Criteria

  • State file written / read at canonical .neo-ai-data/wake-daemon/trio-wake-cooldown.json path
  • Cooldown wrapper reads/writes state via file-lock for concurrent-safe dedup
  • TTL default 30 min, env-overridable
  • Spec coverage: positive + suppression + cycle_id-rotation + concurrency
  • PR body cites the cooldown contract in terms of #10625's detector emission shape (don't paraphrase the contract — reference the canonical doc in #10625's spec)

Out of Scope

  • Detection logic itself — owned by #10625
  • Wake delivery substrate (osascript / mcp-notifications / a2a-webhook) — pre-existing bridge-daemon paths; this ticket emits the wake event, doesn't route it
  • Coordinator-of-the-cycle policy — uses detector's recommendation as-is; doesn't enforce its own
  • Stale-state interpretation — explicitly forbidden per cross-family convergence rationale

Avoided Traps

  • Inventing stale-state interpretation in cooldown layer — must bind to #10625's detector contract. Anti-pattern surfaced by @neo-gpt during 2026-05-03 trio convergence.
  • Time-based cooldown without cycle_id check — would permanently suppress a fresh detection-cycle that legitimately re-fires after activity gap. Cycle_id is the idempotency primary key; TTL is secondary defense.
  • In-memory cooldown only — multiple heartbeat instances need shared state across processes. File + lock is the right substrate.

Related

  • Blocked-by: #10625 (all-agent-idle detection) — needs detector contract before cooldown can bind
  • Builds-on: existing heartbeatLock.mjs (#10319) — same file-lock pattern for concurrent-safe state writes
  • Convergence anchor: trio coordination 2026-05-03, @neo-gpt MESSAGE:e49dc3c5 ("cooldown should bind to detector's emitted state, not invent its own stale-state interpretation")

Origin Session ID: b1839431-cba1-4b6d-913f-27b09e472e67

Retrieval Hint: query_summaries("heartbeat liveness substrate-stack cooldown idempotent trio wake convergence") + query_raw_memories("cooldown bounded trio wake bind detector contract not invent stale-state")

tobiu closed this issue on May 3, 2026, 2:24 PM
tobiu referenced in commit ac05e9a - "feat(ai): trio wake cooldown primitive (#10626) (#10632) on May 3, 2026, 2:24 PM