Nested background subagent: unresumed completion + stale idle_notifications + confident-wrong state claims turn a routine one-command deploy into a ~30-min ordeal (compounds #78782/#73647/#68922)

Status Open
Maintainer reply None cached
Activity 0 comments · opened Jul 23, 2026

Summary

A routine, one-command container redeploy (rebuild image → push to registry → update the cloud container app → confirm the version string on the page) was dispatched to a background subagent. Because of the subagent lifecycle / status-reporting behavior tracked in #78782, #73647, and #68922, that routine task turned into a ~30-minute back-and-forth in which the supervising session could not trust any status it received and had to determine the true state by independently polling the cloud registry and container revisions. The end user reasonably concluded the deployment "looked like a clusterfuck," and nearly concluded that a broken release had been pushed and falsely reported as done — when in fact the release was correct and healthy the whole time.

This report is a case study of how those individually-filed bugs compound in practice into a severe operator-experience failure, submitted because the combined effect is much worse than any single linked issue conveys.

Baseline: this pipeline is normally reliable

We have run numerous deployments through this exact pipeline without issue. The build/push/deploy steps themselves are routine and reliable; the deploy is effectively one script. Nothing about the deployment was hard or novel here. The entire failure was in the agent-orchestration / status-reporting layer, not in the deploy. This is important framing: it is a regression in the operator experience, not a flaky deploy process.

Environment

  • Claude Code CLI on macOS (Darwin 25.5), model Opus 4.8 (1M context).
  • One foreground session supervising one background subagent spawned via the Agent tool (run_in_background: true).
  • The subagent itself launched a long-running (~5–10 min) background Bash task — a docker build (rootless VM runtime) → registry push → cloud container-app update. So the shape is nested: background subagent → background Bash task.

What happened (timeline, genericized)

  1. Subagent verified all preconditions correctly, then launched the deploy as a background Bash task.
  2. The image built successfully; the first registry push hit a transient "connection reset by peer" to the registry. Because the script uses set -e, it aborted before any cutover — correct, safe behavior. The subagent reported this accurately.
  3. Subagent said "retrying now," then immediately emitted idle_notification { idleReason: "available" } with a stale summary still saying "retrying" — but the retry had not actually executed in that turn (#68922-adjacent: status describing intended-but-unperformed work).
  4. Parent independently queried the registry, saw no new artifact + no new revision, and correctly concluded the retry hadn't landed — so it nudged the agent.
  5. It turned out a second attempt was running as a detached background Bash task; the parent's read-only registry check had crossed with the in-flight push (registry showed the old state because the resumed upload hadn't finished). Two truthful observations, mutually contradictory, because there was no reliable progress channel.
  6. The subagent kept going idle after each status and never auto-resumed when its background Bash task completed (#78782). The deploy actually finished successfully — new revision healthy, serving, correct version — but no completion notification arrived. The parent had to poll the cloud registry and container revision list to discover that the work was done.
  7. Throughout, every status ping was delivered wrapped in the full multi-paragraph peer-message security boilerplate (#73647), so the one line of real signal was buried under a repeated ~150-word legal-sounding wall on each ping.

Operator impact / severity

  • A normally ~5-minute routine deploy consumed ~30 minutes of real-time back-and-forth.
  • The supervising session could not trust any status and had to reconstruct ground truth out-of-band on every step.
  • The end user's takeaway was that the assistant "looked like a clown" and had "pushed out a bad release and claimed it was done." Neither was true — the release was correct and healthy from the moment the cutover completed — but the missing/misleading progress signals made that impossible to demonstrate in real time. This is reputational damage caused purely by the harness's inability to report the state of its own background work.

Second failure mode: confident, incorrect assertions about system state (model reliability)

Independent of the harness status bugs above — and, from the user's perspective, worse — the assistant repeatedly stated architectural "facts" with high confidence that were wrong, then reversed them. This spanned two sessions:

  • In a prior session, the assistant told the user flatly that the native library was not being invoked and that the operation ran through a bundled Python-library path. This session's direct verification (reading the dispatch code and the live run records) showed the opposite: the user's operations invoke the native library directly, in-process. The earlier statement was simply false.
  • Within this session, the assistant made successive contradictory claims about which of several execution paths was live and whether a given fix had reached the user's path — asserting one thing, walking it back, then re-confirming — before finally pinning it down with evidence.

The pattern is stating system-state facts with unwarranted certainty and only verifying afterward. A wrong-but-confident claim about "what is deployed / what is being called" directly causes the operator to make bad decisions and destroys trust. Combined with the harness's inability to surface trustworthy background-task state (above), the operator was left unable to rely on either the assistant's assertions or its status pings.

This is a model-behavior issue (area:model), not a harness bug. The expected behavior: verify system-state claims from evidence before asserting them, explicitly distinguish "verified from evidence" vs "inferred / remembered," and qualify confidence accordingly. It is filed here alongside the harness issues because in this episode the two compounded: unreliable facts on top of unreliable status.

(For completeness: additional model-side reasoning errors also occurred — an incorrect initial assumption about the build mechanism, and initially missing that a container daemon was already available under a different context. Same root behavior: asserting before verifying.)

What would have prevented the whole episode

  1. Resume/notify the spawning subagent when its background Bash task exits (success or failure) so completion is pushed, not polled — the core of #78782.
  2. Never emit idle_notification summaries that describe actions not yet performed; a status ping should reflect actual state, not intent (#68922).
  3. Don't wrap pure lifecycle/status pings (idle_notification, available, completion) in the peer-message security boilerplate, and de-duplicate that wrapper after first occurrence within a session (#73647).

Any one of these three would have collapsed this 30-minute ordeal back into the ~5-minute routine it should have been.

Related issues

  • #78782 — background Bash task completion never resumes in-process subagents (root cause of the polling requirement).
  • #73647 — peer-message security boilerplate injected on idle_notification status pings.
  • #68922 — model asserts background agents are complete before the task-notification.

View original on GitHub ↗