sandbox-bench

Benchmark React or Next.js changes on Vercel Sandbox VMs with paired A/B statistics: react PR/commit vs base, or Next.js PR/commit vs base, measured end-to-end through the bench/render-pipeline app (rps, latency, p95; TTFB, RSS and document/Flight bytes when the Next side captures them) and, for React changes, through the react repo's flight-ssr-bench fixture (Node AND Edge web-streams paths, Fizz and Flight+Fizz). Use whenever the user asks to bench, perf test, or A/B a React PR, a react-server-dom / Flight / vendored React change, or a Next.js PR ("is this PR faster", "does this regress RSC?", "measure the perf impact of <commit>"), even if they don't say "benchmark" — any request to quantify a server-side performance difference between two revisions belongs here. Runs remotely (laptop-free), applies correctness gates before measuring, and reports boot-level confidence intervals.

Install
npx skills add 'https://github.com/vercel/next.js/tree/canary/.agents/skills/sandbox-bench'
Download bundle ↓
canary · bfcf687Scanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗
View on GitHub
← Back to SKILL.md
// Shared core for the sandbox-bench launchers (sandbox-e2e.mjs,// sandbox-ssr.mjs): config-derived constants, vercel sandbox plumbing// (exec, chunked upload, detached loops), PR/arm resolution with the// CI-green gate, cached react arm builds, snapshots, the status.json// recovery record, and live interim estimates. Workload-specific code// (what runs on a measurement VM) stays in each launcher.import { execFile, spawn } from 'child_process'import { promisify } from 'util'import fs from 'fs'import os from 'os'import path from 'path'import crypto from 'crypto'import {  loadConfig,  sandboxScope,  ensureNextRepo,  ensureReactRepo,} from './config.mjs' const execFileP = promisify(execFile)export { execFileP } export const DRY_RUN = process.argv.includes('--dry-run')export const CONFIG = loadConfig({ requireScope: !DRY_RUN })// Clones happen on first use: the react one only when a react ref is// benched or pinned (pure Next A/B uses each ref's vendored React).export let nextRepoResolvedexport function NEXT_REPO_LAZY() {  if (!nextRepoResolved) nextRepoResolved = ensureNextRepo(CONFIG)  return nextRepoResolved}export let reactRepoResolvedexport function REACT_REPO_LAZY() {  if (!reactRepoResolved) reactRepoResolved = ensureReactRepo(CONFIG)  return reactRepoResolved}export const VERCEL = CONFIG.vercelBinexport const SCOPE = CONFIG.team ? sandboxScope(CONFIG) : []export const CACHE = path.join(CONFIG.cacheDir, 'e2e')export const REACT_SNAP_CACHE = path.join(CONFIG.cacheDir, 'react-snap')export const SETUP_VERSION = 'v1-al2023-node24-jdk21'// Targets build-all-release-channels needs for a sync-react-able arm// (both channels, oss-stable + oss-experimental).export const E2E_BUILD_TARGETS =  'react/,react.react-server,react-dom/,react-dom.,react-dom-server,scheduler/,react-is,react-server-dom-turbopack,react-server-dom-webpack'// owner/repo for CI-artifact lookup, from the configured clone URL.export const REACT_GH_REPO =  CONFIG.reactRepoUrl.match(/github\.com[:/]+([^/]+\/[^/.]+)/)?.[1] ??  'react/react'export const NEXT_GH_REPO =  CONFIG.nextRepoUrl.match(/github\.com[:/]+([^/]+\/.+?)(?:\.git)?$/)?.[1] ??  'vercel/next.js' // Recovery record for bench-collect.mjs: if a launcher dies, the// remote VMs keep executing their detached loops, and this file names// them so the results can still be collected.export const status = { file: null, state: {} }export function writeStatus(patch) {  if (!status.file) return  status.state = {    ...status.state,    ...patch,    updatedAt: new Date().toISOString(),  }  try {    fs.writeFileSync(status.file, JSON.stringify(status.state, null, 2))  } catch {}} export async function sb(args, opts = {}) {  const scoped = ['sandbox', ...args]  const sep = scoped.indexOf('--')  scoped.splice(sep < 0 ? scoped.length : sep, 0, ...SCOPE)  const { stdout, stderr } = await execFileP(VERCEL, scoped, {    maxBuffer: 64 * 1024 * 1024,    ...opts,  })  // The CLI prints some results (e.g. snapshot ids) on stderr.  return `${stdout}\n${stderr}`} // The platform rejects single `sandbox cp` uploads somewhere above ~128MB// ("Request Entity Too Large", observed 2026-07-20; 645MB tree tarballs that// uploaded fine hours earlier started failing). Upload large files in parts// and reassemble on the VM, verifying the sha256 end to end.export const CP_CHUNK_BYTES = 128 * 1024 * 1024export async function sbCpToVm(vm, localPath, vmDest) {  const size = fs.statSync(localPath).size  if (size <= CP_CHUNK_BYTES) {    await sb(['cp', localPath, `${vm}:${vmDest}`])    return  }  const partDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sbcp-'))  try {    await execFileP('split', [      '-b',      String(CP_CHUNK_BYTES),      localPath,      path.join(partDir, 'part-'),    ])    const parts = fs.readdirSync(partDir).sort()    for (const p of parts) {      await sb(['cp', path.join(partDir, p), `${vm}:${vmDest}.${p}`])    }    const localSha = (      await execFileP('shasum', ['-a', '256', localPath])    ).stdout.split(' ')[0]    const catList = parts.map((p) => `'${vmDest}.${p}'`).join(' ')    const out = await sbExec(      vm,      '10m',      `cat ${catList} > '${vmDest}' && rm -f ${catList} && sha256sum '${vmDest}' | cut -d' ' -f1`,      `cp:${path.basename(vmDest)}`    )    // sbExec output interleaves stderr (CLI banners); take the last    // sha-shaped token rather than the last line.    const shaTokens = out.match(/\b[0-9a-f]{64}\b/g)    const remoteSha = shaTokens ? shaTokens[shaTokens.length - 1] : ''    if (remoteSha !== localSha) {      throw new Error(        `chunked upload of ${localPath} corrupt: local ${localSha} != remote ${remoteSha}`      )    }  } finally {    fs.rmSync(partDir, { recursive: true, force: true })  }} export // PR spec ("37023" or a github PR URL) -> arms: base = merge-base of the// PR head with upstream main, cand = PR head. Fetched into local refs so// git archive / yarn.lock reads work as for any other sha.async function resolvePrArms(pr, repo, repoUrl, defaultBranch) {  const num = String(pr).match(/(\d+)\/?$/)?.[1]  if (!num) throw new Error(`cannot parse PR number from "${pr}"`)  console.error(`fetching ${repoUrl} PR #${num} + ${defaultBranch}...`)  // The clone is shared: concurrent launchers fetching the same ref  // race the ref lock. Namespace the temp refs by pid and retry the  // fetch (pack files still contend occasionally).  const ns = `refs/bench-tmp/${process.pid}`  for (let attempt = 1; ; attempt++) {    try {      await execFileP('git', [        '-C',        repo,        'fetch',        '-q',        repoUrl,        `+refs/pull/${num}/head:${ns}/pr-${num}`,        `+refs/heads/${defaultBranch}:${ns}/upstream-${defaultBranch}`,      ])      break    } catch (e) {      if (attempt >= 3) throw e      console.error(        `fetch attempt ${attempt} failed (${e.message.split('\n')[0].slice(0, 80)}); retrying...`      )      await new Promise((r) =>        setTimeout(r, 5000 * attempt + Math.random() * 5000)      )    }  }  const cand = (    await execFileP('git', ['-C', repo, 'rev-parse', `${ns}/pr-${num}`])  ).stdout.trim()  const base = (    await execFileP('git', [      '-C',      repo,      'merge-base',      `${ns}/upstream-${defaultBranch}`,      cand,    ])  ).stdout.trim()  await execFileP('git', [    '-C',    repo,    'update-ref',    '-d',    `${ns}/pr-${num}`,  ]).catch(() => {})  await execFileP('git', [    '-C',    repo,    'update-ref',    '-d',    `${ns}/upstream-${defaultBranch}`,  ]).catch(() => {})  console.error(    `PR #${num}: cand=${cand.slice(0, 12)} base=${base.slice(0, 12)} (merge-base with ${defaultBranch})`  )  return [    { name: 'base', ref: base },    { name: `pr${num}`, ref: cand },  ]} // Green CI on the react repo is the correctness gate for react arms: a// perf number from a broken build is worse than no number. Local or// unpushed refs have no CI — --allow-ungated skips the check, and// sandbox-gate.mjs exists to gate such refs on a VM instead.const ciVerdicts = new Map()export async function assertCiGreen(sha, armName, allowUngated) {  if (!ciVerdicts.has(sha)) {    let verdict    try {      const out = (        await execFileP(          'gh',          [            'api',            '--paginate',            `repos/${REACT_GH_REPO}/commits/${sha}/check-runs?per_page=100`,            '--jq',            '[.check_runs[] | {name, conclusion}]',          ],          { maxBuffer: 1 << 24 }        )      ).stdout      const checks = out        .trim()        .split('\n')        .filter(Boolean)        .flatMap((page) => JSON.parse(page))      if (checks.length === 0) {        verdict = 'no CI runs found (unpushed or unbuilt commit)'      } else if (checks.some((c) => c.conclusion === null)) {        verdict = 'CI still running — retry when it finishes'      } else {        // Policy: all tests (including build), flow, and lint must be        // green. DevTools suites and repo-infra jobs (artifact syncs,        // cleanup, staleness) don't gate benching. Ignore-by-name, so        // any NEW job blocks by default instead of being skipped.        const IGNORED =          /devtools|^cleanup$|^stale$|_artifacts$|^sizebot|^dependabot/i        const relevant = checks.filter((c) => !IGNORED.test(c.name))        const bad = relevant.filter(          (c) =>            c.conclusion !== 'success' &&            c.conclusion !== 'neutral' &&            c.conclusion !== 'skipped'        )        // Name the offenders: the human deciding whether to proceed        // ungated needs to see what failed at a glance, not re-query CI.        verdict =          bad.length === 0            ? 'green'            : `CI not green (${bad.length}/${relevant.length} relevant checks): ` +              [...new Set(bad.map((c) => `${c.name} (${c.conclusion})`))]                .slice(0, 8)                .join('; ')      }    } catch (e) {      verdict = `could not query CI (${e.message.split('\n')[0].slice(0, 80)})`    }    ciVerdicts.set(sha, verdict)  }  const verdict = ciVerdicts.get(sha)  if (verdict === 'green') {    console.error(`arm ${armName}: react ${sha.slice(0, 12)} CI green`)    return  }  if (allowUngated) {    console.error(      `arm ${armName}: react ${sha.slice(0, 12)} UNGATED (${verdict}) — proceeding per --allow-ungated`    )    return  }  throw new Error(    `arm ${armName}: react ${sha.slice(0, 12)}: ${verdict}.\n` +      'Benching an unverified build produces untrustworthy numbers. Either wait for/fix CI, ' +      'gate the ref yourself (node sandbox-gate.mjs --arms ' +      armName +      '=<ref>), and then ' +      're-run with --allow-ungated, or pass --allow-ungated if you accept the risk.'  )} export async function commitTitle(repo, ref) {  try {    return (      await execFileP('git', ['-C', repo, 'log', '-1', '--format=%s', ref])    ).stdout.trim()  } catch {    return undefined  }} export function printRunContext(out, d) {  if (!d) return  if (d.pr) out(`PR: ${d.pr.title ? `"${d.pr.title}" — ` : ''}${d.pr.url}`)  for (const a of d.arms ?? []) if (a.title) out(`  ${a.name}: "${a.title}"`)} // Live running estimate, printed as pairs complete across all VMs.const T95 = [  12.71, 4.3, 3.18, 2.78, 2.57, 2.45, 2.36, 2.31, 2.26, 2.23, 2.2, 2.18, 2.16,  2.14, 2.13,]export function makeLive(baseName, metrics, keyOf) {  const rows = []  return (vm, row) => {    rows.push({ vmIdx: vm, ...row })    const key = keyOf(row)    const other = rows.find(      (r) =>        r.vmIdx === vm &&        keyOf(r) === key &&        r.block === row.block &&        r.run === row.run &&        r.arm !== row.arm    )    if (!other) return    const cands = rows.filter((r) => keyOf(r) === key && r.arm !== baseName)    const parts = []    let n = 0    for (const metric of metrics) {      const deltas = []      for (const c of cands) {        const b = rows.find(          (r) =>            r.vmIdx === c.vmIdx &&            keyOf(r) === key &&            r.block === c.block &&            r.run === c.run &&            r.arm === baseName        )        if (b && b[metric] > 0) deltas.push((c[metric] - b[metric]) / b[metric])      }      n = deltas.length      if (n < 2) return      const mean = deltas.reduce((a, b2) => a + b2, 0) / n      const sd = Math.sqrt(        deltas.reduce((a, b2) => a + (b2 - mean) ** 2, 0) / (n - 1)      )      const ci = ((T95[n - 2] ?? 2.0) * sd) / Math.sqrt(n)      const p = pairedP(deltas)      parts.push(        `${metric} ${(mean * 100).toFixed(1)}%±${(ci * 100).toFixed(1)} p=${p.toFixed(3)}`      )    }    console.error(`live ${key} n=${n}: ${parts.join('  ')}`)  }} export function pairedP(deltas) {  const n = deltas.length  if (n < 2) return 1  const mean = deltas.reduce((a, b) => a + b, 0) / n  const sd = Math.sqrt(    deltas.reduce((a, b) => a + (b - mean) ** 2, 0) / (n - 1)  )  if (sd === 0) return mean === 0 ? 1 : 0  const t = Math.abs(mean / (sd / Math.sqrt(n)))  const df = n - 1  const pdf = (x) => Math.exp(-((df + 1) / 2) * Math.log(1 + (x * x) / df))  let integral = 0  const STEP = 0.001  for (let x = t; x < t + 60; x += STEP) integral += pdf(x + STEP / 2) * STEP  let norm = 0  for (let x = 0; x < 80; x += STEP) norm += pdf(x + STEP / 2) * STEP  return Math.min(1, integral / norm)} export function sbExec(vm, timeout, script, tag, onRow) {  return new Promise((resolve, reject) => {    // The CLI does not reliably propagate the remote exit code (observed    // exit 0 after a remote `exit 1`, CLI 56.3.x), so the script reports    // its own exit through an EXIT-trap marker; no marker means the    // transport died mid-run. Both are failures.    const wrapped = `trap 'echo "@@EXEC_EXIT $?"' EXIT${script}`    const child = spawn(      VERCEL,      [        'sandbox',        'exec',        vm,        ...SCOPE,        '--timeout',        timeout,        '--',        'bash',        '-c',        wrapped,      ],      { stdio: ['ignore', 'pipe', 'pipe'] }    )    let out = ''    let buf = ''    child.stdout.on('data', (c) => {      out += c      buf += c      const lines = buf.split('\n')      buf = lines.pop()      for (const l of lines) {        if (!l) continue        if (l.startsWith('ROW ') && onRow) {          try {            onRow(JSON.parse(l.slice(4)))          } catch {}        } else {          process.stderr.write(`[${tag}] ${l}\n`)        }      }    })    child.stderr.on('data', (c) => {      out += c      process.stderr.write(        String(c)          .split('\n')          .filter(Boolean)          .map((l) => `[${tag}!] ${l}\n`)          .join('')      )    })    child.on('exit', (code) => {      const marker = out.match(/@@EXEC_EXIT (\d+)\s*$/m)      if (code === 0 && marker && marker[1] === '0') {        resolve(out)      } else {        const why =          code !== 0            ? `cli exit ${code}`            : marker              ? `remote exit ${marker[1]}`              : 'no exit marker (transport died mid-run)'        reject(new Error(`${tag}: ${why}\n${out.slice(-2000)}`))      }    })  })} export async function rmVm(name) {  try {    await sb(['rm', name])  } catch (e) {    process.stderr.write(`warning: could not remove ${name}: ${e.message}\n`)  }} // Long-running remote work detached from the exec stream (streams drop// flakily on multi-minute silences): nohup the script on the VM, then// poll its log with short execs. Immune to transport hiccups.export async function runDetached(vm, tag, script, onLine, deadlineMin) {  let transcript = ''  const local = path.join(os.tmpdir(), `loop-${vm}.sh`)  // EXIT trap, not ERR: the ERR trap does not fire for several failure  // shapes (e.g. `cmd || (tail; exit 1)`), which left loop.done unwritten  // and the poll waiting on heartbeats forever.  fs.writeFileSync(    local,    `trap 'code=$?; if [ $code -eq 0 ]; then echo LOOPOK; else echo LOOPFAIL; fi > /vercel/sandbox/loop.done' EXIT\nset -e\n${script}\n`  )  await sb(['cp', local, `${vm}:/vercel/sandbox/loop.sh`])  fs.rmSync(local, { force: true })  await sb([    'exec',    vm,    '--timeout',    '2m',    '--',    'bash',    '-c',    'rm -f /vercel/sandbox/loop.done /vercel/sandbox/loop.log; nohup bash /vercel/sandbox/loop.sh >/vercel/sandbox/loop.log 2>&1 & echo kicked',  ])  let offset = 0  let failures = 0  const deadline = Date.now() + deadlineMin * 60_000  while (true) {    await new Promise((r) => setTimeout(r, 45_000))    if (Date.now() > deadline)      throw new Error(`${tag}: detached loop deadline exceeded`)    let out    try {      out = await sb([        'exec',        vm,        '--timeout',        '2m',        '--',        'bash',        '-c',        `tail -c +${offset + 1} /vercel/sandbox/loop.log | head -c 200000; printf '\\n@@SIZE %s @@DONE %s\\n' "$(stat -c %s /vercel/sandbox/loop.log 2>/dev/null || echo 0)" "$(cat /vercel/sandbox/loop.done 2>/dev/null || echo no)"`,      ])      failures = 0    } catch (e) {      if (++failures >= 6)        throw new Error(          `${tag}: ${failures} consecutive poll failures: ${e.message.slice(0, 200)}`        )      continue    }    const m = out.match(/@@SIZE (\d+) @@DONE (\S+)/)    const body = out.slice(0, out.lastIndexOf('\n@@SIZE'))    transcript += body    for (const l of body.split('\n')) {      if (!l) continue      if (l.startsWith('ROW ') && onLine) {        try {          onLine(JSON.parse(l.slice(4)))        } catch {}      } else {        process.stderr.write(`[${tag}] ${l}\n`)      }    }    if (m) {      offset = Math.min(Number(m[1]), offset + 200000)      if (m[2] === 'LOOPOK') return transcript      if (m[2] === 'LOOPFAIL')        throw new Error(          `${tag}: remote loop failed; tail:\n${body.slice(-1500)}`        )    }  }} // ------------------------------------------------------------ snapshots export async function sha256(text) {  return crypto.createHash('sha256').update(text).digest('hex').slice(0, 16)} export async function snapshotIdFor(cacheDir, key) {  const file = path.join(cacheDir, `snap-${key}`)  if (!fs.existsSync(file)) return undefined  const id = fs.readFileSync(file, 'utf8').trim()  try {    await sb(['snapshots', 'get', id])    return id  } catch {    return undefined  }} export async function takeSnapshot(vm, cacheDir, key) {  const out = await sb(['snapshot', vm, '--stop', '--expiration', '30d'])  const id = out.match(/snap_[A-Za-z0-9]+/)?.[0]  if (!id)    throw new Error(`could not parse snapshot id from: ${out.slice(-500)}`)  fs.mkdirSync(cacheDir, { recursive: true })  fs.writeFileSync(path.join(cacheDir, `snap-${key}`), `${id}\n`)  console.error(`snapshot ${id} cached (${key})`)  return id} // React build environment (repo + node_modules + JDK), shared with// sandbox-ab.mjs. Keyed on the arm's yarn.lock.export async function ensureReactBuildSnapshot(refSha) {  const lock = await execFileP(    'git',    ['-C', REACT_REPO_LAZY(), 'show', `${refSha}:yarn.lock`],    { maxBuffer: 1 << 28 }  )  const key = await sha256(SETUP_VERSION + lock.stdout)  let id = await snapshotIdFor(REACT_SNAP_CACHE, key)  if (id) return id  const vm = `react-snap-build-${Date.now().toString(36)}`  console.error(    `creating react build-env snapshot (one-time for this yarn.lock)...`  )  await sb([    'create',    '--name',    vm,    '--runtime',    'node24',    '--vcpus',    '8',    '--timeout',    '45m',    '--non-persistent',    '--network-policy',    'allow-all',    '--tag',    'purpose=sandbox-bench',    '--silent',  ])  try {    const src = path.join(os.tmpdir(), `react-snap-src-${key}.tgz`)    await execFileP('bash', [      '-c',      `git -C ${REACT_REPO_LAZY()} archive ${refSha} | gzip -1 > ${src}`,    ])    await sb(['cp', src, `${vm}:/vercel/sandbox/src.tgz`])    fs.rmSync(src, { force: true })    await sb([      'exec',      vm,      '--timeout',      '10m',      '--sudo',      '--',      'dnf',      'install',      '-y',      '-q',      'java-21-amazon-corretto-headless',    ])    await sbExec(      vm,      '20m',      `set -e; mkdir -p /vercel/sandbox/react && cd /vercel/sandbox/react && tar -xzf ../src.tgz && rm -f ../src.tgz && ` +        `npm i -g yarn >/dev/null 2>&1 && yarn install --frozen-lockfile --ignore-engines >/dev/null 2>&1 && echo react env ready`,      'react-snap'    )    return await takeSnapshot(vm, REACT_SNAP_CACHE, key)  } finally {    await rmVm(vm)  }} // React CI builds every upstream commit and PR; reuse those artifacts// instead of building. Requires gh auth. Returns false -> build remotely.export async function tryCiArtifactArm(sha, cached, pack) {  try {    const runs = JSON.parse(      (        await execFileP(          'gh',          [            'api',            `repos/${REACT_GH_REPO}/actions/workflows/runtime_build_and_test.yml/runs?head_sha=${sha}&per_page=5`,          ],          { maxBuffer: 1 << 24 }        )      ).stdout    )    const id = runs.workflow_runs?.find((r) => r.head_sha === sha)?.id    if (!id) return false    const arts = JSON.parse(      (        await execFileP(          'gh',          [            'api',            `repos/${REACT_GH_REPO}/actions/runs/${id}/artifacts?name=artifacts_combined`,          ],          { maxBuffer: 1 << 24 }        )      ).stdout    )    const art = arts.artifacts?.find(      (a) => a.name === 'artifacts_combined' && !a.expired    )    if (!art) return false    console.error(      `downloading CI artifacts for ${sha.slice(0, 12)} (run ${id})...`    )    const work = fs.mkdtempSync(path.join(os.tmpdir(), 'ci-arm-'))    try {      await execFileP(        'bash',        [          '-c',          `cd ${work} && gh api repos/${REACT_GH_REPO}/actions/artifacts/${art.id}/zip > a.zip && ` +            `unzip -q a.zip && tar -xzf build.tgz && ${pack}`,        ],        { maxBuffer: 1 << 24 }      )    } finally {      fs.rmSync(work, { recursive: true, force: true })    }    return fs.existsSync(cached) && fs.statSync(cached).size > 1 << 20  } catch (e) {    console.error(      `CI artifact lookup failed (${e.message.slice(0, 100)}); building remotely`    )    return false  }} // Ref arms build remotely (dual-channel yarn build) and cache by sha.export async function ensureRefArm(arm) {  const sha = (    await execFileP('git', ['-C', REACT_REPO_LAZY(), 'rev-parse', arm.ref])  ).stdout.trim()  arm.sha = sha  // Key on the build recipe too: a changed target list must not serve  // stale artifacts from the shared cache.  const recipe = crypto    .createHash('sha256')    .update(E2E_BUILD_TARGETS)    .digest('hex')    .slice(0, 6)  const cached = path.join(CACHE, `arm-${sha.slice(0, 12)}-${recipe}.tgz`)  arm.tgz = cached  if (fs.existsSync(cached)) {    console.error(`arm ${arm.name}=${sha.slice(0, 12)} (cached build)`)    return  }  fs.mkdirSync(CACHE, { recursive: true })  if (    await tryCiArtifactArm(      sha,      cached,      `tar -czf ${cached} build/oss-stable build/oss-experimental`    )  ) {    console.error(`arm ${arm.name}=${sha.slice(0, 12)} from CI artifacts`)    return  }  const snap = await ensureReactBuildSnapshot(sha)  const vm = `sbench-armbuild-${Date.now().toString(36)}`  console.error(    `building react arm ${arm.name}=${sha.slice(0, 12)} remotely...`  )  await sb([    'create',    '--name',    vm,    '--snapshot',    snap,    '--vcpus',    '8',    '--timeout',    '45m',    '--non-persistent',    '--network-policy',    'allow-all',    '--tag',    'purpose=sandbox-bench',    '--silent',  ])  try {    // build-all-release-channels stamps versions from git (sha + commit    // date), so the upload must be a real shallow checkout, not a bare    // archive.    const src = path.join(os.tmpdir(), `arm-src-${sha.slice(0, 12)}.tgz`)    const work = fs.mkdtempSync(path.join(os.tmpdir(), 'arm-git-'))    const tmpRef = `refs/bench-tmp/${sha.slice(0, 12)}`    await execFileP('git', ['-C', REACT_REPO_LAZY(), 'update-ref', tmpRef, sha])    try {      await execFileP('git', ['init', '-q', work])      await execFileP('git', [        '-C',        work,        'fetch',        '-q',        '--depth',        '1',        REACT_REPO_LAZY(),        tmpRef,      ])      await execFileP('git', ['-C', work, 'checkout', '-q', 'FETCH_HEAD'])      await execFileP('bash', [        '-c',        `cd ${work} && COPYFILE_DISABLE=1 tar --no-xattrs -czf ${src} .`,      ])    } finally {      await execFileP('git', [        '-C',        REACT_REPO_LAZY(),        'update-ref',        '-d',        tmpRef,      ])      fs.rmSync(work, { recursive: true, force: true })    }    await sb(['cp', src, `${vm}:/vercel/sandbox/src.tgz`])    fs.rmSync(src, { force: true })    // The exec stream drops on long silent commands; heartbeat keeps it    // alive during the ~10min dual-channel build. Newline before the    // backgrounded heartbeat: a trailing & after && backgrounds the    // whole chain.    await sbExec(      vm,      '40m',      `set -els /vercel/sandbox/react/node_modules >/dev/nullcd /vercel/sandbox/reactfind . -mindepth 1 -maxdepth 1 ! -name node_modules -exec rm -rf {} +tar -xzf ../src.tgzgit rev-parse HEAD(while true; do echo "hb mem=$(free -m | awk '/^Mem/{print $3}')MB $(tail -1 /tmp/build.log 2>/dev/null | cut -c1-60)"; sleep 30; done) & HB=$!yarn build "${E2E_BUILD_TARGETS}" >/tmp/build.log 2>&1 || (kill $HB; tail -20 /tmp/build.log; exit 1)kill $HBtar -czf /vercel/sandbox/arm.tgz build/oss-stable build/oss-experimentalecho arm built`,      `armbuild:${arm.name}`    )    fs.mkdirSync(CACHE, { recursive: true })    const armTmp = `${cached}.tmp-${process.pid}`    await sb(['cp', `${vm}:/vercel/sandbox/arm.tgz`, armTmp])    if (fs.existsSync(armTmp)) fs.renameSync(armTmp, cached)    // sandbox cp does not reliably fail on missing remote files.    if (!fs.existsSync(cached) || fs.statSync(cached).size < 1 << 20) {      fs.rmSync(cached, { force: true })      throw new Error(        `arm ${arm.name}: downloaded artifact missing or too small`      )    }    console.error(`cached ${cached}`)  } finally {    await rmVm(vm)  }}