[MODEL] Claude self-assigns unrequested full test-suite runs, then block-polls the background task instead of awaiting its completion notification
Type of Behavior Issue
Other unexpected behavior — Claude assigned itself expensive verification work that was never requested, then blocked on polling loops waiting for it.
What You Asked Claude to Do
Two small, well-scoped edits in a private React + Vitest project:
- Add a new connection-type constant, its display label, and a logo-map entry (3 added lines across 2 enum files), plus tests, to match a backend change.
- Follow-up: "yes, lets fix the labels." — change two string literals in a label map, plus tests.
No test command was requested at any point. The project's full suite takes ~5 minutes.
What Claude Actually Did
For change 1:
- Made the edits and ran the relevant targeted specs (correct, fast).
- Ran
yarn lint(reasonable). - Then started the entire test suite (
yarn test) unprompted via Bashrun_in_background. - Then, instead of waiting for the harness's task-completion notification, opened a foreground blocking poll loop against the task's output file:
for i in $(seq 1 22); do ... sleep 5; donewith a 130s timeout. - That timed out with no output, so it opened a second, longer poll:
for i in $(seq 1 55); do ... sleep 10; donewith a 570s timeout, which ran to completion. Suite finished in 291.55s, exit 0, all passing.
For change 2 (two string literals):
- Made the edit, ran the targeted spec (31 tests, passing) and
yarn lint, and grepped for the old strings — all of which fully covered the change. - Then queued another full
yarn testrun anyway, and opened another 570s blocking poll on it. - The user interrupted at this point ("what the hell are you upto ?", then "you wasted 8 minutes on label change ?", then "who asked you to even start it").
Expected Behavior
- Run the targeted specs covering the change plus lint, report what those covered, and stop. Do not self-assign a 5-minute full-suite run that was never requested — or ask first if it genuinely seems warranted.
- If a long task is started with
run_in_background, rely on the task-completion notification the harness already sends. Never sit in asleep-based Bash poll loop against the task output file — it adds latency and consumes turns/tokens while providing nothing the notification wouldn't.
The second point seems like a straightforward guardrail: the tool description for background Bash explicitly states the session is re-invoked when the work finishes, and the Monitor tool description explicitly warns against polling for a single completion event. The model still polled, twice, in the same session.
Files Affected
No unwanted file modifications. All edits were in scope and correct.
The cost was time and tokens, not files:
- ~291s of wall-clock blocked on poll loop #1 (ran to completion)
- a second full-suite run queued and polled before the user killed it
- multiple extra assistant turns consumed purely by polling
Permission Mode
Not sure — "auto mode" was active for part of the session; individual Bash calls and edits were not being prompted.
Can You Reproduce This?
Sometimes (intermittent)
Steps to Reproduce
- Open a project with a slow full test suite (~5 min) and a
CLAUDE.mdthat documents bothyarn testand coverage thresholds. - Ask for a small, well-scoped change (e.g. add an enum constant, or change a couple of string literals).
- Observe: after correctly running the targeted specs, the model additionally starts the full suite unprompted, then poll-loops on the background task rather than awaiting the completion notification.
Claude Model
Opus (Opus 5, 1M context)
Relevant Conversation
Claude's own summary once challenged:
"The label edit + targeted tests: about a minute. Then I queued a redundant full yarn test and opened a 9.5-minute blocking poll on it. You killed that after ~1 minute. The genuinely wasted ~5 minutes was earlier: same pattern on the connection-type change, where the blocking poll ran the full 291s to completion. Neither full run was needed. For a two-string label change, targeted tests plus a grep for the old strings is the whole verification story. And when I do want a full run, it notifies me on its own — the polling loop was pure dead time on top."
And:
"Nobody. I started it on my own — you never asked for a full suite."
Impact
Medium — no changes to undo, but wasted user wall-clock, tokens, and credits on self-assigned work across two separate edits in one session.
Claude Code Version
2.1.251 (Claude Code)
Platform
Anthropic API
Additional Context
- Possibly related (both closed): #44957 "Agent repeatedly polls background tasks despite explicit user instructions to stop" and #79348 "Monitor tool: background poll loop silently stops emitting output/heartbeats mid-run". This report differs in that there was no prior instruction to stop, and the underlying issue is the unrequested initiation of the expensive run as much as the polling.
- The polling behavior may be reinforced by the background task's output file being empty/unflushed for the duration of the run —
tail/caton it returned nothing repeatedly, which appears to have encouraged the model to keep polling rather than trust the notification mechanism. - A repo
CLAUDE.mdthat documents test and coverage commands (including "Try to always improve the coverage") may bias the model toward running the full suite even when the user hasn't asked and the change is trivially scoped.
Session id for triage: ee0d11c2-fdb1-49f6-b3a0-1213e03093ce