Skip to content

fix(run): serialize concurrent provisioning (kill worktree-metadata race)#13

Merged
suzuke merged 1 commit into
mainfrom
fix/concurrent-worktree-add-race
Jul 5, 2026
Merged

fix(run): serialize concurrent provisioning (kill worktree-metadata race)#13
suzuke merged 1 commit into
mainfrom
fix/concurrent-worktree-add-race

Conversation

@suzuke

@suzuke suzuke commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Problem

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 made delta2_concurrent_first_runs_race_key_both_bindings_verify flaky and flaked the 0.2.0 release pipeline once.

Path to the fix (design reviewed with fugu)

  1. Selective retry of worktree add — tried first, but -b had already created the branch before the transient failure, so the retry hit branch already exists. Retrying a non-atomic op means fighting its partial state (fugu's design point (c) predicted exactly this).
  2. Escalated to fugu's (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.
  3. A high-pressure probe then caught the same race in 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 warnings clean.

🤖 Generated with Claude Code

…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 suzuke merged commit ddc1319 into main Jul 5, 2026
3 of 4 checks passed
@suzuke suzuke mentioned this pull request Jul 5, 2026
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>
@suzuke suzuke deleted the fix/concurrent-worktree-add-race branch July 10, 2026 05:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant