Symptom (observed once, not yet reproducible)
While running studio wp datamachine-code workspace worktree add wc-site-generator cherry-pick-finding-packet-fix --from=static/marbling-bench from a Studio agent shell on a workspace that already had ~474 worktrees registered, DMC reported success with branch metadata cherry-pick-finding-packet-fix (created), but the actual worktree on disk was checked out to the source branch (static/marbling-bench), not the requested new branch.
$ studio wp datamachine-code workspace worktree add wc-site-generator cherry-pick-finding-packet-fix --from=static/marbling-bench
Success: Worktree \"wc-site-generator@cherry-pick-finding-packet-fix\" added at /Users/.../wc-site-generator@cherry-pick-finding-packet-fix (branch fix/static-validation-finding-packets-regression).
Handle: wc-site-generator@cherry-pick-finding-packet-fix
Path: /Users/.../wc-site-generator@cherry-pick-finding-packet-fix
Branch: cherry-pick-finding-packet-fix (created)
$ cd /Users/.../wc-site-generator@cherry-pick-finding-packet-fix
$ git status -sb
## static/marbling-bench...origin/static/marbling-bench [ahead 1] <-- not the new branch
$ git branch --show-current
static/marbling-bench
Net effect: a subsequent git cherry-pick committed onto static/marbling-bench directly, and git push origin static/marbling-bench would have shipped that commit straight to whatever PR owns that branch — exactly the cross-session collision the <repo>@<slug> worktree convention exists to prevent.
In my case the resulting commit landed on PR #91's branch, which was actually convenient for my task, but it could just as easily have force-pushed an unrelated experiment onto someone else's open PR.
Cannot reproduce on rerun
I removed the worktree (and the deleted local branch) and reran the exact same command four times in a row. Every subsequent run produced the correct outcome (worktree on cherry-pick-finding-packet-fix, branch created). So this is either:
- A race condition with another concurrent DMC mutation,
- An interaction with the workspace state at that moment (~474 worktrees, disk-budget warning fired, fetch had succeeded, base was 10 commits behind upstream — under the 50-commit staleness threshold),
- Or something I misread in the original output.
Filing this as observational rather than as a deterministic bug, but flagging the codepath that would be most likely to manifest the symptom.
Suspected codepath
inc/Workspace/Workspace.php::worktree_add_locked() (lines 1394-1407 at HEAD 6010125):
exec( sprintf( 'git -C %s show-ref --verify --quiet %s 2>&1', escapeshellarg( $primary_path ), escapeshellarg( 'refs/heads/' . $branch ) ), $_unused, $exists_local );
$created_branch = false;
$resolved_base = null;
if ( 0 === $exists_local ) {
$cmd = sprintf( 'worktree add %s %s', escapeshellarg( $wt_path ), escapeshellarg( $branch ) );
} else {
$base = $from && '' !== trim( $from ) ? trim( $from ) : $this->resolve_default_base( $primary_path );
$resolved_base = $base;
$cmd = sprintf( 'worktree add -b %s %s %s', escapeshellarg( $branch ), escapeshellarg( $wt_path ), escapeshellarg( $base ) );
$created_branch = true;
}
If for any reason show-ref --verify --quiet refs/heads/<new-branch> returned exit 0 even though the new branch didn't actually exist (stale ref-cache, parallel ref churn, packed-refs interaction), DMC would dispatch the no--b form against the new-branch-name positional, which git would interpret as "check out existing branch with that name" — but if the branch actually doesn't exist, the command would fail. So that path doesn't fully explain my observation either.
A more defensive shape would be: regardless of which command DMC chose, after run_git, verify the worktree HEAD actually matches $branch before reporting success and writing inventory rows. Suggested check (uses git plumbing, no extra deps):
$head_check = $this->run_git( $wt_path, 'rev-parse --abbrev-ref HEAD' );
if ( ! is_wp_error( $head_check ) ) {
$actual_branch = trim( (string) ( $head_check['output'] ?? '' ) );
if ( $actual_branch !== $branch ) {
$this->run_git( $primary_path, sprintf( 'worktree remove --force %s', escapeshellarg( $wt_path ) ) );
return new \WP_Error(
'worktree_branch_mismatch',
sprintf( 'Worktree was created at %s but checked out branch \"%s\" instead of the requested \"%s\". Removed the half-cooked worktree; please retry.', $wt_path, $actual_branch, $branch ),
array( 'status' => 500, 'expected' => $branch, 'actual' => $actual_branch )
);
}
}
That converts a silent collision (which I hit, but cannot reproduce) into a loud, recoverable error — matches the rest of the staleness-gate behavior in the same function, where a half-cooked worktree gets torn down rather than returned.
Repro environment
- Host: macOS, Studio CLI driving DMC on
intelligence-chubes4.
- Workspace:
/Users/chubes/Developer, ~474 worktrees registered (above the 100-warning threshold), disk-budget status warning.
- Repo:
chubes4/wc-site-generator, primary at static/spore-ledger-field-supply, source branch static/marbling-bench had a local checkout 10 commits behind origin/static/marbling-bench.
- DMC HEAD:
6010125 fix: expose bounded cleanup-eligible apply path.
- Studio agent shell, no concurrent CLI calls visible from my session — but I can't speak to background tasks the agent runtime might have triggered.
Happy to instrument or rerun under different conditions if there's a code path you want me to push on.
Symptom (observed once, not yet reproducible)
While running
studio wp datamachine-code workspace worktree add wc-site-generator cherry-pick-finding-packet-fix --from=static/marbling-benchfrom a Studio agent shell on a workspace that already had ~474 worktrees registered, DMC reported success with branch metadatacherry-pick-finding-packet-fix (created), but the actual worktree on disk was checked out to the source branch (static/marbling-bench), not the requested new branch.Net effect: a subsequent
git cherry-pickcommitted ontostatic/marbling-benchdirectly, andgit push origin static/marbling-benchwould have shipped that commit straight to whatever PR owns that branch — exactly the cross-session collision the<repo>@<slug>worktree convention exists to prevent.In my case the resulting commit landed on PR #91's branch, which was actually convenient for my task, but it could just as easily have force-pushed an unrelated experiment onto someone else's open PR.
Cannot reproduce on rerun
I removed the worktree (and the deleted local branch) and reran the exact same command four times in a row. Every subsequent run produced the correct outcome (worktree on
cherry-pick-finding-packet-fix, branch created). So this is either:Filing this as observational rather than as a deterministic bug, but flagging the codepath that would be most likely to manifest the symptom.
Suspected codepath
inc/Workspace/Workspace.php::worktree_add_locked()(lines 1394-1407 at HEAD6010125):If for any reason
show-ref --verify --quiet refs/heads/<new-branch>returned exit 0 even though the new branch didn't actually exist (stale ref-cache, parallel ref churn, packed-refs interaction), DMC would dispatch the no--bform against the new-branch-name positional, which git would interpret as "check out existing branch with that name" — but if the branch actually doesn't exist, the command would fail. So that path doesn't fully explain my observation either.A more defensive shape would be: regardless of which command DMC chose, after
run_git, verify the worktree HEAD actually matches$branchbefore reporting success and writing inventory rows. Suggested check (uses git plumbing, no extra deps):That converts a silent collision (which I hit, but cannot reproduce) into a loud, recoverable error — matches the rest of the staleness-gate behavior in the same function, where a half-cooked worktree gets torn down rather than returned.
Repro environment
intelligence-chubes4./Users/chubes/Developer, ~474 worktrees registered (above the 100-warning threshold), disk-budget statuswarning.chubes4/wc-site-generator, primary atstatic/spore-ledger-field-supply, source branchstatic/marbling-benchhad a local checkout 10 commits behindorigin/static/marbling-bench.6010125 fix: expose bounded cleanup-eligible apply path.Happy to instrument or rerun under different conditions if there's a code path you want me to push on.