buzz-acp: idle pool teardown kills an in-flight session waiting on background subagent notifications (queued wakeup lost, no stop bookkeeping)
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Summary
The buzz-acp idle-pool teardown fires while a session is mid-task and waiting on background subagent task-notifications. The teardown destroys the agent pool and the queued wakeup with it. The task dies silently: no error, no stop bookkeeping, and the delegation thread never gets a report.
## Environment
- macOS 26.6.1 (arm64), Buzz Desktop managed agent
- claude-agent-acp 0.66.0
- buzz-acp config from the log: `idle_timeout=900s max_turn=7200s agents=10 subscribe=Mentions dedup=Queue`
## What happened (all times UTC, 2026-08-19)
A managed agent picked up a delegated investigation and worked normally:
- 20:24:16 delegation event arrives; 20:24:18 `agent_pool_ready agents=10`.
- 20:25:33 the agent posts a pickup message in the thread.
- 20:26:34 to 20:26:55 the session launches three background subagents (Claude Code `Agent` tool, `run_in_background: true`).
- 20:27 to 20:38 the session reads code and logs interim findings. Turn structure: each mini-turn ends, then a background task-notification re-wakes the session.
- 20:39:25.689 the third subagent result arrives as a queued task-notification. This is the LAST transcript entry. Zero assistant messages follow.
- 20:39:39.430 buzz-acp logs: `idle pool sleep bound reached — tearing pool back to lazy state idle_pool_sleep_seconds=900`. This is 13.7 seconds after the notification was queued.
The buzz-acp process stayed alive all night (only relay reconnect lines afterward). `managed-agents.json` kept `last_stopped_at` and `last_exit_code` empty because the harness treated this as a routine idle teardown. Nobody noticed the dead task for 8 hours.
## The idle timer does not track real session activity
Two data points from the same process, same night:
1. The killed session: teardown at 20:39:39, exactly `pool_ready (20:24:18) + 900s` on a 30-second tick grid. The session was active almost the entire window (tool calls, transcript writes, a published relay message at 20:25:33). None of it reset the timer.
2. A control turn at 21:12: one continuous foreground turn, ran 21:12:34 to 21:50:55, pushed a PR and posted its report. Teardown came at 21:51:39, i.e. anchor 21:36:39, which is mid-turn. The turn survived only because it finished before the deadline hit a tick.
So the timer counted nothing from the first session after pool creation, and it stopped counting the second turn about 14 minutes before that turn finished.
## Expected
1. A session with an in-flight turn, pending background tasks, or a queued task-notification counts as active. The idle timer must not tear it down.
2. If a teardown does stop a session, the harness persists stop bookkeeping (`last_stopped_at`, reason) so a dead task is visible.
3. A queued wakeup (task-notification) survives a pool teardown and is re-delivered after the pool is rebuilt.
## Actual
The teardown killed a working session mid-task, dropped the queued wakeup, and recorded nothing.
## Evidence
Agent log (`agents/logs/__.log`):
```
2026-08-19T20:24:18.004196Z INFO buzz_acp: agent_pool_ready agents=10
2026-08-19T20:39:39.429933Z INFO buzz_acp: idle pool sleep bound reached — tearing pool back to lazy state idle_pool_sleep_seconds=900
```
Claude Code session transcript (119 entries): last entry at `2026-08-19T20:39:25.689Z` is a `` user message for the third background subagent. The last assistant message is at 20:38:51. The session was never invoked again.
Happy to provide fuller log excerpts.
Contributor guide
Assessment
This issue has not been assessed yet.