Repository navigation
App-owned follow-up completes while nested work runs, then loses the final result #21837
Description
What happened
An app-owned follow-up published INTERIM as a completed result while its nested checker was still running. The checker later resumed the writer, which produced FINAL, but FINAL was not automatically delivered to the parent. The parent could mistake the interim response for completion.
Expected: keep the follow-up pending until its nested work and continuation finish, preserve continuation ownership, and deliver FINAL to the parent exactly once while preserving the original READY task result.
This was one controlled lifecycle with a deliberately interim response, not evidence of the model spontaneously stopping. Frequency is unknown.
Diagnosis
Saved task responses and scoped projections establish three observations: premature terminal publication, an automatic continuation without the follow-up task association, and no parent result transfer for that continuation through the final snapshot.
Source inspection at upstream commit 10f7db7e38ea353c5b2b6c324c155cb6a6bedf72 is consistent with this sequence: finalization gates nested-work readiness for the original task; follow-up intake excludes agent/server dispatches such as the delegated-completion wake. This is a source-level explanation, not a verified mapping to the tested executable.
Correction and original-obligation retention passed after recovery. All child work completed. Native compaction was neither exercised nor witnessed; behavior on newer builds and other providers has not been established.
Steps to reproduce
- Use async
delegate_taskto start a disposable writer. Ask it to retain a synthetic value M1 and an obligation for later work, then return READY. - After READY, send one
t3_thread_send(mode="queue")to that child. It starts immediately because the child is idle. Replace M1 with M2 and request one async nested checker viadelegate_task. - Have the checker wait about 40 seconds and return a synthetic marker. Instruct the writer to end its first follow-up turn immediately with INTERIM, then consume the checker result on automatic continuation and return FINAL.
- While the checker runs, inspect the returned follow-up task ID with
task_status. After the automatic continuation ends, capture its task association and exact source-run parent transfers before reading the final result. - Read that follow-up's
task_statusonce to recover the later terminal summary.
This is a same-conversation continuation, not an independent review round. Independent delegated review rounds still require fresh delegate_task calls.
Version
v0.1.1-nightly.20261018.3335 — observed on 2026-10-19 UTC. This is the affected running build recorded during the experiment, not a triage CLI version or a claim about the current installation.
Environment
Linux/WSL, installed t3 serve runtime; T3 app-owned delegation. Writer and nested checker: Codex gpt-6.1-sol, reasoningEffort=high, serviceTier=default. Client, Node, and provider CLI versions were not recorded.
Evidence
Normalized excerpts from retained projections and tool responses; UTC on 2026-10-19:
02:36:27: checker running; follow-up completed/result_available
hasPendingChildRuns=false; published summary=INTERIM
02:37:02: checker completes; automatic writer run 3 starts
delegatedCompletion.parentRunId points to follow-up run 2
run 3 delegatedTaskId absent (SQL extraction: null)
02:37:42: run 3 completes with substantive FINAL
02:38:04: no parent subagent_result transfer for run 3
02:38:10: task_status exposes FINAL in latestTerminalSummary
latestTerminalResultContextTransferId=null
stable summary remains INTERIM
02:38:20: final snapshot still has no parent transfer for run 3
Parent transfers exist for READY and INTERIM. The pre-recovery snapshot predates the recovery read. Four child runs and three task records completed.
Recorded executable SHA256: d01ba2e9bbdcaa4da0cb9a60a17a73a0861c2841080555b71401102a0b6cd30d. Installed executable-to-source mapping remains unknown.
Related issues
- #13490, closed by merged #17696: direct follow-up delivery. This case adds nested work and an automatic continuation after that follow-up.
- #16603: early completion with live work; includes an unconfirmed nested-agent observation. This report supplies a specific app-owned follow-up lifecycle with lost FINAL evidence; a common cause has not been established.
- #21772 / #21813: provider-triggered wakes. The PR explicitly excludes delegated-completion wakes from grandchildren.
- #18649, closed without merge: related result-delivery proposal, not a shipped fix.
Fix applied or workaround
No runtime fix applied. One later task_status read recovered FINAL from latestTerminalSummary; check the later run identity rather than treating the stable INTERIM summary as final. An explicit final parent handoff remains an operational workaround, but was deliberately not exercised here.
Filed by
Prepared by GPT-6 Astra through the Codex harness in T3 Code, using retained experiment evidence from Codex GPT-6.1 Sol. No t3 triage CLI run was performed.
Activity
juliusmarminge commentedon Oct 19, 2026
Note
Grok responding on behalf of Julius.
Thanks for the controlled lifecycle and the careful limits. Current main matches both parts of your reading.
apps/server/src/orchestration-v2/Orchestrator.ts:10603-10614). A follow-up task finishes as soon as its latest run reaches a terminal state (Orchestrator.ts:10252-10262), so a follow-up can publish while its own nesteddelegate_taskis still running.apps/server/src/orchestration-v2/ProviderContinuationService.ts:119-135). Follow-up intake ignores that kind of message (Orchestrator.ts:6940-6949), so the continuation run has no task, and its result never reaches the parent.This overlaps with #16603 and #21772, but neither covers it. #16603 is about the original task and running commands. The open fix for #21772 still leaves this wake out on purpose. Keeping this open as its own bug.
For now, reading the follow-up's task status after the nested work finishes shows the later result.
juliusmarminge commentedon Oct 21, 2026
Reproduced on current main 70e5e384da using the web dev server on Linux with isolated, pruned real data. Writer and nested checker used Codex
gpt-6.1-sol, high reasoning, standard service tier.Ran READY → one queued follow-up → async checker (
sleep 40) → INTERIM → automatic FINAL. While the checker ran, the follow-up already reportedcompleted/result_available, summaryINTERIM,hasPendingChildRuns=false. Writer run 3 later completed withFINAL BETA21837 CHECK21837, withoutdelegatedTaskIdor a parent result transfer. Parent received READY and INTERIM only. A final status read recovered FINAL vialatestTerminalSummary; published summary stayed INTERIM and original READY remained intact.Runtime transcript and scoped projection excerpts. The duplicate scan found no matching open report for this nested follow-up lifecycle.
juliusmarminge commentedon Oct 22, 2026
Existing fix #21877 addresses this lifecycle; no replacement PR opened. The retained Linux web/server reproduction on 70e5e384da shows READY and INTERIM delivered, with FINAL recovered only through task status. Independent verification of the existing PR head could not finish: the VM became saturated and tool calls stalled. Issue remains open pending verification and landing.
CookerTea commentedon Oct 24, 2026
Still happening on 0.1.2 (stable) with Claude children: twice in two days, a
t3_thread_sendfollow-up task finalized at the end of its own turn while the child'sdelegate_taskreviewers and arun_in_backgroundBash command were still running. The real result came in a later turn and never reached the parent. Same shape as the report above. The race on the original-task path is filed separately as #24297.vhpx commentedon Oct 25, 2026
Additional production impact observed by our project orchestrator on 2026-10-25. The installed macOS desktop reports
0.1.3-nightly.20261024.3630. This is a current user/operator report, not a new controlled reproduction or an executable-to-source mapping.Six delegated lanes today followed the same pattern: an interim result such as waiting on a background suite reached the parent; a background/watch completion automatically started a later child run; that run produced final PR/head/verdict information, but no completion notification reached the parent. The parent recovered the later result through
task_status.latestTerminalSummaryor a child timeline read. Original-task and follow-up paths should both be checked; #24297 may cover part of the former.Could the existing fix ensure every terminal run of an owned child has durable parent-result delivery, including background/watch/self-wake runs after the original task has already finalized? Please preserve original task lineage and distinguish interim from final state; either associate those wakes with the owning task or deliver a child-run result keyed by child thread and terminal run. Exactly-once processing needs a durable delivery/consumption identity so crash/retry/manual recovery cannot lose a result or trigger duplicate integration.
Useful regression cases: original task and queued follow-up; nested child and background command completion; multiple later child runs; completed/idle versus running parent; interrupted/provider-failed terminal child; app restart between terminal event and delivery; late/manual status recovery; settled predecessor with explicit custody transfer. Preserve active background custody rather than settling a child merely because its interim task says completed.
We are adding explicit child-to-parent completion receipts plus per-terminal-run parent reconciliation as an operational workaround. This is not a runtime fix or independent proof that the pending PR resolves all reported cases. No credentials, private transcript or customer data are attached.
ScottN-PV commentedon Oct 25, 2026
Written by Claude Opus 5.5 on behalf of @ScottN-PV.
#21877 (head
3dda05ac50) covers less than this. It fixes one case: a queued follow-up whose own run starts a nesteddelegate_task. That follow-up stays pending until the nested task ends. The nested-result wake then runs under the follow-up's task, so the final reply reaches the parent once.It does not cover wakes from background commands or watches. The follow-up waits while the provider lists the command as pending. The wake run that the command's exit starts has no task, so its result is not delivered. It also leaves the original task unchanged, and it adds no per-run or restart delivery handling. #21772 and #24297 track those paths.
This comes from reading the source and from our Linux test of the nested case. We have not run your macOS build.
DanielJomphe commentedon Oct 27, 2026
Focused tests confirm ScottN-PV's reading above. With #21877, a follow-up that starts a background command (CookerTea's
run_in_backgroundcase) is held while the command runs, but it still completes with its interim reply.When the command exits, Claude wakes the child in a new run. The original task already has a result, so
recordSubagentFollowupgives that run a new task (Orchestrator.ts:7458onmain). The real reply does reach the parent, but as a second task with the same title, while the follow-up itself completes with its interim text. #21877'scontinuedTaskIdavoids this for nested results, which name their source run indelegatedCompletion.parentRunId. A background-command wake names no run.Two focused tests in
DelegatedCompletionDelivery.test.ts, onmainat570d4b03ee:mainThe tests write orchestrator events directly. They model the adapter with #24391, which keeps the command published until its wake run ends. Without #24391, the published roster empties before the wake run starts (#24297), which gives the follow-up an earlier chance to finalize on its interim reply.
Regression tests (DelegatedCompletionDelivery.test.ts)
Put
seedBackgroundFollowupabove thesubagent follow-upsblock and the two tests inside it; they use the file's existing helpers and imports.Results at
570d4b03ee:#21877 is waiting on verification, so I'd follow up after it lands rather than stack on it.
Reported by DanielJomphe. Investigation and tests by Claude Opus 5.5 in Claude Code, through T3 Code.
Dropje97 commentedon Oct 28, 2026
Still observable on
0.1.3-nightly.20261027.3754on Linux x64 (Debian 13), with a Claude Fable 5.1 parent and Claude Opus 5.5 children. Provider initialization records confirm Claude Code2.1.311andbypassPermissions. Codex CLI0.165.0is installed at inspection; the cases below were traced in Claude children, not independently reproduced with Codex.This is a local build of upstream
d2c440312e5f39d59827ed466838a623516454d6with SQLite read-performance patches. The task intake/finalization and completion-dispatch logic are unchanged; the MCP service and continuation service match that upstream revision byte for byte. No clean-release reproduction was run.Read-only database inspection found these completed later runs without a
delegatedTaskIdor a parentsubagent_resulttransfer. All times are 2026-10-27 UTC; A–C are separate children:Delivery is selective: child C's runs ending at
23:36:57.337Zand23:39:28.194Zhad task associations and parent transfers. Child B's intervening runs at23:07:16.761Zand23:08:45.841Zdid too.An additional original-task case produced READY at
21:55:09.277Z; its first parent result transfer instead referenced a later rebase/status reply at22:02:15.234Z. I have not established that this shares the nested-follow-up cause.Our workaround is to check PR status and read child task/thread results explicitly. The needed behavior is to retain the follow-up's ownership through nested-result wakes and deliver its eventual report once, including decision requests. #21877 remains open and unmerged; I have not tested its fix.
Hassan-Zbib commentedon Oct 29, 2026
Note
Claude Opus 5.5 (Claude Code) posting on behalf of @Hassan-Zbib.
Background-command case on
0.1.4-nightly.20261028.3814(Windows 11, Claude Code 2.1.312, Opus 5.5 parent and child, asyncdelegate_task): at3_background_waitmark (#24610) doesn't hold a wake run's follow-up task.After the original task closed early (#24297), each wake run got its own
provider-continuationtask. Each of those completed when its run ended, even though the child had marked a still-running command and got it back inmatched. Fromstatev2.sqlite, UTC:bpoldxej6,br8ttxfbrpnpm gateare both running in the background…"bpoldxej6incidents+platform(taskbpoldxej6)."bo50xuxz0The final result is no longer lost; it arrives as another task with the same title. But the parent got four interim "completed" notices, each costing a turn. Holding a follow-up open while its own marked waits run, as the original task is held, would fix that.
Aside: the system prompt says to call
t3_background_wait"with its task ID", but the tool takes ataskIdsarray, so the child's first call ({"taskId":"b3gyl80d9"}) failed validation.DavidPerezA12 commentedon Oct 30, 2026
Still present on stable 0.1.5 (macOS, Claude Opus 5.5 parent and child), and on
mainat32ecd71726.A
provider-continuationtask completed when its run ended while its command was still markedawaited: true.A visible effect not mentioned above: the parent's Lineage moves the child to "Previous agents" as completed for the whole wait (about 24 minutes here).
grisetio commentedon Oct 30, 2026
Note
Written by Claude Opus 5.5 (high reasoning effort, Claude Code harness inside T3 Code) on behalf of @grisetio, who reviewed it before posting.
Another case on macOS arm64, Claude Opus 5.5 parent and child, both on high reasoning effort, async
delegate_task. It covers the background-wake shape above and also shows a server restart variant: the child's final run is a restart continuation with no task at all, so its result never reaches the parent.The server runs a fork of stable with one patch (a Codex account-usage view) that doesn't touch orchestration. Runs 1–2 were on a v0.1.3 base with Claude Code 2.1.312. The child's own work restarted the server mid-sequence, so run 3 was on v0.1.5 with Claude Code 2.1.314.
Times in UTC:
provider-continuationtask. The child starts another background command, which restarts the T3 server once it activates, marks it witht3_background_wait, and ends its turn with another interim reply. The parent gets that as a second completed task with the same title.task_statusstill shows the original task's run-1 interim summary. The final report could only be found by reading the child thread.As we read #27222 ("once a task has settled, it no longer owns later work in the child thread"), dropping run 3 is intended behavior once the original task has settled. So with an early settlement (#24297) and a restart, the final result is lost entirely, rather than arriving as a duplicate task as in the cases above. #21877 wouldn't change this either, because nothing here involves nested
delegate_taskin a follow-up.Expected: the parent receives the run-3 result exactly once, either because the original task stays open across the background wait and the restart, or because restart continuations of a child thread report under the last task that owned the thread.