Skip to content

Commit 26b4be0

Browse files
sweetmantechclaude
andcommitted
fix(sandbox): set source.prebuilt:true when restoring from org snapshot
Caught during the hit-case smoke test against a real recoupable org repo: with a snapshot found and `baseSnapshotId` plumbed in, the sandbox boot still fell through to a fresh `git clone`, which then failed with exit 128. Reason: I'd dropped the `prebuilt` source flag from the port, calling it "informational." It is not. Reading lib/sandbox/vercel/sandbox/VercelSandbox.ts, the flag switches between two distinct boot paths: - `source && baseSnapshotId && !source.prebuilt` → fresh clone on top of snapshot (often fails for private repos and defeats the warm-boot benefit) - `source?.prebuilt && baseSnapshotId` → `git fetch` + `git reset --hard` against the repo that's already inside the snapshot (the fast path) Setting `prebuilt: !!orgSnapshotId` matches open-agents' behavior and unlocks the actual ~75s warm-boot win this PR exists to enable. Tests updated: existing assertions for hit-case extended to also verify `source.prebuilt === true` when a snapshot is found, and `source.prebuilt === false` when the lookup misses. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 25e4b78 commit 26b4be0

2 files changed

Lines changed: 13 additions & 1 deletion

File tree

lib/sandbox/__tests__/createSandboxHandler.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,10 @@ describe("createSandboxHandler", () => {
186186
expect(findOrgSnapshot).toHaveBeenCalledWith("org-acme-xyz");
187187
const arg = vi.mocked(connectSandbox).mock.calls[0]?.[0];
188188
if (!arg || !("options" in arg)) throw new Error("expected new-API config shape");
189+
if (!("state" in arg)) throw new Error("expected new-API state shape");
189190
expect(arg.options?.baseSnapshotId).toBe("snap_abc123");
191+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
192+
expect((arg.state as any).source.prebuilt).toBe(true);
190193
});
191194

192195
it("skips the snapshot lookup entirely for non-recoupable repos", async () => {
@@ -221,7 +224,10 @@ describe("createSandboxHandler", () => {
221224
expect(findOrgSnapshot).toHaveBeenCalledWith("org-no-snap-yet");
222225
const arg = vi.mocked(connectSandbox).mock.calls[0]?.[0];
223226
if (!arg || !("options" in arg)) throw new Error("expected new-API config shape");
227+
if (!("state" in arg)) throw new Error("expected new-API state shape");
224228
expect(arg.options?.baseSnapshotId).toBeUndefined();
229+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
230+
expect((arg.state as any).source.prebuilt).toBe(false);
225231
});
226232

227233
it("does not attempt skill installation when no sessionId is provided", async () => {

lib/sandbox/createSandboxHandler.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,13 @@ export async function createSandboxHandler(request: NextRequest): Promise<NextRe
7575
state: {
7676
type: "vercel",
7777
...(sandboxName ? { sandboxName } : {}),
78-
source: { repo: body.repoUrl },
78+
// `prebuilt: true` when restoring from an org snapshot tells the
79+
// Vercel sandbox runtime to skip the fresh `git clone` and instead
80+
// `git fetch` + `git reset --hard` the repo that's already inside
81+
// the snapshot. Without this flag, Vercel treats the snapshot as a
82+
// base image and tries to clone fresh on top — which often fails
83+
// for private repos and definitely defeats the warm-boot benefit.
84+
source: { repo: body.repoUrl, prebuilt: !!orgSnapshotId },
7985
},
8086
options: {
8187
timeout: DEFAULT_TIMEOUT_MS,

0 commit comments

Comments
 (0)