[Bug]: Original delegate_task task finalizes on a stale result in the gap before the child's background-exit wake turn#24297

opened1d agobyCCookerTea

Before submitting

  • I searched existing issues and did not find a duplicate. (#16603 and #21837 cover follow-up tasks finishing early; this one is about the original delegate_task task, which does wait, closing in a race.)
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. A parent thread starts a Claude child with delegate_task (mode: "async").
  2. The child starts a long Bash command with run_in_background and also starts two reviewers of its own with delegate_task, then ends its first turn ("still running, waiting on the checks").
  3. The task correctly sits in waiting_for_children.
  4. The background command exits. Claude Code starts a wake turn in the child for that exit.

Expected behavior

The task stays open until the child's wake turn (and the turns started by its reviewers finishing) have run, and the parent receives the child's last result.

Actual behavior

The task finalizes in the gap between the background command exiting and the wake turn being registered, using the stale text from run 1 as the result. Timestamps from the state DB (statev2.sqlite), one case:

text
122:50:35.143 task finalized, summary = run 1's "still running" text
222:50:35.251 parent woken with that summary
322:50:35.330 child run 3 starts (the wake turn for the background command's exit)
4later runs 4 and 5 start when the child's two reviewers finish; run 5 has the real final result

A finalized task never reopens, so runs 3–5 belong to no task and their result is never delivered to the parent. task_status shows latestTerminalSummary for the later runs, but nothing wakes the parent.

It looks like delegatedTaskProgress sees no non-terminal run and no pending background item for a moment (the command has ended, the wake run isn't created yet) and finalizeAppOwnedSubagent closes the task on that snapshot.

Impact

Major degradation or frequent failure: 3 missed results in 2 days across our parent threads (this race once, the #21837 follow-up path twice).

Version or commit

T3 Code 0.1.2 (stable)

Environment

Ubuntu 24.04 server, Claude provider (Claude Code SDK), claude-opus-5-5

Workaround

Children never end a turn while a background command or reviewer they started is still running. They wait inside the turn (t3_thread_wait on reviewer threads, foreground waits for commands), and a Claude Code Stop hook blocks a child's turn end without a final status line. Parents read task_status before trusting a wake.

Synced from GitHub

Note

Claude Opus 5.5 posting on behalf of @dilbagh

Two more hits of this race in one parent thread on 0.1.2 stable (Ubuntu 24.04, Claude Code 2.1.309; parent Claude Opus 5.5, children Claude Fable 5.1, all delegate_task async).

Each child opened a PR, started gh pr checks --watch with run_in_background, and ended its turn saying it was waiting on CI. When CI finished, the parent got the "Delegated task … finished" notification a few tens of milliseconds before the child's wake run was requested:

ChildParent notifiedChild wake run requestedGapChild's final report
A01:21:55.26701:21:55.32457 ms01:22:20
B04:41:18.35104:41:18.39039 ms04:41:47

In A's case task_status at notification time showed hasPendingChildRuns: true and latestTerminalSummary: null, but the task was already completed / result_available. The parent took the stale "waiting on CI" text as the state and ended its turn. The child's later final report ("CI green, PR Ready") showed up in task_status, but nothing woke the parent. Both PRs sat ready to merge until the user asked for a status, about 2 h and 1 h 40 min later.

The workaround we're using: children stop at a Ready PR without waiting on CI, and the parent calls watch_pull_request itself. That avoids the child's background-exit wake altogether.