Skip to content

fix(sandbox): scope user-driven SANDBOX_START to the locked provider kind#4478

Open
pedrofrxncx wants to merge 1 commit into
mainfrom
fix/sandbox-start-locked-provider-kind
Open

fix(sandbox): scope user-driven SANDBOX_START to the locked provider kind#4478
pedrofrxncx wants to merge 1 commit into
mainfrom
fix/sandbox-start-locked-provider-kind

Conversation

@pedrofrxncx

@pedrofrxncx pedrofrxncx commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Source

Bug found reading sandbox-lifecycle-context.tsx (high-churn file this run).

What's wrong

SandboxLifecycleProvider receives a sandboxProviderKind prop specifically so "entry selection and SANDBOX_START are scoped to this kind [and] the preview never silently shows a different-provider sibling" (per the prop's own doc comment). Commit #4025 wired this through for the auto-start and self-heal effects, but the user-driven start() action — which retry() and resume() also call — built its SANDBOX_START args without sandboxProviderKind.

Failure scenario: a thread is locked to sandboxProviderKind: "user-desktop". That sandbox fails to start (errored state, no previewUrl yet, no branchMap entry recorded). The user clicks Retry. retry()start() calls SANDBOX_START with no sandboxProviderKind, so the server falls back to its link-or-env default provider policy instead of honoring the lock — the sandbox can come up on agent-sandbox instead, exactly the "different-provider sibling" the surrounding code says should never happen.

Fix

Extracted the SANDBOX_START arg-building into one pure, exported helper (buildSandboxStartArgs) matching the existing tested-pure-helper pattern already used in this file (shouldAutoStart, shouldSelfHeal, computeDrawerStatus), and reused it at all three call sites (auto-start effect, self-heal effect, user start()). Added a regression test asserting the built args include sandboxProviderKind when the thread has a locked kind.

To verify

bun test apps/mesh/src/web/components/sandbox/hooks/sandbox-lifecycle-context.test.ts

Checks run locally

  • bun run fmt
  • bunx tsc --noEmit in apps/mesh (no new errors)
  • bun test apps/mesh/src/web/components/sandbox/hooks/sandbox-lifecycle-context.test.ts (24 pass)

Full CI will validate the rest.


Summary by cubic

Scopes user-driven SANDBOX_START to the thread’s locked provider to prevent starting on a different provider.

  • Bug Fixes
    • Extracted buildSandboxStartArgs and used in auto-start, self-heal, and user start() so all calls include sandboxProviderKind when locked.
    • Added regression tests for the arg builder (includes sandboxProviderKind when locked; omits optional fields when absent).

Written for commit 253110f. Summary will update on new commits.

Review in cubic

…kind

Auto-start and self-heal already passed sandboxProviderKind to
SANDBOX_START so provisioning stays pinned to the thread's locked
provider (#4025), but the user-driven start() — which retry() and
resume() also call — built its args without it. Retrying a failed
locked-provider sandbox (or resuming a suspended one) could get
re-provisioned on a different provider than the one the preview is
locked to, the exact 'different-provider sibling' the surrounding code
says should never happen.

Extract the shared arg-builder (buildSandboxStartArgs) so all three
call sites stay in sync, and add a regression test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant