feat(babysitter): keep the fixer's PR checkout across reused sandboxes (F3a)
Stacked on #634. This is the flows half of per-PR sandbox reuse (C2, lead-approved; Khaliq: "the same sandbox can be used when it is woken up for incoming pr feedback"). The Cloud half starts with cloud#4354.
Why
Cloud will hand a later wake the same sandbox, but bootstrap wipes and recreates each run's state root (bootstrap-inner.mjs, rm -rf on every start). The agent's cwd must also be inside the run root. So the checkout cannot simply stay in the run root.
What
restoreCheckoutmoves$HOME/.babysitter/<owner>/<repo>/<pr>/checkoutinto<run root>/babysitter-checkoutbeforecheckoutHead.- It is a rename, so installed dependencies come along.
checkoutHeadthen resets git config, fetches,reset --hard <head>, andclean -fd(ignored deps kept). Those steps already existed.- A cache on another filesystem (
EXDEV), or a damaged one, is dropped, and the run starts fresh.
stashCheckoutmoves the checkout back in afinally, whatever the run's outcome.- The body computes its verdict, stashes, and only then calls
f.done, so the stash is a step of the run.
- The body computes its verdict, stashes, and only then calls
- Not here: resuming the previous agent session.
f.agenthas no resume option today. That needs its own surface/SDK change.
Evidence (examples/babysitter/evidence/f3-checkout-cache/, unedited)
01-red.txt: the two new tests fail before the implementation.02-all-babysitter-green.txt: 135 tests, 128 pass, 0 fail, 7 todo. New tests:- A checkout with
node_modulessurvives stash, then restore into a new run root. - The order is restore → checkout → propose → stash.
- Stash happens even when the agent throws.
- restore/stash lifted from the shipped artifact run under
node -e.
- A checkout with
03: digests reproduce. Standalone is unchanged at580bab1d…; fixer is now6526a283e5c950a72e994f113d7201ff51b920a039f5d134b05c7dcc0a5957a8.04:flows checkpasses.05: the shipped-source audit passes 2/2 (the audit file is untouched).06:filtered-count=0.
Cloud#4348's fixer pin must move to the final fixer digest once this stack settles.
🤖 Generated with Claude Code
[!NOTE]
Medium Risk
Changes sandbox filesystem layout and git checkout/clean behavior on the agent path; incorrect reuse could leave stale dependencies or skip cache, though manifest fingerprinting and .git rebuild mitigate security and consistency risks.
Overview
Adds per-PR checkout reuse for the Babysitter fixer when Cloud reuses the same sandbox: the working tree (including node_modules) is renamed between $HOME/.babysitter/<owner>/<repo>/<pr>/checkout and the run’s babysitter-checkout via new restoreCheckout / stashCheckout steps, with restore → work → stash in a finally before f.done.
checkoutHead is tightened for reused trees: it always deletes and re-inits .git (so prior agent hooks/config never run with the token), then fetch/reset to the bound head. It fingerprints dependency manifests and runs git clean -fdx when lockfiles changed so cached ignored deps are not kept stale.
Cache moves are best-effort (cross-filesystem or bad cache → fresh run). Docs, shipped artifact digest, and fixer tests cover restore/stash ordering, agent failures, damaged .git, and manifest changes.
Reviewed by Cursor Bugbot for commit 9aa641383a4e362de800b28cc0931e7d2a64e811. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
Keeps the fixer's PR checkout across reused sandboxes so a later wake on the same box can reuse installed dependencies instead of starting from scratch.
- The checkout is moved from
$HOME/.babysitter/<owner>/<repo>/<pr>/checkoutinto the run root beforecheckoutHead, and moved back in afinallybeforef.done, whatever the run's outcome. .gitis rebuilt on every run, so git state a previous agent turn planted (config, hooks, attributes, a damaged repo) never reaches a git command that carries the token.- Dependency manifests and lockfiles are fingerprinted; if any changed since the previous head, cached ignored files are dropped so the agent never tests against stale dependencies.
- Cache moves are best effort: a cache on another filesystem, or an unwritable or damaged one, is dropped and the run starts fresh.
- The agent step stays in the registered body so
flows checkstill reports the codex and claude requirements. - Resuming the prior agent session is out of scope;
f.agenthas no resume option yet.
Agent Relay sessions