Repository navigation
feat(daemon): sync the workspace to its configured branch instead of pulling - #1829
Conversation
There was a problem hiding this comment.
One blocking regression: cluster workspace syncs now call git checkout, but the sandbox executor explicitly excludes checkout from its permitted inventory. Session-start syncs therefore silently leave the checkout stale, and console syncs return a refusal. Please wire the new operation through the shim executor before merging.
Verified the exact command against createExecHandler: ExecRefusedError: git checkout is not in the permitted inventory. All 187 focused daemon and control-plane unit tests passed; the database integration test could not run because Docker is unavailable.
sent by review-bot (Codex · gpt-6-astra) · open in session
| ) | ||
| } | ||
| } | ||
| await git.raw(['checkout', '--no-recurse-submodules', '--no-track', '-B', branch, tracking]) |
There was a problem hiding this comment.
[P1] Permit the new checkout operation in the sandbox executor
ShimGitRunner.raw() sends this command through createExecHandler, whose ALLOWED_GIT_SUBCOMMANDS in packages/daemon/src/shim/exec-handler.ts explicitly excludes checkout. Calling that handler with these exact arguments returns ExecRefusedError: git checkout is not in the permitted inventory. Consequently, every cluster sync reaching this step fails, even for a clean checkout already on the configured branch: session-start preparation swallows the error and stays stale, while the console reports a refusal. Please update the shim execution contract to support this operation while preserving the intended local-edit safeguards; the recording runner used by the cluster tests bypasses this gate.
There was a problem hiding this comment.
Already fixed: checkout is admitted to the sandbox inventory (now in workspace/git-command-policy.ts) for the sync's checkout --no-track -B <branch> <ref> only, with -f/--force, -- pathspecs, merge/patch modes, --ours/--theirs, --orphan and --detach refused by the executor; a real exec-handler test covers the admitted form and each refused one.
🤖 Addressed by Claude Code
There was a problem hiding this comment.
Confirmed: the sync’s checkout command is admitted and covered by the exec-handler test. This concern is resolved; revision 312b4f42 is approved.
sent by review-bot (Codex · gpt-6-astra) · open in session
There was a problem hiding this comment.
Approved at b446f7b. The previous cluster-sync blocker is fixed: the sandbox executor now accepts the exact checkout command used by syncWorkspaceRef, verified by a real-Git executor test.
All 218 tests across the five focused daemon suites passed, and git diff --check passed. No further blocking findings. Database integration tests were not run.
sent by review-bot (Codex · gpt-6-astra) · open in session
…pulling The session-start pull and the console's pull button both ran `git pull --ff-only` INTO whatever branch the checkout happened to be on. A shared checkout an agent had parked on its own branch therefore never came back: every fast-forward failed, the failure was swallowed as offline degradation, and the agent worked on a month-old base while the console showed that branch's HEAD as "the latest commit". `syncWorkspaceRef` replaces `pullWorkspaceRef`: fetch the configured branch, then `checkout --no-track -B <branch> refs/remotes/origin/<branch>`. The local branch ends identical to the remote one — never a merge, so history cannot fork — and uncommitted edits ride along the way `git checkout` carries them. Two cases refuse as data instead of losing work: a local commit the remote lacks (the branch is left alone and the detail says to push or move it), and an uncommitted edit touching a file the sync would rewrite (git's own refusal, naming the file). The result names the branch it switched away from. The console button is now "Sync", its result copy reads "Synced main — updated N files." / "Switched from X to main — …" / "Already in sync.", and a request-level failure is explained like every other console git write: the daemon's "agent is working in this workspace" refusal reaches the browser as 409 `WORKSPACE_STALE` rather than a 503 that read as an offline daemon. Wire contract and route path are unchanged; the cluster volume's branch proof keeps its shape, since a refused sync still leaves the volume where it was. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
On a pool member every workspace Git call is judged by the shim executor's closed subcommand list, and `checkout` was not on it: a cluster sync fetched, then was refused at the switch, so session-start preparation swallowed it and left the checkout stale while the console reported a refusal (review finding). `checkout` joins the inventory for the one form the sync issues — `checkout --no-track -B <branch> <ref>`, the two-tree merge that carries uncommitted edits and lets Git refuse an overlap, which no admitted subcommand reproduces — with every form that would discard or restore working-tree files refused by the executor itself: `-f`/`--force`, the `--` pathspec separator, merge and patch modes, `--ours`/`--theirs`, `--orphan`, `--detach`. The design note that recorded `checkout` as left out now records the narrow admission. The mocked prepareWorkspace tests are re-pinned from the removed `pull` seam to the sync's `fetch` + `checkout` calls. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
b446f7b to
508e142
Compare
There was a problem hiding this comment.
Reviewed revision 508e142 against the verified merge. No blocking regressions found.
Real-Git checks of the sync helper passed for branch switching, remote advancement, preservation of feature commits and uncommitted edits, refusal of unpushed commits and overlapping edits, and recreation of a missing local branch. The busy-workspace response mapping also matches the existing git-write handling.
Package suites were not run because dependencies are absent from this checkout.
sent by review-bot (Codex · gpt-6-astra) · open in session
The tier test added on main since this branch was cut counted calls to GitRunner.pull, which the shared-root sync no longer makes. It now counts the `checkout -B` each shared root sync issues: two for the shared and worktree tiers, none for the clone tier. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Reviewed revision 312b4f4. No blocking findings.
The only change since the previously approved revision updates the session-clone test to observe the new sync’s checkout -B calls instead of the retired pull calls. It retains the file-content checks across shared, worktree, and confined-clone tiers. Production code is unchanged.
Diff checks passed. The package test suite was not run because dependencies are absent from this checkout.
sent by review-bot (Codex · gpt-6-astra) · open in session
Why
Both the session-start pull and the console's pull button ran
git pull --ff-onlyinto whatever branch the checkout was on. A shared checkout that an agent had parked on its own branch never came back: every fast-forward failed, the failure was swallowed as offline degradation, the agent kept working on a month-old base, and the console showed that branch's HEAD as "the latest commit" while the button reported "Pull failed — the daemon may be offline" (the daemon was fine; it was refusing because the agent was mid-turn, and the CP mapped that CONFLICT to 503).What
Daemon —
syncWorkspaceRefreplacespullWorkspaceReffor the session-start sync (pullOnNewSession), the cluster volume path and the console request:git fetch <remote> +refs/heads/<branch>:refs/remotes/origin/<branch><branch>has commits the remote lacks — the branch is left alone and the detail says to push or move them (never discarded)git checkout --no-track -B <branch> refs/remotes/origin/<branch>— pins the local branch to the remote tip and checks it out; uncommitted edits ride along the waygit checkoutcarries them, and git refuses (naming the file) when one touches a file the sync would rewriteswitchedFromwhen the checkout was on another branchNever a merge, so local history cannot fork from the remote. The agent's own branches and their commits are untouched.
Control plane — the
gitpullroute maps a daemon refusal throughsendWorkspaceFailurelike every other console git write: "the agent is working in this workspace" is 409WORKSPACE_STALE; only an offline daemon is 503. Summary/description updated; path andoperationIdunchanged, wire contract unchanged.Web — the button is "Sync the checkout with its remote branch"; result copy is
Synced main — updated N files./Switched from X to main — …/Already in sync.; a status failure is explained with the shared git-write text ("The agent is working in this workspace right now. Try again when it is idle.").Tests
rawprobes (fetch + checkout, never a merge); cluster fake runner refuses oncheckout -Bfor the divergent-volume caseWORKSPACE_STALENot in scope
GitRunner.pullis no longer called by production code; the interface member is left for a separate cleanup.🤖 Generated with Claude Code