Repository navigation
fix(server): Grok hand-off turns settle after the worktree changes - #35390
juliusmarminge wants to merge 3 commits into
Conversation
Reproduces #35274: interruptTurn forks its transition into a closed session scope, the fiber never starts, the transition permit leaks, and the next interrupt waits forever. AI-assisted; verified with the tests and tools listed above.
AcpAdapterV2.interruptTurn forked its transition into the session scope. After a worktree hand-off detaches the session, that scope is closed, so the fork never started, the transition permit leaked, and the ingestion cleanup's interrupt waited on it forever, leaving the run running. Fork detached when the session scope is already closed. Fixes #35274 AI-assisted; verified with the tests and tools listed above.
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — The change lets interrupt cleanup finish after a session scope closes, preventing a leaked permit from leaving hand-off turns stuck. Normal open-session behavior and existing teardown safeguards remain unchanged. No code changes detected at You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Other scenariosAll 64 scenario measurements match All 64 scenario measurements
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
|
The automated pipeline stopped on this pull request and will not merge it: the capture step could not show the problem on the base commit, so there is nothing to prove fixed. On head: enabled Grok, added a fresh project, started Handoff proof with 'Reply ready.' and observed completion. Sent 'Call the t3_worktree_handoff MCP tool now to move this thread to a new worktree on a new branch named handoff-proof. Do not pass a continuationPrompt. Do not run other tools.' The worktree was bound, but the turn failed with 'The provider event stream closed unexpectedly' and retained a Waiting handoff row. Sent 'In the new worktree, reply follow-up complete.'; it failed to open the provider session, while the stale Waiting row remained. On base: the initial 'Reply ready.' turn and retries failed to open the provider session because the configured authentication method was not advertised, preventing the handoff reproduction. Reviewed both recordings and the head screenshot before uploading. Stopped both servers and removed both worktrees and scratch files. It stays open for a person to finish or close. |
|
Note 🤖 Claude Opus 5.5 responding on behalf of leonhoulier I ran the live Grok repro this PR still needs. The hang from #35274 no longer reproduces on current Setup: macOS, Grok CLI 1.0.77,
Two other runs don't count. On Why it no longer hangs, as far as I can tell: the traces on both servers contain no The adapter bug itself is still on |
AcpAdapterV2.interruptTurn takes runtimeTransitionPermit and runs its transition in a fiber forked with Effect.forkIn(sessionScope, ...), releasing the permit via Effect.ensuring inside that fiber. After a worktree hand-off, ProviderSessionManager.detach has already closed the session scope; Effect's forkIn then returns an unstarted, already-interrupted fiber, so the ensuring/release never runs. The first interrupt exits Interrupted and the permit leaks; the ingestion-failure cleanup's second interruptTurn blocks forever on the permit, so the failed terminal is never written and the run stays running with later messages queued. The fix forks the transition with Effect.forkDetach (same startImmediately/uninterruptible options) when sessionScope.state is already Closed, so the transition actually runs and releases the permit; with an open scope it still forks into the session scope as before. No regex or parser added. The live Grok repro was not rerun; the fix is shown by the unit test.
Fixes #35274
Reproduction on main
Commit fd8e386 (origin/main). Isolated dev server:
T3CODE_DEV_SEED=0 vp run devin a fresh worktree. Enabled the grok provider instance in the worktree's settings.json, added a fresh one-commit git repo witht3 project add, rant3 thread start --provider grok --model grok-4.6 --wait(turn 1 completed, reply 'ready'), thent3 thread send <thread> "Call the t3_worktree_handoff MCP tool now... Do not pass a continuationPrompt...". Server trace: mcp.tool.t3_worktree_handoff Success (589 ms); AcpAdapterV2.interruptTurn exit Interrupted ('All fibers interrupted without error', 16 ms) inside ProviderSessionManager.detach (Success); then WARN 'orchestration V2 provider event ingestion failed' with ProviderAdapterEventStreamError -> 'Workspace changed.'. The second AcpAdapterV2.interruptTurn span (from the ingestion-failure cleanup) never ended, and 'failed to interrupt turn after ingestion failure' was never logged.t3 thread showreported the threadrunningwith the hand-off worktree bound; a follow-upt3 thread sendreturnedQueued.Still running more than a minute later. Deviations: model grok-4.6 (grok-4.7-build-fast isn't on this machine's model list), and a local, uncommitted change skipping AcpSessionRuntime's 'did not advertise configured authentication method' check, because this machine's Grok 1.0.77 with XAI_API_KEY advertises onlygrok.comauth (it does acceptxai.api_key). Failing test: AcpAdapterV2.test.ts 'settles interrupts that arrive after the session scope has closed' fails on main with 'an interrupt nobody cancelled must not exit as interrupted'. It passes with a scratch change that forks the transition detached instead of into the closed sessionScope; that change was reverted and not committed.Evidence
Being captured: before and after in the real app. This section is filled in before the pull request can merge.
Tests
vp test run src/orchestration-v2/Adapters/AcpAdapterV2.test.ts -t "after the session scope has closed" (apps/server): passes with the fix, fails without it ('an interrupt nobody cancelled must not exit as interrupted'). vp test run src/orchestration-v2/Adapters/AcpAdapterV2.test.ts: 105/105 passed. vp run check:changed: format, lint, knip, graphql, typecheck (14 packages), tests (2 files) all pass on the second run; the first run failed only on format, fixed with vp fmt.
Not in this change
AI-assisted; verified with the tests and tools listed above.