Skip to content

Auto-settle on PR merge races the Claude wake turn after an awaited background task completes #26083

Closed as not planned

Description

@hanneslipusch

Version: 0.1.3 (also on main as of 80f411f13d)

What happens
An agent runs a background Bash task (a merge wait), registers it with t3_background_wait, and ends its turn. The linked PR merges while the task runs. When the task exits, the thread is auto-settled before the Claude wake turn is registered, and settling closes the session, so the wake turn is lost. The agent never runs its post-merge steps.

Timeline from one real thread

  • .015 background task exits (exit 0); task list empties and triggers the settle check (ThreadSettlementService.ts:618)
  • .022 thread settled (auto-settle on merge; no active run yet)
  • .040 session detached, reason "Thread settled." (Orchestrator.ts:3851)
  • .045 query.close sent to Claude
  • Claude had started the wake turn (API request at .227); it never completed.

Why
#24610 (fixing #17625) protects the thread while the awaited task runs. It does not cover the gap between task completion and the wake run attaching: ClaudeAdapterV2.ts:7632-7669 only registers the wake run once the reply streams, and its pending-work check (:10560) reads the already-empty task list.

Repro
Background sleep 120 + t3_background_wait on a thread whose linked PR has already merged, then end the turn. In a control run without a PR, the settle step fired at +8 ms after the task list emptied and the wake turn registered at +375 ms; with a merged PR the thread settles inside that gap.

Suggested fix
Keep the adapter's pending-work signal true from task completion until the wake run attaches, and have the settle check ask the live session (as stillReportsBackgroundWork already does). The ACP adapter already counts buffered continuations; doing it in the settle check covers every provider.

Workaround: disable sidebarAutoSettleOnMerge.

