fix(server): settle no longer leaves monitors and dev servers running - #5774
Conversation
Settling a thread now stops its idle provider session the same way archive does, so PR watch loops and background dev servers die when you mark the thread done instead of running on for hours and waking the thread back up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
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. |
Review follow-up: the pre-stop projection read stays best-effort, but a failed read now leaves a warning instead of silently skipping the stop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ApprovabilityVerdict: Approved 4a614a9 This is a straightforward bug fix extending existing archive cleanup logic to also work for settle commands. The changes follow established patterns, include defensive race-condition handling, and are well-tested. You can customize Macroscope's approvability policy. Learn more. |
Review follow-up: the settle-originated session stop is now conditional (onlyIfSettled) and decided in the decider against the serialized read model, so a turn started between the settle and the stop survives. Archive stops stay unconditional. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
## What's Changed * chore: vouch gfsaaser24 by @t3dotgg in pingdotgg/t3code#5761 * chore: vouch saphid by @t3dotgg in pingdotgg/t3code#5763 * fix(server): stop Codex threads with queued follow-ups by @t3dotgg in pingdotgg/t3code#5762 * fix(web): usage page loses the cost quality panel, gains a back button by @t3dotgg in pingdotgg/t3code#5756 * feat(server): agents can now open the images you paste into chat by @t3dotgg in pingdotgg/t3code#5757 * fix(web): pinned reorder no longer reshuffles while writes land by @t3dotgg in pingdotgg/t3code#5767 * feat(web): overhaul project settings into a real settings page by @t3dotgg in pingdotgg/t3code#5768 * fix(web): usage totals no longer jump while devices report in by @t3dotgg in pingdotgg/t3code#5772 * fix(server): settle no longer leaves monitors and dev servers running by @t3dotgg in pingdotgg/t3code#5774 * feat: pick worktree or current checkout per project by @t3dotgg in pingdotgg/t3code#5766 * fix(web): sidebar rows show the branch again, not a truncated plan step by @t3dotgg in pingdotgg/t3code#5776 * feat(server): vp run migrate-dev-db seeds worktree dev dbs with real data by @t3dotgg in pingdotgg/t3code#5773 * feat(web): keep unsent drafts one click away in the sidebar by @t3dotgg in pingdotgg/t3code#5777 **Full Changelog**: pingdotgg/t3code@v0.0.33-nightly.20260809.1039...v0.0.33-nightly.20260809.1040 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.33-nightly.20260809.1040
Settling a thread means "I'm done with this", but the provider session kept running its background work. An audit of real usage found settled threads with PR monitors that ran 4 more hours (then woke the thread at 3am via
reason: activity) and dev servers that burned ports and RAM for 13+ hours.Settle now mirrors archive: after the command lands, the server dispatches
thread.session.stopif the thread has a live session. That takes down everything inside the provider process — monitors, background shells, subagent fleets.Details worth knowing:
starting/runningsession, so this only ever stops idle sessions between turns.stoppedsession-set does not count as session activity, so the stop cannot un-settle the thread it follows.Not covered here: processes an agent detach-spawns with
nohup/setsidescape the provider process tree entirely. That needs process-group/cgroup ownership and is a separate change.Tests: two new
server.test.tscases (settle with live session stops it without closing terminals; settle with no session dispatches nothing extra). Existing archive hook tests all pass.Built by Claude Fable 5 running in Claude Code.
Note
Medium Risk
Changes thread lifecycle and when provider sessions stop, including a new race-sensitive decider path; behavior is guarded by
onlyIfSettledand covered by new tests.Overview
Settle now tears down idle provider sessions (monitors, dev servers, background work) by dispatching a follow-up
thread.session.stopafterthread.settlelands, using the same post-command hook as archive when the thread still has a non-stopped session. Terminals stay open on settle—only archive continues to close terminal panes.Settle cleanup stops are conditional:
thread.session.stopgains optionalonlyIfSettled, and the decider rejects that stop if the thread was unsettled, the session is starting/running, or a queued turn start appeared before the stop is decided—so a quick re-engage after settle does not kill the new session. Archive-driven stops remain unconditional.The WS layer shares one “parking” path for archive and settle, logs a warning when the pre-stop session snapshot read fails (instead of silently skipping), and adds integration tests for settle-with-session vs no-session.
Reviewed by Cursor Bugbot for commit 4a614a9. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix
thread.settleto stop sessions conditionally without closing terminalsthread.settlevia the WS RPC now triggers a follow-upthread.session.stop(withonlyIfSettled=true) when the thread has a non-stopped session, replacing the previous behavior that also closed terminals.onlyIfSettledboolean field to thethread.session.stopcommand contract; when set, the stop is rejected withOrchestrationCommandInvariantErrorif the thread has been re-engaged (session starting/running, or a queued turn start exists).thread.archive, notthread.settle.thread.settleno longer closes dev server terminals or monitors as a side effect.Macroscope summarized 4a614a9.