Repository navigation
fix(server): Stop reaches background work after a run fails before its provider starts - #15474
vitalyiegorov wants to merge 1 commit into
Conversation
…s provider starts When the newest run failed before its provider started, it had no provider turn, so run.interrupt rejected it as not interruptible. Stop then could not end the background work the thread still showed. The interrupt now falls back to the provider thread's latest turn, whose session owns that work. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a focused server-side bug fix that corrects provider-turn selection for stopping background work after a pre-provider failure, while preserving existing behavior in other cases. It touches no schemas, defaults, infrastructure, sensitive areas, or static-analysis configuration. You can add or adjust custom eligibility rules. Learn more. |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 🧰 Additional context used📚 Code guidelines (1)No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (2)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review. 📝 WalkthroughWalkthroughWhen a run fails before its provider starts, ChangesBackground work interruption
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~12 minutes Change: Bug fix · Severity of issue fixed: Medium Suggested reviewers: Merge Risk: ⚪ Minimal · up to The failed-run Stop path can reach background work from an earlier turn. No issue requiring a change before merge was identified. Architecture SummaryArchitecture risk: 🟡 Medium · up to The change affects 1 system. Changed systems: Architecture concerns Review detailsSystems and components
Before / after behavior
Reliability and maintainability
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Problem
Fixes #15472. After a turn leaves background work running, a message that fails before its provider starts becomes the newest run, with no provider turn. Stop then targets that run. The client sends the newest run because the server only reaches background work through it.
dispatchRunInterruptfinds no provider turn for that run's attempt and rejects it withRun … is not interruptible.The work keeps running and the thread is stuck until it ends on its own.Change
apps/server/src/orchestration-v2/Orchestrator.ts: when the run being stopped has background work but no provider turn of its own, the interrupt uses the provider thread's latest turn.That reuses the existing settled-turn path.
ProviderTurnControlServicesendsrequestRuntimeRestart, Claude closes the CLI process for the native thread, and the settle follow-up ends what's left. Background work on other provider threads is still reached by the existing loop.The fallback only applies when
hasBackgroundWorkis true, which requires the newest run to be settled. Stop on a preparing or running run is unchanged. The client already sends the right run, so this is a server-only change.Scope and approval
A focused fix for #15472, which I filed with the reproduction and screenshot. It waits on triage, like any bug PR. It adds a fallback inside one handler, with no contract or client changes. #15013 tracks V2 interrupt hardening and doesn't list this case.
Verification
BackgroundWorkStop.integration.test.ts: the stopped run is now a newer run that failed before its provider started. Stop must still reach both provider threads and interrupt all three pending items. Onmainthe test fails withRun run:5 is not interruptible., the exact error from the report. Here it passes.apps/servertest file that dispatchesrun.interruptor covers interrupts:BackgroundWorkStop,CodexAdapterV2,ThreadManagementService,runtimeLayer,OrchestratorMcpService,OrchestratorMcpToolkit,Orchestrator.control-reads. 220 passed and 8 were skipped (live OpenCode).apps/servertypecheck passes. Lint and fmt pass on the touched files; the one lint warning, an unusedlayerUnavailable, is already onmain.Implemented with Claude Opus 5.5 in T3 Code (Claude Code harness).
🤖 Generated with Claude Code