Activity

  1. danddanddand commented on Oct 31, 2026

    @danddanddand
    Contributor

    Another occurrence on 0.1.6 (Claude Code via the Agent SDK). This time the merged PR was a self-hosted GitLab MR.

    • The agent merged the MR, called t3_background_wait on a background Bash watcher, and ended its turn.
    • About 40 s later the watcher exited. The task_notification and the empty background_tasks_changed reached T3, and T3 sent query.close 13 ms later. That was before the CLI's wake API request (~50 ms).
    • No run or notification item appeared. The user got no update for 2 hours, until they sent a message themselves.

    Also, the "No response requested." that shows up in the Claude transcript after this is not the model ignoring the notification. On resume, the CLI writes it ("model": "<synthetic>") to close the dangling wake turn, so the model never saw the task finish.

    #26108 matches the trace. It now conflicts with main, so it needs a rebase before it can land.

  2. altintasutku commented on Nov 1, 2026

    @altintasutku

    Another occurrence on 0.1.6 (Windows, desktop app, Claude Agent SDK, claude-opus-5-5).

    • The agent merged its PR (~20:48Z), started a ~5 min background test run, called t3_background_wait on it (matched), and ended its turn at 20:53:54Z.
    • 20:59:13.496Z task_notification (completed) and an empty background_tasks_changed arrived.
    • 20:59:13.514Z ThreadSettlementServiceV2.sweep dispatched thread.auto-settle; query.close was sent at .602Z, 106 ms after the notification. No wake run or item appeared.
    • The thread stayed silent until the user wrote ~10 min later. On resume the model saw the synthetic "No response requested." and wrongly told the user it had ended the turn itself.

    sidebarAutoSettleOnMerge was at its default. +1 for landing #26108.

    Prepared by Claude Opus 5.5 (claude-opus-5-5) via T3 Code triage.

  3. aport73 commented on Nov 2, 2026

    @aport73

    Another occurrence on 0.1.7-nightly.20261101 (macOS, Claude Code 2.1.316 via the Agent SDK). The PR host was a self-hosted Forgejo, sidebarAutoSettleOnMerge was at its default, and after-days was off. I found 12 occurrences across 3 threads, all with merged PRs. About 270 idle wakes on other threads resumed fine.

    • task_notification (completed) and an empty background_tasks_changed arrived. About 100 ms later the CLI emitted system/status: requesting, its own wake turn.
    • 7 ms after that: thread.auto-settle → ProviderSessionManager.detach → query.close.
    • One more detail: the detach queues a recovery continuation as a buffered provider wake (creationSource: "provider"). The follow-up run resumes the query but never sends prompt.offer, because Claude drains an empty wake buffer (the notification died with the closed query). The run finalizes about 10 ms later. So the fallback can't recover a wake that was cut off. Delivering that continuation as message_text when the session that buffered it is gone would let it recover, independent of fix(server): auto-settle on merge waits for a pending Claude wake turn #26108.

    The thread stayed idle for 28 minutes (856 on another thread) until the user wrote. +1 for rebasing and landing #26108.

    This comment was written by an AI model, Claude Opus 5.5 (claude-opus-5-5), running in Claude Code inside T3 Code, and posted with the user's approval.

  4. ethan-huo commented on Nov 4, 2026

    @ethan-huo

    Still reproduces on 0.1.7-nightly.20261102.4093 (macOS, Claude Agent SDK, claude-opus-5-5), and main at e68e19d60 has no change to this path.

    Our trigger makes it deterministic rather than a race: agents merge their PR and then wait in the background for the deploy pipeline to promote the merge commit (15–40 min). The linked PR is therefore always merged when the awaited task exits, so every such wait is lost. Three threads, same shape each time:

    • system/task_notification (completed or failed) + empty background_tasks_changed, then outgoing query.close 12–45 ms later; no init, no wake run.
    • Earlier wakes in the same thread, before its PR merged, resumed normally (init → wake turn → result with origin.kind: "task-notification").

    Side note: sidebarAutoSettleKeepPullRequests: true does not help here, since resolveAutoSettlementAt returns for a merged PR before it reads that setting. Disabling sidebarAutoSettleOnMerge is the only workaround we found.

  5. enzotrp974 commented on Nov 5, 2026

    @enzotrp974

    Still reproduces on 0.1.8-nightly.20261104.4165 (macOS, Claude Code 2.1.316 and 2.1.318). We crossed the two conditions over 299 idle wake-ups from about two days of local logs:

    Linked PR merged before the wake-up No merged PR
    t3_background_wait used 71 wake-ups, 23 missed 106, 0 missed
    t3_background_wait not used 37, 0 missed 85, 0 missed

    "Missed" means no model reply within 5 minutes of the task notification. In the misses we read, query.close follows the empty background_tasks_changed by 43 to 258 ms, as described above.

    Two things this adds:

    • Every miss needed both conditions. A merged PR alone and t3_background_wait alone each lost nothing here.
    • Leaving out t3_background_wait is a second workaround, besides turning off sidebarAutoSettleOnMerge. The sample is small, and the thread no longer shows as working while it waits. The T3 system prompt tells Claude threads to call this tool, so the default instructions lead agents into this bug.

    Measured and written by Claude (Opus 5.5) from local session and provider logs.

  6. lukasbxy commented on Nov 6, 2026

    @lukasbxy

    Measured data from two self-hosted machines, in case it helps prioritise #26108, #29820 or #31449. Versions were nightlies from 0.1.7-nightly.20261104.4151 to 0.1.8-nightly.20261105.4234, with Claude Code 2.1.318 through the Agent SDK. sidebarAutoSettleOnMerge was at its default.

    I joined the provider protocol logs with thread.settled events. A "wake" below is a task_notification that arrived while the session was idle.

    Wakes from 2026-10-31 to 2026-11-06 Count query.close within 3 s
    thread.settled within 1.31 s after the notification 13 13
    No thread.settled nearby, session stayed open 310 0
    No thread.settled nearby, session closed anyway 12 12
    • In the most recent 48 hours, 15 of 88 idle wakes were lost, or 17%. Auto-settle accounts for 13 of those 15.
    • The settle landed 10 ms to 1,310 ms after the notification, with a median of 28 ms.
    • Ten of the lost wakes were only noticed when the user asked what had happened. Those threads sat idle for 1 to 422 minutes, about 17 hours in total. Three others were never resumed.
    • Before each loss the agent had done everything right: it started the background command, t3_background_wait returned it as matched, and the turn ended normally.

    Two details that may not be covered yet:

    1. A close without a settle. The 12 closes in the last table row show the same shape, task_notification, then an empty background_tasks_changed, then query.close, but with no thread.settled event within 5 s. Ten predate the 48-hour window. I could not identify the caller, because the server traces rotate after about 90 minutes here. This suggests fixing only the settle check may leave a second path open. hasPendingBackgroundWork in ClaudeAdapterV2 still reads as false while the buffer holds only the task_notification, since it counts user, assistant and result frames.
    2. A wake run that starts and dies. In 2 of the 15 cases T3 did create the run. The notification item appeared, query.open followed about 3 s later, query.close came within a second, and the run completed in 2 to 5 s with no assistant message or tool call. From the UI that looks like an agent that read the notification and decided to do nothing.

    As a workaround I set sidebarAutoSettleOnMerge to false in settings.json on both machines today. The server picked it up without a restart. I'll report back here if wakes are still lost.

    Prepared by Claude Opus 5.5 from local logs.

  7. lucasbastianik commented on Nov 6, 2026

    @lucasbastianik

    Another occurrence on 0.1.7-nightly.20261103.4119 (macOS, Claude Code 2.1.318 via the Agent SDK, claude-opus-5-5). sidebarAutoSettleOnMerge was at its default. Two wakes were lost in one thread, both on background commands awaited with t3_background_wait.

    • 2026-11-05 21:53:58Z: task_notification (failed), linked PR merged 21:51:07Z, last user message 21:45:31Z. provider-session.detach ("Thread settled.") came 7 ms later. Idle for 2h34 until the user wrote.
    • 2026-11-06 02:59:10Z: task_notification (completed), linked PR merged 02:33:39Z, last user message 02:01:01Z. Detach came 39 ms later. Idle for 6h02 until the user wrote.
    • The other 5 notifications in the session did not meet that condition, because no PR had merged since the last user message, and they all woke normally.
    • On resume the model again read the synthetic "No response requested." as its own reply and told the user it had failed, which hid the cause until we checked the raw transcript fields.

    We set sidebarAutoSettleOnMerge to false as a workaround. +1 for landing #26108 or #29820.

    Prepared by Claude Opus 5.5 (claude-opus-5-5) running in T3 Code, and posted with the user's approval.

  8. beausee commented on Nov 8, 2026

    @beausee

    Another occurrence on 0.1.7 (macOS, Claude Agent SDK, claude-opus-5-5), twice in one day, on a long-running orchestrator thread.

    • PRs linked to the thread merged, after the user's last message. The agent called t3_background_wait on a background Bash task and ended its turn.
    • 07:49:32.632Z: task_notification and an empty background_tasks_changed. 07:49:32.651Z: query.close (19 ms).
    • 11:20:17.916Z: the same pair. 11:20:17.955Z: query.close (39 ms). An earlier moment with one task still on the roster did not close.
    • The transcript shows the synthetic "No response requested." Each wake turn was lost.

    The cost is larger for an orchestrator. This thread was directing other threads. Nothing but a new user message reopened it, so it stayed closed for 3 h 25 min and then 25 h 2 min, and the workers' finished reports went unread.

    The settle event itself is gone from our rotated logs, so the link to the settle path is from the timing and the merged-PR condition. We have set sidebarAutoSettleOnMerge to false as the workaround. #26108 would be welcome.

  9. mahirozdin commented on Nov 9, 2026

    @mahirozdin
    Contributor

    I'm adding numbers from my setup. This has stopped being an occasional annoyance: it is now the most common way my agent work gets silently abandoned.

    Setup: T3 Code 0.1.7 on a Linux server running as a service, Claude Agent (claude-opus-5-5), about 10 active projects. "Settle on merge" is at its default. In my workflow the agents merge their own PR and then do the post-merge steps: deploy, release tag, store upload, live check, final report.

    What I measured (read-only pass over statev2.sqlite, Oct 16 – Nov 9):

    • 369 PR merges made inside an agent run, across 280 threads.
    • 42 of those runs started background work after the merge (deploy, CI watch, build, test run).
    • 10 times I had to step in manually because the post-merge work had been cut off, across 9 different projects. Each time the thread settled when the agent's turn ended, the provider session was detached, and no wake run appeared. The next thing in the thread was me asking "what's the status?"
    • 3 more threads were abandoned silently. The agent's last message promised a follow-up ("I'll verify 1.18.0 is live", "waiting for the release workflow to finish") that never happened, and nobody noticed at the time.
    • In 7 of the 10, the agent did exactly what T3 asks: it called t3_background_wait on the task before ending its turn. Once the linked PR has merged, the tool does not protect this path.
    • Those threads sat dead for anywhere from a few minutes to 4 hours before I noticed (two of them for about 2 h 10 m), roughly 9.7 hours in total.
    • It is getting worse. All 10 manual interventions came between Oct 31 and Nov 9. Before 0.1.3 I found one silent case. 0.1.3 shipped fix(server): threads settle right after a shell merge of an unlinked PR #24830 (immediate settle after a shell merge) and fix(threads): Working holds only background work the agent waits on #24610 (only awaited work holds). The settle code is identical in 0.1.5, 0.1.6 and 0.1.7, so this is how things work now, not a one-release regression.

    What it costs in practice:

    • A production deploy that died during the image build and left the site on the old version.
    • A TestFlight build that nobody checked.
    • A store resubmission waiting on a live check that never ran.
    • Final reports that were never written.

    I wrote "finish everything and write the report before merging, because the merge settles the thread" into my agent instructions in five separate threads and in my shared agent notes. It didn't help. Some of the remaining work only makes sense after the merge (deploying the merge commit, pushing the release tag), and the agent has no way to keep its thread alive while it does that work.

    Ask: #26108 looks like the right fix for the awaited case. Going by the data above, it would remove most of these incidents. Could it be prioritized?

    Related variant (3 of my 10): the agent merges, starts the deploy with run_in_background without t3_background_wait, and ends its turn. Under #24610 unmarked commands never hold, so the thread settles about a second later, and the detach kills the deploy itself. Timeline from today:

    06:29:29Z  gh pr merge 90 --merge --delete-branch (linked PR)
    06:30:03Z  remote.sh deploy started with run_in_background
    06:30:27Z  agent ends its turn: "when the deploy finishes I'll check 7 pages and write the final report"
    06:30:28Z  thread.auto-settle -> provider-session.detach "Thread settled."
               deploy log stops during the image build; the site stays on the old version
    08:40Z     I notice and ask what happened
    

    I understand the unmarked rule is intentional because of dev servers, so I won't file this as a bug. Still, when a settle is triggered by a merge, background work started after mergedAt in the same run is almost always the post-merge work itself. If you're open to it, I can write this up as an Ideas discussion. One option is to hold merge-settle while a task started after the merge is still live. Another is to let agents opt their own thread out over MCP, as in #26110.

    Workaround for anyone else hitting this: have the agent pin its thread (t3_thread_organize → pin) before merging, and call settle itself when the work is done. Pinned threads are skipped by isAutoSettlementCandidate, and settle applies at turn end and clears the pin. This keeps "Settle on merge" on for every thread that has nothing left to do after the merge.

  10. spereirag commented on Nov 9, 2026

    @spereirag

    Another reproduction on 0.1.8-nightly.20261105.4234 (desktop app, Linux x64, local server, Claude claude-opus-5-5). ThreadSettlementService.ts on main still has the same settle path, and #26108 / #29820 / #30837 / #31449 are unmerged.

    Timeline (UTC). The thread has 4 linked GitLab MRs, all merged after the last user message:

    • 18:10:57: the agent merges an MR, starts a background Bash loop polling a CI job, registers it with t3_background_wait (matched), and ends its turn at 18:11:03.
    • 18:12:06.023: task_notification, the background command completed (exit 0).
    • 18:12:06.024: background_tasks_changed, the task list is now empty.
    • 18:12:06: thread.auto-settle is accepted, then ProviderSessionManager.detach ("Thread settled.").
    • 18:12:06.053: query.close is sent to Claude. The turn reporting the task result never runs, and the agent only resumed when the user messaged about 70 minutes later.

    Near miss in the same thread 11 minutes earlier: after another merge, an awaited task finished at 18:01:25 and the agent's next turn started the same second. The auto-settle sent at 18:01:26 was rejected by the snapshotAt check ("changed before automatic settlement"). So whether the thread settles depends only on whether the agent's turn starts before the settle check runs.

    Written by Claude Opus 5.5 (Claude Code) via t3 triage.

  11. MARCROCK22 commented on Nov 9, 2026

    @MARCROCK22

    Another occurrence on 0.1.7 (Windows x64, desktop app, Claude Code 2.1.321 through the Agent SDK, claude-opus-5-5). The times below are from the CLI's session transcript; we didn't have the server's log at hand.

    • 20:44:37Z: the agent started a background Bash cleanup and called t3_background_wait on it (matched).
    • 20:53:40Z: the agent merged the thread's linked PR, after a watch_pull_request wake for its checks.
    • 20:57:08Z: the agent's last reply; it ended its turn with the cleanup still running.
    • 21:10:54.927Z: the cleanup's task-notification (completed) was recorded.
    • 21:10:58.282Z: the CLI sent the wake turn's API request. No assistant reply was recorded for it.
    • 21:26:36.815Z: a synthetic "No response requested." ("model": "<synthetic>") was written, 3 s before the user's next message, which resumed the session 16 minutes after the wake was lost.

    On resume the model read that synthetic message as its own reply, and told the user it had ignored the notification. We only found the cause in the transcript's model field.

    Three earlier background waits in the same thread, before the PR merged (test runs of 1 to 10 minutes), and the watch_pull_request wake, all woke normally.

  12. juliusmarminge commented on Nov 12, 2026

    @juliusmarminge
    Member

    I tried to reproduce this on the current build and could not.

    Commit 31a108c (origin/main). T3CODE_DEV_SEED=0 vp run dev (fresh DB, default settings, so auto-settle on merge is on). Created a scratch private GitLab project with one open MR, added the local clone as a project (t3 project add), then started real Claude threads with t3 thread start --provider claudeAgent --model <cheapest Claude model> and this prompt: (1) link_pull_request for the MR URL, (2) run glab mr reopen 1; sleep 3; glab mr close 1 in the foreground, (3) start sleep 40 && echo done-waiting with run_in_background, (4) t3_background_wait on that task, (5) end the turn and reply WOKE-AFTER-TASK when woken. Ran 6 threads (the first one used glab mr close only and sleep 90). In each, the MR snapshot was recorded as closed with closedAt after linkedAt and after the user message, so the auto-settle condition held: every thread was auto-settled (thread.settled, actor server:auto-settle) about 2.3 s after its wake turn finished. In all 6 the wake turn ran and replied WOKE-AFTER-TASK. Timings from the provider protocol log and server traces, measured from the empty background_tasks_changed: the CLI's wake init arrived at +30/+65/+75/+79/+88/+127 ms, the wake run was created about 5-20 ms after init, and the first ThreadSettlementServiceV2.sweep ran at +54/+91/+92/+107/+113/+190 ms, after the wake run had attached, so the settle check saw an active run. On this VM the settle sweep never landed inside the window (task_notification to wake init). Reporters' traces show it landing 7-45 ms after the notification, inside that window. The code gap is confirmed by reading: isAutoSettlementCandidate checks only the projected pendingBackgroundTasks (empty by then); thread.settle detaches every live session unconditionally (Orchestrator.ts ~4866); and ClaudeAdapterV2's hasPendingBackgroundWork returns false while the wake buffer holds only the task_notification, which the existing test 'buffers wake output and requests a single continuation run' asserts.

    Closing as not planned. If it still happens for you, reply with the exact steps and the version you are on and it will be looked at again.

  13. sc-frederick commented on Nov 12, 2026

    @sc-frederick

    Note

    🤖 Claude Opus 5.5 responding on behalf of sc-frederick

    Seeing this on 0.1.10-nightly.20261111.4544 (desktop app with its local server, Arch Linux x64, Claude Code 2.1.322 through the Agent SDK provider), and on an earlier nightly from 2026-11-10 and 2026-11-11.

    Steps: link a PR to a Claude thread and merge it. Have the agent start a 2-minute command with run_in_background, call t3_background_wait on its task id, and end the turn.

    On this machine 5 of 75 awaited background tasks never woke the agent, and each of those 5 threads had a merged PR. In each, after the CLI's task_notification and an empty background_tasks_changed, a provider-session.detach from server:auto-settle:<thread> was created 14 to 28 ms later, and query.close followed 21 to 44 ms after the notification. Claude's wake turn normally starts 24 to 52 ms after the notification, so it lost the race. settledAt was backdated to the last run's completion.

    Latest case: task_notification at 04:26:54.013Z; provider thread stored with pendingBackgroundTasks: [] at .014; auto-settle detach at .027; query.close at .037.

    That gap may be why repros failed: it is 10 to 30 ms wide, and on a slower machine the first settle check can land after the wake has attached. #34568 or #32223 may close it; I haven't tested a build with either.

  14. dev-valshin commented on Nov 12, 2026

    @dev-valshin

    Still reproduces on 0.1.9 (self-hosted Linux server, Claude Agent SDK, claude-opus-5-5, GitLab MRs, sidebarAutoSettleOnMerge at default). Twice today on one long-running lead thread, after the agent merged an MR, started a background Bash watcher for the target pipeline, registered it with t3_background_wait (matched), and ended its turn:

    Background task exit (output written) thread.auto-settle dispatched Gap
    16:17:48.521Z 16:17:48.539Z 18 ms
    19:03:05.879Z 19:03:05.905Z 26 ms

    No wake run either time; the thread stayed idle until the user wrote (2 h 24 min the first time). Timings are consistent with the 10–30 ms window described above, which may explain why it did not reproduce on a slower VM. Could this be reopened? #32223 looks like the right fix; happy to test a build with it.

  15. dilbagh commented on Nov 15, 2026

    @dilbagh

    Note

    Claude Opus 5.5 posting on behalf of @dilbagh

    Still reproduces on 0.1.9 (self-hosted Linux arm64 server, 4 cores, Claude Code 2.1.325 via the Agent SDK, claude-opus-5-5, sidebarAutoSettleOnMerge at default). From orchestration_events, the effect outbox and the agent's task output file:

    Time (UTC, 2026-11-15) What happened
    04:25:19 Agent merges the thread's linked PR
    04:25:58 Agent starts a bounded background Bash watcher for the merge's main run
    04:26:00 t3_background_wait {"taskIds":["…"]} → matched
    04:26:02 Turn ends
    04:41:35.956 Watcher exits 0 (task output written)
    04:41:35.983 thread.settled, command server:auto-settle:…, plus provider-session.detached "Thread settled."
    04:54:24 Next run, started only because the user asked why nothing came back

    Gap from task exit to auto-settle: 27 ms. No wake run was created.

    About the repro that closed this: in it, the settle sweep ran 54–190 ms after the empty background_tasks_changed, after the wake run had attached. Here it ran inside that window. The race looks timing-dependent, so a fast dev VM may never hit it. Running the repro under CPU load, or adding an artificial delay before the wake run attaches, should make it show up reliably. #30837 and #31449 both still look needed; could this be reopened?

    Drafted with Claude (Opus 5.5) in T3 Code from this install's event store.

  16. sweepies commented on Nov 15, 2026

    @sweepies

    Note

    🤖 Claude Opus 5.5 (Claude Code, following the t3 triage playbook) posting on behalf of the user

    @juliusmarminge, flagging this since you closed it: the race only shows up on threads whose linked PR has already merged, which may be why it didn't reproduce for you (see the repro at the end).

    Still reproduces on 0.1.9 (self-hosted Linux x64 server in a small k3s pod, used from the web app; Claude Code 2.1.323 through the Agent SDK; claude-opus-5-5; sidebarAutoSettleOnMerge at default). It happened twice today on the same long-running thread. Both times the agent merged the thread's linked PR, started a background gh run watch on the deploy, registered it with t3_background_wait (matched), and ended its turn.

    Second occurrence (UTC 2026-11-15, from the provider event log and server.trace.ndjson):

    Time What happened
    07:11:20 Agent merges the linked PR and triggers the deploy
    07:11:24.399 Background Bash gh run watch starts (local_bash)
    07:11:26.494 t3_background_wait → {"matched":["<task>"],"unmatched":[]}
    07:11:30.146 Turn ends (result success, end_turn)
    07:12:02.026 Task exits 0 (task_updated end_time)
    07:12:02.030 task_notification completed, then background_tasks_changed tasks=[]
    07:12:02.041 ThreadSettlementServiceV2.sweep starts
    07:12:02.050 thread.auto-settle dispatched (server:auto-settle:<thread>:…)
    07:12:02.068–.086 cleanUpSettledThread, then ProviderSessionManager.detach / closeScopeWithin
    07:12:02.083 query.close. No system init for the wake turn ever arrives
    07:12:09 User sends "?" by hand. That is the only reason the thread continued

    First occurrence: at 05:32:27.556 task_notification, then at .649 query.close, with the same server:auto-settle command. The thread then sat idle for 66 minutes until the user wrote.

    On threads with no merged PR on this server, idle task notifications woke the agent every time. In those runs the SDK's system init/status: requesting for the wake turn came 70–80 ms after the empty background_tasks_changed. The settle here took about 50 ms, so it wins whenever the thread's linked PRs are all merged.

    Why, from the v0.1.9 source:

    • ThreadSettlementService.ts processEvent: provider-thread.updated with an empty pendingBackgroundTasks calls enqueueThread right away.
    • isAutoSettlementCandidate checks activityRunStatus, backgroundWorkHoldsCompletion(pendingBackgroundTasks) and threadHasQueuedTurnStart. All three are clear in that gap: the run is finished, the roster is empty, and the queued-turn grace only covers user messages.
    • ClaudeAdapterV2 already tracks wakeEligibleBackgroundTasksByNativeThread, which outlives the empty background_tasks_changed level. Nothing exposes it to the settlement check, so pullRequestSettles (merge at or after the last user-authored message) settles the thread, and the settle detaches the session.

    No commit on main since v0.1.9 that touches ThreadSettlementService.ts or orchestrationV2PendingBackgroundWork.ts seems to address this. #30837 (open, conflicting) looks like the fix. Could this be reopened? The duplicate #33041 was also closed as not reproducible, but it needs a merged PR on the thread to reproduce: background sleep 60 plus t3_background_wait on a thread whose linked PR has already merged, then end the turn.

    Workaround for now: turn off "Auto-settle on merge".

    Produced by Claude Opus 5.5 (claude-opus-5-5) in Claude Code, following the T3 Code triage playbook.

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