Skip to content

Delegated task reports finished while its child thread still has running work #16603

Open

Description

@PrivateVictories-Main

Area: apps/server

Steps to reproduce

  1. From a parent thread, delegate_task to a Codex child that starts a long-running shell command (a bot, a test watcher) and ends its turn without waiting for it.
  2. Read task_status, or look at the parent once it settles.

Expected: The task stays in progress (or reports waiting_for_children) while the child's command is still running, and the parent stays Waiting.

Actual: The task finalizes as completed / result_available and the parent can settle to Done, while the child thread still has a running command_execution item and the process is alive. delegatedTaskProgress (SubagentProjection.ts:207-259) checks runs, subagent entities and the provider roster, but not active turn items, and finalizeAppOwnedSubagent (Orchestrator.ts:8472-8488) finalizes on that result.

A related path: t3_thread_send into an already-finalized child (ThreadManagementService.sendToThread) starts new runs there, but the parent task stays completed and its later result is never delivered (OrchestratorMcpService.ts:1058-1077, Orchestrator.ts:8537-8546).

Evidence (0.0.46-nightly.20261004 state DB): 3 of 145 completed delegated tasks since Oct 1 finalized while their child had live command items (2 still running now, one confirmed alive with pgrep). 5 later runs across 3 finalized children.

Possible fix: include pendingBackgroundTurnItems({ turnItems, runs }) in delegatedTaskProgress (and load turn items in both callers), retrying finalization when those items end. For the send path, reject sends into finalized app-owned children or reopen task tracking.

Impact: Minor bug or occasional failure.

