Repository navigation
fix(server): subagents no longer stay Running after an account restart stops their session - #334
Merged
Merged
Conversation
…t stops their session The Claude account service stops a thread's provider session between turns (rebalance, mode change, hard limit). Its idle check looked only at the parent turn, so it also stopped sessions whose background subagents were still working, and the session release recorded nothing for them: the subagent rows, the parent's subagent cards and the child's root turn stayed running until the parent got another message (84 minutes on 2026-10-20). - A released provider session now settles the provider-native subagents it leaves open (cancelled), for every release reason except server shutdown, which startup recovery already handles. A cheap subagent-row check first keeps idle releases from paying for the full recovery read. - Rebalance and mode-change restarts now wait for the session's background work, re-checked on the 15 s status poll and capped at 60 minutes. Access-revoked and hard-limit stops are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use Effect.catchTags (t3code/prefer-catch-tags), give the test store's getThreadRecords the projection's subagents, and cover an idle release with no open subagent skipping the full recovery read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tart waits - Skip a subagent whose provider thread the recovery read did not load: it may still run in another shared session. - A completePendingRestart fiber that lost the race no longer leaves a stale background-wait start behind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tusharbhardwaj-bk
approved these changes
Oct 20, 2026
Collaborator
Author
|
Merged as bk-agent-01, pinned to the approved head
Next: I check stagebkt3. Then I open one |
bk-agent-01
added a commit
that referenced
this pull request
Oct 20, 2026
#328's shell-read reader worker is upstream's (loadShellSnapshotParts, readerWorker) on this branch, so its stage-only copies are dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 21, 2026
Collaborator
Author
|
Production check: this change went live through promotion #335 (bkmain |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Claude subagents sometimes show "Working" for more than an hour, and their parent session shows running subagents. The subagents do no work in that time.
On 2026-10-20, "Review skills/docs PR 1135" showed "Working for 1h 24m". Its transcript ends with a model request at 09:21:22 UTC and has nothing more until 10:45. The bkt3 log shows the cause:
ClaudeAccountsService.threadIsIdlechecks only the parent turn, so the account service stopped the process to move the session to another account. This ended both subagents in the middle of their work.ProviderSessionManager.writeReleaseRecordsrecords only the session stop. The subagent rows, the parent's subagent turn items and the child's root node stayedrunning, so the child showed "Working" and the parent showed "2 Working".The same thing happens on every account-service stop path:
rebalance,mode-changed-after-turn(it stopped this fix's own session at 10:52:33 while its background code reader ran) andhard-limit. From 2026-10-13 to 2026-10-20, the account service stopped 124 Claude sessions (80hard-limit, 44rebalance). 29 of these stops hit a session with open subagent rows. At 10:47 UTC, 9 subagent rows in 6 live sessions were stalerunning.PR #301 does not cover this: it handles a subagent end that the live Claude process reports. Here the process is gone, and the server does not read Claude's "background agents didn't finish before the previous session ended" notice on the next start.
Fix
B. A released session settles the subagents it leaves open.
writeReleaseRecords(one marked block inProviderSessionManager.ts) calls the newreleasedSessionSubagents.expbkt3.ts.provider_nativesubagents of the released driver and instance, started at or before the release, ascancelled. It writes existing events only:subagent.updated,turn-item.updatedfor the parent's card, andnode.updatedfor the subagent node. In each child thread, it also cancels the runless root turn and its open items, and it follows nested children.server_shutdown, because startup recovery and its restart wake handle that case. A plain detach settles nothing.orchestration-v2.provider-session-release-subagents-failed, and startup recovery stays the fallback.A. Optional restarts wait for background work.
ForkProviderSessions.hasLiveBackgroundWorkasks each live session of the thread for the adapter'shasPendingBackgroundWork. A failed check counts as "work pending".threadIsIdle(rebalance) now also requires no live background work, so a rebalance skips that thread.completePendingRestartdefer while work runs. The 15 s status poll (refreshStatus→recheckBackgroundWaits) checks them again, because a subagent end gives no turn event. AfterBACKGROUND_WORK_RESTART_CAP_MS(60 min), the restart runs anyway, and fix B cleans up.No new event types, schema changes or migrations. The fork-marker check passes.
How I tested
This host runs no tests (the dev-server compute policy). CI runs the checks below on head
ffa176f511. After the merge, I check the change on stagebkt3.ProviderSessionManager.releasedSubagents.expbkt3.test.ts:app_ownedone, another driver, and a finished one.server_shutdownis skipped. A failed read does not fail the release.ClaudeAccountsService.test.ts:claude.account.restart-deferred {waitingFor: 'background-work'}andorchestration-v2.provider-session-release-subagents-cancelledin the log, and for subagent rows that stayrunningwith no update.Review
A fresh-context review of the diff found no P0 or P1 findings. Two P2 findings are fixed in
ffa176f511: a subagent whose provider thread was not loaded is no longer cancelled, and a race incompletePendingRestartno longer leaves a stale wait start. These P2 findings stay open as follow-ups:🤖 Generated with Claude Code