fix(run): serialize concurrent provisioning (kill worktree-metadata race)#13
Merged
Conversation
…data race Two agents starting a session on the SAME repo at once could fail to provision: git's `worktree add` — and, it turns out, the `git config --worktree` hooks wiring — both scan the shared worktree list, and either can read a SIBLING's half-written admin metadata and fatal (`failed to read .git/worktrees/<other>/commondir`). This is what made `delta2_concurrent...` flaky and flaked the 0.2.0 release pipeline once. Path to the fix (design reviewed with fugu): - A selective retry of `worktree add` was tried first, but `-b` had already created the branch before the transient failure, so a retry then hit `branch already exists` — retrying a non-atomic op means fighting its partial state. (fugu's design (c) warned of exactly this.) - Escalated to fugu's design (d): a per-source-repo advisory `flock` under the home (never inside `.git`, keyed by an FNV-1a of the repo path), auto-released on fd close so a crashed holder never wedges it. Best-effort — a lock-setup failure proceeds unserialized rather than blocking a session. - A high-pressure probe then caught the SAME race in `configure_worktree_hooks` (`git config --worktree` reads worktree metadata too), so the lock covers the WHOLE provisioning critical section — add + hooks wiring — and is released before the (long-lived) agent spawns so sessions don't serialize. Windows (unverified) has no cross-process lock and proceeds unserialized. Verified: a direct concurrency probe (16 concurrent first-runs × 100 rounds = 1600 launches, plus 960 more at the pressure that previously produced 5 failures) is now 0 failures; the `concurrent_worktree_provision_stress` test (12-way) and `delta2` guard it. Full workspace suite green, clippy clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
suzuke
added a commit
that referenced
this pull request
Jul 5, 2026
Bumps the shim to 0.2.1 for the concurrent-provisioning fix (#13): a per-source-repo advisory flock serializes the worktree-metadata-touching provisioning (worktree add + `config --worktree` hooks), so two agents starting a session on the same repo at once no longer fatal on a sibling's half-written worktree metadata. agentic-git-core stays 0.1.0 (unchanged). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two agents starting a session on the same repo at once could fail to provision. Git's
worktree add— and, it turns out, thegit config --worktreehooks wiring — both scan the shared worktree list, and either can read a sibling's half-written admin metadata and fatal (failed to read .git/worktrees/<other>/commondir). This madedelta2_concurrent_first_runs_race_key_both_bindings_verifyflaky and flaked the 0.2.0 release pipeline once.Path to the fix (design reviewed with fugu)
worktree add— tried first, but-bhad already created the branch before the transient failure, so the retry hitbranch already exists. Retrying a non-atomic op means fighting its partial state (fugu's design point (c) predicted exactly this).flockunder the home (never inside.git; keyed by an FNV-1a of the repo path). Auto-released on fd close, so a crashed holder never wedges it. Best-effort — a lock-setup failure proceeds unserialized rather than blocking a session.configure_worktree_hooks, so the lock now covers the whole provisioning critical section (add + hooks wiring) and is released before the long-lived agent spawns so concurrent sessions serialize only their provisioning, not their whole run.Windows (unverified) has no cross-process lock and proceeds unserialized.
Verification
A direct concurrency probe — 16 concurrent first-runs × 100 rounds = 1600 launches, plus 960 more at the exact pressure that previously produced 5 failures — is now 0 failures. Regression guards:
concurrent_worktree_provision_stress(12-way) +delta2. Full workspace suite green,clippy -D warningsclean.🤖 Generated with Claude Code