fix(sandbox): keep Claude Code dispatches out of tenant warm pools - #5835
Merged
Conversation
added 2 commits
August 6, 2026 21:14
A dispatch claim is `cloneOnly` — it wants a checkout, not a dev server. It could still resolve a tenant pool, and binding one is actively destructive: Studio posts `cloneOnly` + the thread branch, the daemon classifies `branch-change`, and its clone step stops the dev task. So every dispatch consumed a warm slot AND de-warmed the pod it took. They fall back to the generic pool, which is what an empty pod is for. Also stop the daemon spawning a second dev server: POST /exec/<starter> now returns the running task (`alreadyRunning: true`) instead of starting another. An agent that runs `dev` on a pod already running it — the normal state of a warmed sandbox — otherwise puts two builds on one memory limit and OOMs the pod out from under itself.
pedrofrxncx
enabled auto-merge (squash)
August 7, 2026 00:21
decocms Bot
pushed a commit
that referenced
this pull request
Aug 7, 2026
PR: #5835 fix(sandbox): keep Claude Code dispatches out of tenant warm pools Bump type: patch - @decocms/sandbox (packages/sandbox/package.json): 1.43.0 -> 1.43.1 - deploy/helm/sandbox-env (chart 0.12.2) (deploy/helm/sandbox-env/values.yaml deploy/helm/sandbox-env/Chart.yaml): image.tag/appVersion -> 1.43.1 Deploy-Scope: both
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.
Two bugs found while running the Electrolux pool in prod (follow-up to #5830).
1. Dispatches were eating — and de-warming — the tenant pool
The Claude Code dispatch path already asks for
cloneOnly: true(
harnesses/sandbox-dispatch-client.ts): it wants a checkout, no install, nodev server. But that claim could still resolve a tenant pool, and binding one is
worse than wasteful:
cloneOnly: true+ the thread branch;branch-change→ clone step →stopDevTask().So every dispatch consumed a warm slot and killed the dev server on the pod
it took. On a
size: 2pool a couple of dispatches empty it out.resolveTenantPoolnow refusescloneOnlyclaims, which fall back towarmpool: "default"— the generic pool of empty pods, which is exactly what adispatch wants and gets there fastest. The rule lives in the pure resolver so
it's covered by a unit test rather than implied by the call site.
2. The daemon would spawn a second dev server
POST /_sandbox/exec/<script>spawned unconditionally, while the orchestrator'sown dev task spawns with
ReplaceByLogName. So an agent runningdevon a podthat is already running it — the normal state of a warmed sandbox, and exactly
what this feature creates more of — got a second Vite/Next build on the same
pod's memory limit and OOMed the pod out from under itself.
Now a well-known starter (
dev/start) with a live task returns that task(
{ taskId, status, alreadyRunning: true }) instead of spawning. Idempotent, soan agent that asks twice keeps pointing at the same server rather than
restarting it — a restart on a big repo is minutes.
Ceiling worth naming: this guards the
/execroute, which is the path Studio'stooling uses. An agent shelling out to
npm run devin a terminal stillbypasses it.
Tests
cloneOnlyclaim resolves no pool;cloneOnly: falsestill does.devtask,POST /exec/devanswers
alreadyRunning: trueand twice in a row returns the sametaskId.The fixture helper gained an optional
scriptsmap so a repo can declare along-running
dev.daemon-e2esuite green.Summary by cubic
Prevented Claude Code clone-only dispatches from using tenant warm pool pods, and made dev/start execution idempotent to avoid duplicate dev servers. This keeps tenant pools warm and reduces OOMs during dispatch-heavy periods.
Bug Fixes
resolveTenantPoolnow takes a claim object and rejectscloneOnlyclaims, falling back towarmpool: "default".runner.tspassescloneOnly. Added unit tests.POST /_sandbox/exec/<starter>returns the running task (alreadyRunning: true) instead of starting a second dev server. AddsRunningByLogNamein the Go task manager and an e2e test.setupBareRepoacceptsscriptsto define a long-runningdev.Refactors
Written for commit 9a89e4f. Summary will update on new commits.