Repository navigation
Description
What happened
An agent (Claude, claude-opus-5-5) merged the thread's linked PR, started a background Bash command to poll the deploy's check runs, registered it with t3_background_wait, and ended its turn saying it would continue when the build finished. When the command exited, the thread auto-settled 7 ms later. Settling detached the provider session, so the agent never received the task-completion notification and never resumed. The user had to send a message to get it going again.
Diagnosis
The thread was eligible for auto-settle on merge (sidebarAutoSettleOnMerge, default true) because the PR merged after the latest user message. isAutoSettlementCandidate correctly held it while the awaited task was pending (backgroundWorkHoldsCompletion). When the task finished, provider-thread.updated emptied pendingBackgroundTasks, ThreadSettlementService.processEvent enqueued a sweep, and thread.auto-settle was sent at once. Settling detaches live provider sessions (Orchestrator.ts, "Archive and settle stop idle background work"), which kills the follow-up turn the provider was about to start for the task notification. threadHasQueuedTurnStart only gives a grace period to user messages, not to provider-started follow-up turns. The same race should apply to inactivity-based auto-settle.
Possible fixes: give a short grace period after awaited background work ends (like QUEUED_TURN_START_GRACE_MS) before a thread can auto-settle, or skip auto-settle until the provider has handled the task's completion notification.
Steps to reproduce
- Keep "Auto-settle on merge" enabled (the default).
- In a Claude thread, have the agent open a PR and link it to the thread.
- Ask the agent to merge the PR and then wait for CI/deploy, e.g.
run_in_backgrounda loop that polls check runs for ~1-2 minutes, then callt3_background_waiton that task and end the turn. - When the background command exits, the thread auto-settles immediately and the agent never resumes.
Version
0.1.7-nightly.20261103.4138 (desktop app, local server, macOS arm64). Commit 115739c.
Environment
macOS 27.0 arm64, Node 24.22.1, T3 Code Desktop against its local server, provider claudeAgent (claude-opus-5-5).
Evidence
- Turn ended 20:51:19.05Z right after `t3_background_wait` returned `{"matched":["bs00argh7"],"unmatched":[]}`.
- PR snapshot: `state: merged`, `mergedAt: 20:51:03Z`; latest user message 20:49:16Z.
- Server trace: `orchestrationV2.EventSink.writeIfProviderThreadOwner` at 20:53:01.391Z, then `orchestrationV2.dispatch.once` `thread.auto-settle` (command id `server:auto-settle:<thread>:...`) at 20:53:01.398Z.
- Next activity was the user's message at 20:56:19Z, which unsettled the thread and started a new provider session.Related issues
#11788 (snoozed threads auto-settled), #11711 (pinned threads auto-settling). Neither covers this.
Fix applied or workaround
Turn off "Auto-settle on merge" in Settings, or pin threads that are waiting on post-merge work.
Filed by
Triaged and written by Claude Opus 5.5 (claude-opus-5-5) via Claude Code inside T3 Code
Activity
addisonk commentedon Nov 5, 2026
Another occurrence today, on T3 Code 0.1.6 (macOS desktop, Claude provider, claude-opus-5-5, full-access thread launched by another thread with
t3_thread_launch). Same outcome: the agent never resumed and the user had to send a message. The timing differs from the report above, though: the thread settled when the turn ended, while the awaited task was still running, not when the task exited.Timeline (UTC, from
t3_thread_read):bk3zmhrho).t3_background_waitwith that ID returns{"matched":["bk3zmhrho"],"unmatched":[]}.settledAtis the same timestamp.updatedAtmoves to 23:09:47.820, but no run starts.So the awaited task held the thread for under a second: settlement fired at turn completion, about 94 seconds before the task ended. The thread was merge-settle eligible, since the PR merged after its latest user message. This may be the merge-sweep path in #29899, or the awaited task not yet counting as pending when the turn closed. I haven't read the code to tell which.
A
t3_thread_send(modeauto) from another thread restarted it.Written by Claude Opus 5.5 in Claude Code, run from T3 Code.
mahirozdin commentedon Nov 9, 2026
Same failure here on 0.1.7 (Linux server, Claude Agent). I posted numbers from about three weeks of use in #26083 (#26083 (comment)): 10 manual interventions after merge-then-deploy flows, and in 7 of them
t3_background_waithad already been called.jelsco commentedon Nov 10, 2026
Four more occurrences of the turn-end variant described in the comment above, on 0.1.7 (Windows x64 desktop app, Claude provider, claude-opus-5-5). In each one the wait matched, and the thread settled at the exact moment the run completed, while the awaited task was still running. Settling detached the session, so the task's completion never woke the agent.
Both threads were merge-settle eligible: each had a linked PR that merged after the latest user-authored message (thread A's PR at 2026-11-09 00:16:36Z, thread B's at 2026-11-09 15:33:52Z).
Times are UTC, read from the thread's turn items and
settledAt:t3_background_waitresultsettledAtmatched: ["b3nc8i6z9"]matched: ["brh008qal"]matched: ["bz5c28s40"]matched: ["bxlmvd07e"]The tasks were a pre-push check run of roughly 10 to 15 minutes, so each was still running when the thread settled. Each thread sat idle for 2 to 9 hours until a message from another thread restarted it.
As far as I can tell, the open fixes (#26108, #29820, #30837) cover the gap between the awaited task finishing and the wake turn attaching. #31449 covers explicit settles. None of them seems to cover this case: here
isAutoSettlementCandidatelets the merge sweep settle at run completion, as ifpendingBackgroundTaskswere empty at that moment even though the wait had matched seconds earlier. I haven't traced why the pending list is empty at that point.What we're running locally in the meantime, in case it helps anyone: in
resolveAutoSettlementAt, the merge/close path returns null until the thread has been quiet for a window. Quiet means no run activity and no sweep that sawbackgroundWorkHoldsCompletiontrue. That covers both variants. It is a behaviour change (merged threads linger for up to that window), so I'm not proposing it as the fix.