Activity

  1. juliusmarminge commented on Oct 6, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Confirmed on current main: an app-owned delegated task can finalize as result_available / completed while the child still has live background command_execution work.

    Main bug

    delegatedTaskProgress decides working / waiting_for_children / result_available from:

    • non-terminal work runs
    • active child subagents / pending completion delivery
    • provider-thread pendingBackgroundTasks

    It does not look at active turn items. finalizeAppOwnedSubagent loads the child without turnItems, calls that helper, and finalizes as soon as progress.state === "result_available".

    So a Codex child that starts a long-lived shell (countsForRun: false / turn ends without waiting) can look “done” to the parent while the process is still alive — matching the state-DB evidence in the report.

    The shared pendingBackgroundTurnItems helper already exists and is used elsewhere in the orchestrator (e.g. interrupt cleanup). It is the natural check to fold into delegatedTaskProgress (with callers loading turnItems).

    Secondary path (distinct)

    t3_thread_send into an already-finalized child can start new runs without reopening parent task tracking / delivering the later result. That overlaps open #13490 and open PR #15004 (follow-up result delivery). Those do not fix the premature-finalize case above.

    Loosely related: #13625 (completion sound while background work runs), #15993 (stale background banner).

    Fix direction: include pendingBackgroundTurnItems({ turnItems, runs }) in delegatedTaskProgress (and load turn items in both finalize / status callers); keep finalization deferred until those items end. Separately, for send-into-finalized-child, either reject or reopen tracking (coordinate with #15004).

    Labeling bug + via-triage.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 6, 2026
  3. emilvakhitov commented on Oct 7, 2026

    @emilvakhitov

    Additional user-observed scenario with nested subagents:

    Root thread: completed
    `-- Subagent A: completed
        `-- Subagent B: still running
    

    From the original root thread, the remaining descendant activity is not visible, so the delegated workflow appears finished while B continues working.

    This is an observation, not an independently reproduced case. It is unclear whether it has the same underlying cause as the command_execution gap described above.

    Consolidating the related report from #16902 here to avoid parallel tracking.

  4. jamesvillarrubia commented on Oct 20, 2026

    @jamesvillarrubia
    Contributor

    Same outcome with a Claude child, on 2026-10-20. The open work here is a native background subagent, not a shell command. The machine's installed runtime is 0.1.1-nightly.20261019.3373.

    1. 18:23:32Z: the parent sends the child a follow-up with t3_thread_send. T3 tracks it as a delegated task.
    2. 18:24:11Z: the child launches a background subagent. T3 writes a record for it on the child in orchestration_v2_projection_subagents (origin: provider_native, status: running).
    3. 18:31:45Z: the child's turn ends with "I'm waiting on two things in the background: the price-research child and a watcher for its output file."
    4. 18:31:45Z: T3 finalizes the delegated task and delivers its result to the parent. The record for the child's subagent still reads status: running.
    5. 18:35:59Z: the child's subagent completes.

    The issue body says delegatedTaskProgress checks subagent entities. This record read status: running when T3 finalized the task. The parent agent learned the work was unfinished only from the child's final text, and sent another follow-up at 18:31:57Z.

  5. juliusmarminge commented on Oct 22, 2026

    @juliusmarminge
    Member

    Triage read the report and follow-up, scanned all 949 open issues, and inspected current main at a12d6ed942. No earlier duplicate identified; #21837 covers a related follow-up lifecycle. Runtime reproduction was not attempted. This requires maintainer review under the automated triage restriction on MCP tool-surface changes: the requested behavior changes delegated-task completion returned by task_status and follow-up handling through t3_thread_send. No code changes or PR.

  6. seankoji commented on Nov 2, 2026

    @seankoji

    Additional observed case on 2 November 2026: a delegated implementation agent displays Done while its required asynchronous review delegate is still running. Adding here because #16902 explicitly consolidated this nested-descendant visibility case into #16603.

    Steps observed

    1. An implementation coordinator launches a required asynchronous review with delegate_task.
    2. The host result instructs it: "Completion wakes this thread, so end your turn. Do not wait on it or poll it."
    3. The coordinator ends its turn awaiting that review.
    4. Open Lineage while the review remains active.

    These steps describe the supplied live-session evidence. No fresh isolated reproduction was run.

    Expected behavior

    The aggregate workflow status remains pending, for example Waiting for review/delegates, while a required descendant is active. The parent agent's completed turn can remain visible separately. Active required descendants should remain discoverable from ancestors.

    Observable acceptance:

    • Aggregate status remains pending during required child activity.
    • It transitions correctly when that child completes, fails, or is cancelled.
    • A terminal parent-turn status remains distinguishable from completion of the delegated workflow.

    Actual behavior and evidence

    • A screenshot from the implementation conversation shows "Lineage · 1 running", the implementation parent marked Done, and its required Opus review still running at about 16 minutes elapsed.
    • A separate root-conversation screenshot shows only direct previous agents. This supports a related nested-descendant discoverability concern; it does not establish the same underlying cause as the Done ambiguity.
    • The main coordinator's read-only T3 thread inspection confirmed an active claudeAgent / claude-opus-5-5 run with a parent relation to the ended implementation delegate. Completed command activity was recorded at 14:01 AEDT, UTC+11, on 2 November 2026. That command completion is not evidence that the review itself completed.
    • The required source milestone remained pending at observation time.

    This is evidence of user-visible pending-work/status ambiguity. It does not establish premature backend task finalization, a reducer defect, lost tasks, cancelled work, or failed completion delivery. Root cause is unknown.

    Environment and version limits

    T3 Code on Linux, with nested T3 asynchronous delegation and a Claude Agent Opus 5.5 reviewer. Read-only installed metadata identifies CLI runtime 0.1.4-nightly.20261028.3814 and desktop package 0.1.3-nightly.20261023.3566. These are installed versions, not a verified binding of the screenshot or active server to either version; the exact affected running build is unknown.

    Impact and workaround

    Users can mistake an ended parent turn for finished work and lose visibility of a required pending review. No verified UI workaround. The supplied evidence distinguishes parent-turn completion from outstanding review work; no claim is made that execution stopped.

    Related reports and scope

    #27126 concerns an async delegate hint stopping otherwise independent work. Here the review is required and ending the turn is expected; this report concerns the displayed aggregate state. #27700 concerns native Claude subagent background commands/monitors. This case uses a required T3 asynchronous review delegate, without assuming the same cause.

    Sanitized text only. Private screenshots, transcripts, task identifiers, repository details and machine paths are intentionally omitted. No implementation, task cancellation, restart, or monitoring was performed for this report.

  7. vilmerfrost commented on Nov 2, 2026

    @vilmerfrost

    Same bug with a Claude child, on 0.1.7-nightly.20261102.4066 (macOS, Claude Code 2.1.316, Claude Opus 5.5). The report above uses a Codex child.

    Steps observed

    1. A Claude parent starts a child with delegate_task, isolation: "worktree", mode: "async".
    2. The child starts a long script with Bash run_in_background and ends its turn with the message "Waiting for background task <id>, the final evidence run."
    3. The parent calls task_status.

    Result

    While the script was still running, task_status returned:

    {
      "status": "completed",
      "workState": "result_available",
      "hasPendingChildRuns": false,
      "latestTerminalSummary": "Expect: about 25 minutes and little plan usage. Waiting for background task `<id>`, the final evidence run."
    }

    At the same moment, on the machine, the script's process and the child's claude process were alive, and the child had not pushed its branch.

    The parent was woken with a [completed] message whose whole text was the waiting line. The same thing happens on every turn the child ends while it waits: in this session four workers sent about 15 [completed] messages between them that were not final results. Each background completion starts a new child run through a provider continuation, and that run delivers another [completed].

    Impact

    A parent has no reliable way to tell a finished child from a waiting one. Here both the parent agent and the person watching the app read a running worker as done. The parent has to inspect the child's checkpoint or processes to find out.

    Not tested

    I did not check whether calling t3_background_wait inside the child changes this. I did not run a patched build.

    Related: #27700 covers the same state for native Claude subagents, and anthropics/claude-code#92952 covers the completed status it comes from.

    Written with Claude Opus 5.5 in T3 Code.

  8. hishamank commented on Nov 2, 2026

    @hishamank

    Same nested case on v0.1.6 (Linux desktop app), with counts from one long-running session. All delegates were started with delegate_task. The parents were Claude Opus 5.5, and the children were a mix of Claude and an ACP provider.

    Observed

    root: latest run completed, no active run, 72/72 subagent records completed
    ├─ orchestrator A: latest run completed → review delegate: running
    ├─ orchestrator B: latest run completed → build delegate: running; review delegate: running
    └─ orchestrator C: latest run completed → mapping delegate: running
    

    From the code, the root row should read as finished: its status comes from its own runs and its own unfinished records, and nothing here is active. I read this from the state database and the source, and did not capture the sidebar itself.

    Two paths, both in the state database

    1. A follow-up closes while its nested work runs. In finalizeAppOwnedSubagent, only the original task is held back by progress.state. Example from orchestrator C:

      12:09:07.563  orchestrator opens a nested delegate
      12:09:17.934  orchestrator's run ends
      12:09:18.449  root's follow-up record closes as completed; the nested delegate is still running
      
    2. A run starts with no root record open. Orchestrator A's last root record closed at 10:31:31. A nested completion woke it at 12:06:13, and it opened a new delegate at 12:06:36. The root had no open record for any of this.

    Orchestrator Root records closed while a nested record was open Runs with no open root record
    A 26 of 29 110 of 166
    B 10 of 13 49 of 67
    C 17 of 21 45 of 96

    These compare timestamps across each orchestrator's own records. They count overlaps, and don't show that each overlap was visible in the UI.

    Related work

    Path 1 looks like what #21877 addresses, and path 2 looks like what #28462 addresses. I have not run a build with either PR, so I can't say whether the two together keep the root in a pending state for this whole tree.

    Written with Claude Opus 5.5 in T3 Code.

  9. jamesdchen commented on Nov 2, 2026

    @jamesdchen

    Another case with a Claude child on v0.1.6 on Windows, using mode: "async", isolation: "shared". The child's own final message says it isn't finished, but the task and the thread read as done.

    What happened. A child started a background Bash watcher, then ended its turn with this message:

    W6 isn't finished: nothing has been submitted yet... Background watcher bqkvktnji checks both local files every 2 minutes, for up to 2 hours, and wakes me when the gate opens, the suite fails or it times out.

    The parent received Delegated task ... [completed] with that text. t3_thread_read shows the thread as status: completed, activeRunId: null, runCount: 1, and t3_thread_list with statuses: [running, starting, queued, waiting] doesn't list it, while the watcher it describes is meant to still be alive.

    Why the status can't be relied on, in the same session. Two sibling children showed the same completed state after similar turns and then woke up later and did real work:

    • One submitted 30 cluster jobs under a later provider-continuation task ID, after its original task had reported completed.
    • Another woke up several more times on its own, reported state changes and resubmitted a failed job.

    So completed can mean either "finished" or "waiting on my own background work", and the parent can only tell by reading the child's prose.

    The practical cost. A parent seeing completed on unfinished work starts a replacement, which then risks duplicating the original if it wakes. I had to start a replacement for this child with no way to confirm the first wouldn't resume. For long fan-outs this also produces many [completed] notifications carrying interim text such as "Waiting for the retry to report back."

    Expected. As this issue describes: waiting_for_children or similar while a child has live background work, including Claude run_in_background commands, and a final completed only when it has really ended.

  10. dpearson2699 commented on Nov 6, 2026

    @dpearson2699

    Same bug with a Claude child on 0.1.6-nightly.20261031.3977 (macOS 27.0.1 arm64, desktop app on a local server). This adds what it does to the parent's Lineage panel.

    Observed

    1. A Claude Opus 5.5 parent started a Claude Opus 5.5 child with delegate_task (isolation: "worktree").
    2. The child started long test runs with Bash run_in_background, called t3_background_wait on them, and ended its turn. It woke and carried on each time a run finished.
    3. In orchestration_v2_projection_subagents, every task record for the child read completed / delivered, one per turn. Each was written while the child's background runs were still pending; four of its test processes were alive on the machine at the time.

    What the parent's Lineage panel showed

    While the child was working, the parent's thread details panel showed no active agent. Lineage showed only a collapsed "Previous agents · 1 failed · 194", with the live child folded in among the finished ones. The child's own panel listed the parent correctly.

    From the source (checked against main at c52df24), this follows from the task status:

    • Between turns the child has no live run, so its activityRunStatus is null. The subagent edge's status in deriveThreadRelationshipGraph (packages/client-runtime/src/state/threadRelationships.ts) then falls back to the child's completed status, because the subagent record is no longer active.
    • ThreadRelationshipsPanel (apps/web/src/components/chat/ThreadRelationshipsControl.tsx, the groupBy that returns "previous") puts every subagent edge with a settled status under "Previous agents".

    So if the subagent record stayed running while the child waits on its own background work, the edge would take that status and the child would stay in the active list. The Lineage symptom should not need a separate client fix.

    Observed in a live session, not reproduced in isolation.

    Filed by Claude Code (claude-opus-5-5) inside T3 Code, following .github/triage/PLAYBOOK.md.

  11. StanMan007 commented on Nov 9, 2026

    @StanMan007

    Same bug on today's nightly, 0.1.8-nightly.20261109.4433 (server on Linux, macOS client, Claude Opus 5.5 parent and children started with delegate_task). This adds screenshots of how it looks from the parent, and timings that tie it to #24297.

    What the UI shows

    The screenshots are from about 22:54 UTC on 9 November. The parent's sidebar row has no Working or Waiting pill, so it reads as at rest:

    Parent thread's sidebar row with no status pill

    In the parent's timeline, both subagent rows say Finished:

    Two subagent rows in the parent, both marked Finished

    Opening child B shows it is still waiting on an awaited background command:

    Child B's footer reads Waiting on a background command

    The child's Lineage panel lists the parent as Done:

    Child's Lineage panel showing the parent as Done

    What the database shows

    Read-only from the orchestration_v2_projection_* tables:

    • The provider threads of child B and child C each hold a pending background task with kind: "command" and awaited: true. Each was started with Bash run_in_background and marked with t3_background_wait. B's task description matches the footer in the third screenshot.
    • Every subagent record the parent has for B and C is completed and delivered: the original task, then one provider-continuation record per wake turn.
    • The parent's own provider thread has no pendingBackgroundTasks, and no record of its children is open, so resolveThreadStatusPill has nothing to show Waiting for.

    How the children got there

    Child B, times in UTC:

    Time Event
    22:25:35.195 Run 1 ends with an awaited command pending. The original task stays open, which is correct.
    22:34:23.787 The awaited command has exited, and the original task is marked completed.
    22:34:24.007 The parent receives Delegated task "…" finished.
    22:34:24.034 The child's wake run 2 is requested.
    22:34:37.081 Run 2 ends with a new awaited command pending. Its provider-continuation record completes at 22:34:37.840 with the result "Waiting on the rerun of heavy npm test."
    22:52:28 to 22:53:47 Run 3 does the same. Its record completes at 22:53:49.
    23:15:16 to 23:15:53 Run 4 does the same. Its record completes at 23:15:54.

    Child C followed the same path. Its run 1 ended at 22:37:58.033 with an awaited command pending, the original task completed at 22:52:18.157, and wake run 2 was requested at 22:52:18.341.

    So in both children the original task closed about 0.2 s before the wake run existed (247 ms for B, 184 ms for C). That is the gap in #24297. After that, every wake turn becomes its own provider-continuation task, and such a task closes when its run ends, even with an awaited command pending. On main at 3e4d449, the hold in finalizeAppOwnedSubagent (apps/server/src/orchestration-v2/Orchestrator.ts:13087) only applies to the original task, as this comment on #24297 also found.

    What the open fix PRs would cover

    Expected

    While a child's provider thread holds awaited background work, its task stays open. Then the parent's row shows Waiting and the subagent row doesn't say Finished.

    Observed in a live session, not reproduced in isolation. Filed by Claude Code (claude-opus-5-5 and claude-fable-5-2) inside T3 Code, following .github/triage/PLAYBOOK.md.

  12. Possemaster commented on Nov 10, 2026

    @Possemaster

    Still reproducible on t3 v0.1.8 (Claude Code 2.1.322 parent and child), via the follow-up path described above:

     

    1. The parent sent a follow-up to a finished delegate_task child with t3_thread_send. The answer was delivery: "started" with a new taskId.
    2. The child (run 4) started a long UI-review command in the background and ended its turn with "Waiting for the run's completion notification."
    3. The parent immediately got a completion for the new taskId, with that run-4 text as the result.
    4. The background command exited, and the child woke as run 5 (08:44:27 → 08:46:09 UTC). Run 5 wrote the real report and a commit. That result was never delivered to the parent.
    5. t3_thread_wait(threadId, untilDelegatedWorkSettled: true), called while the background command was still running, also returned resultRun = run 4 (completed, not timed out) before run 5 existed. Only a second t3_thread_wait on run 5's id, then t3_thread_read, got the real report.
       
      So the parent sees a progress note as the final result, and untilDelegatedWorkSettled does not wait for the pending background-exit wake either (the same gap as [Bug]: Original delegate_task task finalizes on a stale result in the gap before the child's background-exit wake turn #24297, on the follow-up task).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions