Skip to content

Steering during a delegate_task wait call drops the child's result and shows "Failed to delegate a child task" #27362

Closed

Description

@moinmir

Note

Filed by Claude Code (Claude Opus 5.5) via T3 Code triage.

What happened

A parent called delegate_task with mode: "wait", and the user steered the parent while it waited. The steer cancelled the tool call, so the parent got no taskId. The child kept running and completed, but its result never reached the parent, during or after the turn.

The work-log row also misled the user. During the wait it shows "Delegating a child task", which looks like a stuck launch and invites the steer. After the steer it shows "Failed to delegate a child task", although the child launched and is running.

Diagnosis

Links are pinned to main at a773dc3.

mode: "wait" records the task with completionWake: "settled_only" (OrchestratorMcpService.ts#L2293). With settled_only, the orchestrator skips delivery while the spawning run is live, because the blocking call is expected to return the result (Orchestrator.ts#L11794-L11805).

awaitTask switches the task to completionWake: "always" only on a timeout (OrchestratorMcpService.ts#L1613-L1628). A steer cancels the call but merges into the spawning run, so the run stays live. The child completes, delivery is skipped, and nothing retries when the run settles.

The row label comes from a static table that ignores mode (t3McpToolPresentation.ts#L131), and an interrupted call renders as "Failed to …" (work-log/presentation.ts#L174-L185).

Suggested fix: switch to completionWake: "always" whenever a wait ends without a result, not only on timeout. Label a launched wait as "Waiting for ", and don't show "Failed" when only the wait was cut short.

Steps to reproduce

  1. From a Claude thread, call delegate_task with mode: "wait" and a child task that runs sleep 90.
  2. Steer the parent during the 90 s.
  3. The call returns "interrupted" with no taskId, and the row shows "Failed to delegate a child task".
  4. Let the child finish and the parent's turn end. No completion notice arrives.

With mode: "async", or with mode: "wait" and no steer, the result arrives normally.

Version

0.1.4-nightly.20261028.3824 (server). The relevant code is unchanged on main as of 2026-10-30.

Environment

Linux x64 (WSL2), Node v26.12.1, Claude Code 2.1.314 (parent, Opus 5.5), codex-cli 0.166.0 (child, gpt-6.1-sol).

Evidence

Task row after the child completed and the parent's spawning run settled:

status: completed
completionWake: settled_only
completionDelivery: null
completedAt: 03:47:03Z   (spawning run settled 03:47:13Z)
Delegating a child task during the wait Failed to delegate a child task after the steer

Related issues

#11168: same missing switch to completionWake: "always", but there the client drops the request after ~5 min. This issue covers a steer and the wrong labels.

Fix applied or workaround

No changes on the machine. Use mode: "async" for long children, or find an orphaned child with t3_thread_list (includeSubagents: true).

Activity

  1. domvox commented on Oct 30, 2026

    @domvox
    Contributor

    Reproduced twice on T3 Code 0.1.5 using Claude Haiku 5.5 for both parent and child. Without steering, the confirmation code reached the parent. Steering during delegate_task(mode="wait"), while keeping the parent run active until the child completed, prevented delivery in both trials. The code remained visible in the child card. Thanks for preparing the fix.

  2. domvox commented on Oct 30, 2026

    @domvox
    Contributor

    Retested on the macOS desktop release 0.1.6-nightly.20261030.3917: the result-loss bug still reproduces.

    Parent and child both used Claude Haiku 5.5, medium effort, with T3's MCP delegate_task (not Claude's native Agent tool).

    Results:

    • Control: mode: "wait" without steering — 1/1 result delivered.
    • Steering during the blocking wait — 2/2 results lost, despite both children completing successfully.

    In both reproductions, the steer was confirmed as applied to the same parent runId, and the child completed before that parent run settled. The child generated its own 16-character confirmation code, which was never supplied in the parent's prompt or steer. The parent did not manually read the child history or call task_status; it reported CONFIRMATION_NOT_DELIVERED. A later check of the parent's messages also found no confirmation code.

    Read-only inspection of the task state after completion showed, in both steered cases:

    status: completed
    completionWake: settled_only
    completionDelivery: absent
    

    The control had completionDelivery.state: acknowledged.

    Timing evidence (UTC):

    Trial Child completed Parent run completed
    Steer 1 18:42:42.507 18:42:48.134
    Steer 2 18:43:33.601 18:43:36.916

    The timing was controlled with t3_thread_wait, without shell sleeps or file operations. This retest covers the lost-result behavior; it does not establish the status of the separate work-log-label issue. Async mode and other provider combinations were not retested on this nightly.

  3. 1kuna commented on Nov 9, 2026

    @1kuna
    Contributor

    Title: Related wait-mode loss without a steer: completion acknowledged against a terminal run

    Problem: A retained Codex child-of-a-child case shows a related result-loss path without any steer or user input. The spawning run ended with its blocking delegate call still pending. The child later completed, but delivery was acknowledged without an observing run or committed notice.

    Reproduction or observation: Historical read-only database/event inspection on T3 Code 0.1.6, macOS arm64; no fresh reproduction on current main. The parent called delegate_task with mode: "wait" and timeoutMs: 600000, recorded as completionWake: "settled_only", then continued other tool calls.

    Relative event sequence, paraphrased from the records (no raw transcript):

    • Start: the blocking delegation and child task begin.
    • About 3 minutes 38 seconds later: the spawning run enters waiting, the delegate tool call is cancelled, and the run completes.
    • About 6 minutes 1 second after start: the child completes; delivery becomes claimed and is attached to the already-completed spawning run. A result context transfer is recorded as consumed.
    • About 0.2 seconds later: delivery becomes acknowledged with observedByRunId: null, and the run's delivery field is cleared. No corresponding notice message or new parent run is present.
    • The parent next runs roughly 18 hours later, triggered by an unrelated message.

    This was the only acknowledged-with-no-observer case among 1,060 acknowledged tasks inspected. Among the other 259 wait-mode tasks, 258 returned to a wait whose run was still live and one woke the parent normally. Unlike the opening report, this case did not involve steering.

    Proposed behavior: When a blocking wait can no longer return a result to a live run, fall back to a durable parent wake. Acknowledge only after a live consumer receives the result or a notice is committed; do not consume it against a terminal run. #20274 and the more direct wait-cancellation fix #27387 are open at this check. This evidence may help distinguish their coverage.

    Why native: Only T3 can atomically coordinate wait cancellation, run state, context-transfer consumption, and completion acknowledgement.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions