Repository navigation
fix(app): keep sandbox tabs through a restart, and stop the freeze it caused - #247
Merged
Merged
Conversation
Mounting a new folder on a sandbox that had one of its sessions open froze the whole renderer: no clicks, no typing, force quit the only way out. Applying a mount has no hot path on macOS, so the sandbox restarts, and a sandbox is published as a connection only while it is ready — it leaves server.list for the second or two it takes. Two effects then disagree: the tab store prunes tabs whose server is not in the list, and the titlebar adds a tab back for whatever session the route names. Prune, re-add, prune, about a thousand rounds a second. The loop is synchronous, so the renderer never returns to the event loop and never processes the IPC event that would put the sandbox back and end it. The titlebar effect now skips servers that are not connected. The route is left alone, so the tab comes back on its own once the sandbox does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A sandbox is a connection only while it is ready, so restarting one — to apply a folder you just mounted, or because you stopped and started it — takes it out of server.list for a second or two. The tab store reconciles against that list, read every restart as "this server is gone", and deleted every tab belonging to the sandbox along with each tab's memory: the typed prompt, the terminal, where you were scrolled. Tabs now belong to a sandbox for as long as the sandbox exists rather than as long as it answers. The desktop renderer passes every configured sandbox as retainedServers, the server context exposes it as `retained`, and both of the tab store's prune effects reconcile against list plus retained. Deleting a sandbox is unaffected: dialog-select-server already removes its tabs explicitly, and the sandbox then leaves retained as well. The route is the other half. A retained server has no connection, and mounting the SDK and sync providers with undefined sends the session's requests to whichever server happens to be selected — which answered "this session cannot be found" about a perfectly healthy session, and bounced the route home through a burst of ~250 navigations when a tab was opened while its sandbox was stopped. TargetServerRoute now renders a "Waiting for this server" panel instead, and swaps back to the session by itself the moment the sandbox answers again. Verified end to end against a real vz sandbox: mounting a folder with a session open keeps the tab, shows the waiting panel for ~1.2s, and returns to the session with no interaction. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Mounting a new folder on a sandbox that had one of its sessions open froze the
window: no clicks, no typing, force quit the only way out. Fixing that exposed
the behaviour underneath it — a sandbox restart threw away every tab it owned —
so this does both.
The freeze
Applying a mount has no hot path on macOS, so the guest restarts, and a sandbox
is published as a connection only while it is ready: it leaves
server.listforthe second or two the restart takes. Two effects then disagree about the same
tab —
context/tabs.tsxprunes tabs whose server is not in the list, and thetitlebar adds one back for whatever session the route names. Prune, re-add,
prune, about a thousand rounds a second. The loop is synchronous, so the
renderer never returns to the event loop and never processes the IPC event that
would put the sandbox back and end it, which is why it never recovered on its
own. Any sandbox restart could trigger it, not only mounting a folder.
The titlebar effect now skips servers that are not connected.
Tabs that survive the restart
Tabs belonged to a sandbox for as long as it answered. They now belong to it
for as long as it exists, so a restart no longer closes them or discards each
tab's memory — the prompt you had typed, your terminal, your scroll position.
The renderer passes every configured sandbox as
retainedServers, the servercontext exposes it as
retained, and both prune effects reconcile againstlistplusretained. Deleting a sandbox still clears its tabs:dialog-select-serverremoves them explicitly, and the sandbox leavesretainedat the same time.The route is the other half. A retained server has no connection, and mounting
the SDK and sync providers with
undefinedsends the session's requests towhichever server happens to be selected — which answered "this session cannot be
found" about a healthy session, and bounced the route home through a burst of
~250 navigations when a tab was opened while its sandbox was stopped.
TargetServerRoutenow renders a Waiting for this server panel instead, andswaps back to the session by itself once the sandbox answers.
WSL servers are deliberately left as they are: same latent problem, no
equivalent restart in normal use.
Verification
Driven against a real vz sandbox in the dev app (CDP into the renderer, the
sandbox IPC channel for the mount change):
list oscillating and the command catalog effect re-running ~1000×/s, matching
the
renderer unresponsivestack samples from the original report.tab never leaves the strip, the view shows the waiting panel for ~1.2 s and
returns to the session on its own.
longer bounces home; starting the sandbox swaps it back with no interaction.
bun typecheckclean inpackages/appandpackages/desktop; app (675),browser (69) and desktop (97) tests pass.
DIVERGENCES.mdgets a row perchange and
CHANGELOG.mdan entry for each.🤖 Generated with Claude Code