# Claude session idle-released while its run waits on a delegate_task child; Stop and Settle then fail permanently · Issue \#15173 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/issues/15173)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: completed

Priority: 0

## Description

[Discussion and activity](https://git.cafe/pingdotgg/t3code/issues/15173)

---

### What happened

A V2 Claude thread can't be stopped or settled. I press Stop and nothing happens; Settle is refused. Messages I send ("stop", "stop working") queue up and never start. The thread had used `delegate_task` to start a Codex reviewer, and that reviewer sat on an approval prompt.

### Diagnosis

The Claude session is released after 30 minutes idle while its run is still waiting on an app-owned delegated child (`delegate_task`). After that release, nothing in the UI can end the run.

1. The parent Claude run calls `delegate_task` (Codex child), and its native turn ends (`end_turn`). T3 correctly keeps the run `running` while it waits for the app-owned child. The child is slow; here it waited on an approval prompt.
2. `ProviderSessionManager.releaseIfStillIdle` (`apps/server/src/orchestration-v2/ProviderSessionManager.ts` ~L864–940) only defers release for `runtime.hasPendingBackgroundWork`, the adapter's *native* background work. It doesn't count an app-owned delegated child of a running run. Exactly 30 minutes after `end_turn` the Claude session is released (`query.close`), and the session is persisted as `stopped`. The provider turn row stays `running`.
3. Stop (`run.interrupt`) fails. In `Orchestrator.ts` the `settleOnly` fallback (~L7926) applies only when `providerTurn.status !== "running"` *and* the session is gone. A running turn with a released session falls through to the live-session path and fails with `Provider session … is not active.` (~L7978).
4. `thread.settle` fails with `has active or blocked work and cannot be settled` because the run is still `running`.
5. When the delegated child ends, its completion notice is queued as a new run behind the wedged run. User messages are queued the same way. Neither ever starts, and promote-to-steer fails for the same reason.

Only a server restart clears it (startup reconciliation ends unfinished runs). Restarting interrupts every other active thread on the server.

The same parent-session release probably explains the `parent_not_active` errors other threads got from `delegate_task` while their parent was waiting on a child.

Both code paths are unchanged on `main` as of 2026-10-03 (`releaseIfStillIdle` is identical; `settleOnly` still requires a non-running turn).

### Steps to reproduce

1. On a V2 Claude thread, have the agent call `delegate_task` for a Codex child that won't finish within 30 minutes. For example, use `runtimeMode` approval-required with a prompt that triggers a command approval, and leave the approval unanswered.
2. Let the parent's Claude turn end while it waits for the child. Wait just over 30 minutes (default idle timeout). The provider event log shows an outgoing `query.close`, and the provider session becomes `stopped`. The run, run attempt, root node and provider turn all stay `running`.
3. Press Stop on the parent thread. It fails with `Provider session … is not active.`
4. Press Settle. It fails with `has active or blocked work and cannot be settled`.
5. Send a message. It queues and never starts. Promoting it to steer fails.

### Version

Desktop app 0.0.46-nightly.20261003.2610 (8ed276c246b6); CLI 0.0.45

### Environment

Linux x64 (kernel 7.0.0), desktop AppImage, Node v26.8.2; parent provider claudeAgent (claude-opus-5-5), delegated child codex

### Evidence

```shell
# Provider event log (parent thread): turn ends, then idle release exactly 30 min later
[2026-10-03T10:31:30.363Z] incoming result stop_reason=end_turn
[2026-10-03T11:01:30.935Z] outgoing {"type":"query.close"}

# Projection state (statev2.sqlite) for the parent thread afterwards
run ordinal 1        status=running    (since 10:21:41Z, completed_at NULL)
provider_turn 1      status=running
provider_session     status=stopped    updated_at=11:01:30.936Z
subagent (codex, app_owned, delegate_task)  status=interrupted  completed_at=12:11:56Z
run ordinal 3 (delegated-completion notice)  status=queued
run ordinal 5 (user "stop working")          status=queued

# Server trace: 13 run.interrupt attempts between 12:07 and 12:14, all failed
OrchestratorDispatchError: Failed to dispatch orchestration command run.interrupt (...)
  [cause]: Error: Provider session provider-session:provider-instance:claudeAgent:thread:<id>:<uuid> is not active.

OrchestratorDispatchError: Failed to dispatch orchestration command thread.settle (...)
  cause: Thread <id> has active or blocked work and cannot be settled.

OrchestratorDispatchError: Failed to dispatch orchestration command queued-message.promote-to-steer (...)
  cause: Provider session ... is not active.
```

### Related issues

No existing issue. Closed, unmerged PRs addressed parts of this: #14857 (Stop ends a V2 run whose session is gone, which is exactly the Stop half; closed 2026-10-02 without merging), #14507 (settle a run when its idle session is released; closed), and #14856 (event-consumer failure as a different trigger for the same stranded-run state). #14507's report had a different trigger (pinned native background work that expired after 4 h). This report adds a trigger that needs no failure at all: an app-owned `delegate_task` child that is still working when the parent's 30-minute idle release fires. #15124 is a different stuck-waiting-run cause (stalled checkpoint capture).

### Fix applied or workaround

None applied yet. Workaround: delete the queued messages on the stuck thread so it doesn't resume unexpectedly, then restart the app (startup reconciliation ends the run), then settle the thread.

### Filed by

Claude Code (Claude Opus 5.5) via `t3 triage`

