Repository navigation
Keep running chats safe during managed server updates - #28978
brennanb2025 wants to merge 32 commits into
Conversation
|
The problem: managed SSH and WSL servers could restart for an update in the middle of a chat turn, even with no terminals open. Update safety counted only terminals, so it didn't see chat work that was still running, and losing contact with the server could still count as permission to stop it. What changes for users: the server that would restart now reserves and commits its own restart. Automatic updates wait while chats still have work to do, and losing contact never authorizes stopping a chat. Older servers that can't check for running chats keep the explicit Force update action, and every Force button warns that it can interrupt a chat. Retry text asks the user to update or reconnect once the work is done, instead of promising a retry that is never scheduled. Fixed in review (two rounds, plus a three-model design panel after round 1):
Deferred (not caused by this PR, owned separately): the WSL host row can keep showing "Update … deferred." after an update applies, because the renderer's WSL host store ignores a status change when only the deferred update changed. Turning off auto-naming on the desktop doesn't stop WSL-hosted chats from running their own naming call. Final head: Third main merge ( Fourth main merge ( New in this round: an explicit "stop now" request ( What was verified:
What was not verified:
For Brennan's review:
Earlier rounds (through Second main merge ( Later main merges ( Status: review loop done on the final head, CI green, QA done (R1 proven in CI against real servers; its interrupted-update setup is simulated, as described above). |
|
Windows QA for head 66c0c8c (Windows high spec, real signed-in Claude Code 2.1.302 inside a throwaway WSL2 distro, Codex driving the UI over CDP) Final head 65f151a = QA'd head 66c0c8c plus a main merge (and one test updated to main's helper-work reporting); CI green on it
Side notes (not this PR's change, but it shows up in this PR's row): after Force update or Update, the host row keeps saying "Update to … deferred." even after navigating away and back, although the host status no longer has a deferred update. The renderer's WSL host store ignores a status update when only the deferred update changed. Also, turning auto-name chats off on the desktop does not stop chats on a WSL host from running a separate Claude naming call inside the distro. Same chat continuing after Force update: Running-chat deferral row on a current server: Final head |
# Conflicts: # src/main/managed-server/activation/orcad-activation-host-test-harness.ts # src/main/native-chat/agent-session-wire/structured-agent-session-host.ts # src/main/ssh/orcad-remote-deploy.ts # src/main/ssh/orcad-runtime-maintenance.test.ts # src/main/ssh/orcad-runtime-maintenance.ts # src/main/ssh/orcad-terminal-census-client.ts # src/main/ssh/orcad-transaction-incumbent.ts # src/main/wsl/wsl-orcad-incumbent.test.ts # src/shared/rpc-contract/rpc-params-catalog.generated.ts
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to
|
# Conflicts: # src/main/native-chat/agent-session-wire/structured-agent-session-conversation-lifetime.ts # src/main/native-chat/agent-session-wire/structured-agent-session-host.ts # src/main/runtime/rpc/methods/structured-agent-session-adoption-replay.test.ts
# Conflicts: # src/main/ssh/orcad-remote-deploy.test.ts
Main's room tests deployed over a serving incumbent with a census that has no chat work count and no restart admission, so the update deferred before the room probe ran. Give them the same idle census and slot admission as the other activation tests, and pin the probe before the reservation instead of before the recount it replaced.
# Conflicts: # src/main/native-chat/agent-session-wire/structured-agent-session-attach-orchestration.ts # src/main/native-chat/agent-session-wire/structured-agent-session-host.ts
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
3b582f44-e6c3-4a9c-a8e3-2fd8f044cb9e
⛔ Files ignored due to path filters: 1
src/shared/rpc-contract/rpc-params-catalog.generated.tsis excluded by!**/*.generated.*
📒 Files selected for processing: 58
config/scripts/orcad-daemon-protocol-crossing.test.mjssrc/cli/command-scoped-flag-help.tssrc/cli/specs/managed-server.tssrc/main/daemon/daemon-pty-session-spawn.tssrc/main/managed-server/activation/orcad-activation-crash-recovery.test.tssrc/main/managed-server/activation/orcad-activation-host-test-harness.tssrc/main/managed-server/activation/orcad-activation-readiness-fixture.tssrc/main/managed-server/host-state/orcad-state-mutation-timeout.test.tssrc/main/managed-server/lifecycle/orcad-managed-auto-update.tssrc/main/managed-server/lifecycle/orcad-managed-runtime-context.tssrc/main/native-chat/agent-session-wire/structured-agent-session-attach-orchestration.tssrc/main/native-chat/agent-session-wire/structured-agent-session-conversation-lifetime.tssrc/main/native-chat/agent-session-wire/structured-agent-session-create.tssrc/main/native-chat/agent-session-wire/structured-agent-session-entry-delegates.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host.tssrc/main/native-chat/agent-session-wire/structured-agent-session-idle-sweep.test.tssrc/main/native-chat/agent-session-wire/structured-agent-session-idle-sweep.tssrc/main/native-chat/agent-session-wire/structured-agent-session-mutation-admission.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-admission.tssrc/main/native-chat/agent-session-wire/structured-agent-session-task-queue.tssrc/main/orcad/orcad-entry.tssrc/main/orcad/orcad-restart-admission.test.tssrc/main/orcad/orcad-restart-admission.tssrc/main/orcad/orcad-restart-work-admission.tssrc/main/orcad/orcad-stop-request-listener.test.tssrc/main/orcad/orcad-stop-request-listener.tssrc/main/orcad/orcad-terminal-census.test.tssrc/main/orcad/orcad-terminal-census.tssrc/main/providers/local-pty-provider.tssrc/main/runtime/rpc/methods/orcad-terminal-census.tssrc/main/ssh/orcad-installed-activation.tssrc/main/ssh/orcad-remote-deploy.test.tssrc/main/ssh/orcad-remote-deploy.tssrc/main/ssh/orcad-restart-admission-activation.test.tssrc/main/ssh/orcad-restart-admission-client.test.tssrc/main/ssh/orcad-restart-admission-client.tssrc/main/ssh/orcad-runtime-maintenance.test.tssrc/main/ssh/orcad-runtime-maintenance.tssrc/main/ssh/orcad-snapshot-room.test.tssrc/main/ssh/orcad-terminal-census-client.test.tssrc/main/ssh/orcad-terminal-census-client.tssrc/main/ssh/orcad-transaction-incumbent.tssrc/main/ssh/orcad-update-plan.test.tssrc/main/ssh/orcad-update-plan.tssrc/main/wsl/wsl-orcad-deploy.test.tssrc/main/wsl/wsl-orcad-deploy.tssrc/main/wsl/wsl-orcad-incumbent.test.tssrc/main/wsl/wsl-orcad-incumbent.tssrc/main/wsl/wsl-orcad-real-distro-lane.test.tssrc/renderer/src/components/settings/ManagedServerRow.test.tsxsrc/renderer/src/components/settings/ManagedServerRow.tsxsrc/renderer/src/components/settings/WslHostsSection.tsxsrc/renderer/src/components/settings/managed-server-copy.test.tssrc/renderer/src/components/settings/managed-server-copy.tssrc/renderer/src/i18n/locales/en.jsonsrc/shared/orcad-restart-admission.tssrc/shared/orcad-runtime-capabilities.tssrc/shared/orcad-terminal-census.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.
…onversation is closed The restart check counted a start only while its conversation stayed open, so an idle close during a stalled start let a managed update through. Every tracked attach, create, start and open now counts as restart work in the same tracker that counts the session queue.
# Conflicts: # src/main/managed-server/activation/orcad-activation-crash-recovery.test.ts # src/main/managed-server/host-state/orcad-state-mutation-timeout.test.ts # src/main/ssh/orcad-installed-activation.ts # src/main/ssh/orcad-remote-deploy.test.ts # src/main/ssh/orcad-remote-deploy.ts # src/main/ssh/orcad-runtime-maintenance.ts # src/main/ssh/orcad-snapshot-room.test.ts # src/main/wsl/wsl-orcad-deploy.ts # src/main/wsl/wsl-orcad-incumbent.test.ts # src/main/wsl/wsl-orcad-incumbent.ts
…mit once formatted Main's copy sat at 400 lines only because one line was left unformatted; the merge's formatter pushed it to 401. Inlining the one-use question list keeps it at 400 with identical behavior.
…lient's empty request waits for idle Stopping a slot and restarting it for an older client's update were both an empty .orcad-stop-request file, so routing that file through restart admission let a crash recovery, stranded-setup release or rejected-candidate rollback leave the server running. New clients now write "stop-now" into the request (renamed in whole), which stops at once as before; an empty or unrecognized request takes the chat-safe restart, and a deferred restart logs why. Also gives the restart admission activation fixtures the now-required recount.
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
0ef76e9d-44a4-4afa-ae18-828d46dab827
⛔ Files ignored due to path filters: 1
src/shared/rpc-contract/rpc-params-catalog.generated.tsis excluded by!**/*.generated.*
📒 Files selected for processing: 30
src/main/managed-server/activation/orcad-activation-crash-recovery.test.tssrc/main/managed-server/host-state/orcad-state-mutation-timeout.test.tssrc/main/managed-server/host-state/orcad-windows-host-script.tssrc/main/managed-server/install/orcad-remote-process-control.tssrc/main/managed-server/install/orcad-remote-shell-commands.integration.test.tssrc/main/managed-server/install/orcad-remote-windows-scripts.test.tssrc/main/managed-server/lifecycle/orcad-managed-runtime-context.tssrc/main/native-chat/agent-session-wire/structured-agent-session-host.tssrc/main/native-chat/agent-session-wire/structured-agent-session-restart-admission.tssrc/main/orcad/orcad-restart-admission.test.tssrc/main/orcad/orcad-restart-admission.tssrc/main/orcad/orcad-restart-work-admission.tssrc/main/orcad/orcad-stop-request-listener.test.tssrc/main/orcad/orcad-stop-request-listener.tssrc/main/orcad/orcad-terminal-census.tssrc/main/runtime/rpc/methods/orcad-terminal-census.tssrc/main/ssh/orcad-installed-activation.tssrc/main/ssh/orcad-remote-deploy.test.tssrc/main/ssh/orcad-remote-deploy.tssrc/main/ssh/orcad-restart-admission-activation.test.tssrc/main/ssh/orcad-runtime-maintenance.tssrc/main/ssh/orcad-snapshot-room.test.tssrc/main/ssh/orcad-transaction-incumbent.tssrc/main/wsl/wsl-orcad-deploy.tssrc/main/wsl/wsl-orcad-incumbent.test.tssrc/main/wsl/wsl-orcad-incumbent.tssrc/renderer/src/i18n/locales/en.jsonsrc/shared/orcad-restart-admission.tssrc/shared/orcad-runtime-capabilities.tssrc/shared/orcad-stop-request.ts
🚧 Files skipped from review as they are similar to previous changes: 1
- src/renderer/src/i18n/locales/en.json
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.
… holds the new file Renaming the just-written stop-now request can briefly fail with EPERM, EACCES or EBUSY on Windows; the stop now retries those with the same bounded delays as record-publish instead of answering SIGNAL_FAILED and leaving the server up.
# Conflicts: # src/renderer/src/components/settings/ManagedServerRow.tsx # src/renderer/src/components/settings/WslHostsSection.tsx # src/renderer/src/i18n/locales/en.json







ELI5
A managed Orca server could restart during a running native chat when an automatic update found no open terminals. Counting terminals separately from accepting chat work left a gap where the update could interrupt a turn.
Automatic SSH and WSL server updates now defer while chats have work left, and the serving server stays usable. Once that work finishes, choose Update or reconnect to retry; a deferral does not schedule a retry.
What Changed
The serving host derives outstanding work from existing provider lifetime rules: running turns, unanswered prompts, queued sends, orchestration workers and background work. It releases idle providers through their existing stop path with a five-second deadline, then reserves a restart for at most thirty seconds. No busy flag is saved.
The updater writes its recovery journal before asking the host to commit. The host checks current work and closes admission for new work synchronously before normal shutdown. New work cancels an uncommitted reservation. The updater requires confirmed exit before taking a snapshot; an expired reservation or lost answer never authorizes an external stop of a server that supports this check.
Already-installed older SSH and WSL servers cannot prove that chats are idle, so they need one manual Force update to install this protection. Settings offers the older-server SSH action as well as the existing WSL actions, with a warning that Force stops running chats on those older servers. Finish chats first; an interrupted chat can be continued after the update. CLI help explains the same consequence. On servers that can check chat work, Force still cannot override unfinished chats.
New servers protect older desktops' slot-file update requests through the same admission check. Newer desktops write
stop-nowinto the slot stop file when they stop a server for recovery: crash recovery of an interrupted update, release of a stranded setup, and Windows rollback of a rejected new version. That request still stops the server at once. Only an empty or unrecognized request waits for chats to be idle, and a request that waits logs why. Explicit instance-bound Stop/Forget and operating-system stop signals keep their existing behavior. Terminal daemon preservation, protocol compatibility checks and protection for terminals running inside the server remain in place.Why
The host that owns the providers must own the restart decision. Another client-side count leaves a gap between counting and accepting work. Reusing provider lifetime rules gives updates the existing definition of outstanding work without storing a second busy state.
Intended differences from the common pattern: Orca defers automatic managed updates over outstanding work, and independently updated remote hosts use bounded restart reservations. Explicit older-server upgrades retain the existing stop-and-continue behavior after repeated successful proof that the host lacks restart admission. Lost contact never proves that a server is old or idle. Orca uses the existing inline warning and Force action rather than a new dialog. Automatic update defaults, explicit Stop/Forget and operating-system signals are unchanged.
Linked Issue
Follow-up to #28458 and #26473.
Visual Proof
Pending coordinator-owned final-head Windows/WSL and SSH QA, with before/after screenshots. Settings now exposes the missing older-server SSH action and warns about older-server chat interruption on every Force path.
Testing
ba7c4527402.ba7c4527402648523a8e2db2a1e93259794f0555; CI runs tests, full lint and typecheck.The staged hook unexpectedly caused pnpm to populate dependencies and run package postinstall steps before checking files; its incidental lockfile changes were reverted. No standalone local checks or builds were requested.
Review
Review corrections restore the missing older-server SSH upgrade, disclose the older-server chat interruption on terminal and policy Force paths, and replace an unscheduled automatic-retry promise with an explicit retry/reconnect instruction. Fresh correction review and final readiness remain pending.
Files touched along Neil's update path:
src/shared/orcad-terminal-census.ts,src/main/orcad/orcad-terminal-census.ts,src/main/runtime/rpc/methods/orcad-terminal-census.ts; the SSH filesorcad-installed-activation.ts,orcad-transaction-incumbent.ts,orcad-update-plan.ts,orcad-remote-deploy.ts,orcad-terminal-census-client.ts,orcad-managed-runtime-context.ts,orcad-runtime-maintenance.tsandorcad-managed-auto-update.ts; and the WSL fileswsl-orcad-incumbent.tsandwsl-orcad-deploy.ts, with their affected tests and activation fixtures. No mover internals changed.Agent skill upstream boundary
Notes
SSH and WSL use the same host admission contract; WSL opens a short bridge for each request. Optional census fields and an advertised capability preserve communication with older peers. Folder workspaces use the same provider/session checks as git worktrees. Very old clients that unconditionally send an operating-system stop signal cannot be distinguished from an explicit stop.
Accepted limitation (older desktops only): an older desktop writes the same empty slot stop file for a recovery stop as for an update, so a newer server can't tell them apart and both wait for idle chats. As a result, an older desktop releasing a stranded setup on a newer server can release its lock while that server keeps running. Newer desktops are not affected. The update path that still writes the slot file for a stop (Force on a host proven to lack restart admission) only reaches older servers, and those ignore the file's contents. When an older desktop updates a newer server while a chat is running, the server keeps serving. The older desktop then reports the server as still running and keeps its update lock until the chat finishes. That is the intended older-desktop experience: the chat is never cut off.
Checklist