Problem (umbrella issue — supersedes the two below)
.polyphony/ operational state (run.yaml, run.lock) currently lives at the worktree top-level, but the apex-driver fans out work across multiple worktrees off the same root branch. This creates two coupled bugs:
Sub-bug A: RunLockPathResolver resolves to worktree top, not git common-dir
RunLockPathResolver.ResolveAsync calls IGitClient.GetTopLevelAsync(), which returns the worktree top-level — meaning each worktree gets its own lock and the same root can be acquired N times concurrently. The lock provides no actual protection under fanout.
Sub-bug B: Manifest write-coordination under worktree fanout
RunManifest at .polyphony/run.yaml is worktree-local until merged. Today writes serialize through feature/{root_id} so works-in-flight don't clobber each other, but this is implicit and easily broken.
Proposed structural fix
- Site shared ops state at
<git-common-dir>/polyphony/<root_id>/. (git rev-parse --git-common-dir returns the shared .git even from a worktree.)
- Add an OS-level file lock (
fcntl.flock on Linux/macOS, LockFileEx on Windows) on the manifest path.
- Migrate
RunLockPathResolver and RunManifest to the new location simultaneously.
This collapses two sub-bugs into one structural change.
References
Subsumed scope
This issue intentionally subsumes:
- "Fix RunLockPathResolver to use git common-dir not worktree top-level"
- "Decide manifest write-coordination story under worktree fanout"
Track those as two checkboxes inside this issue rather than as separate filings — the structural fix is one PR.
Problem (umbrella issue — supersedes the two below)
.polyphony/operational state (run.yaml,run.lock) currently lives at the worktree top-level, but the apex-driver fans out work across multiple worktrees off the same root branch. This creates two coupled bugs:Sub-bug A:
RunLockPathResolverresolves to worktree top, not git common-dirRunLockPathResolver.ResolveAsynccallsIGitClient.GetTopLevelAsync(), which returns the worktree top-level — meaning each worktree gets its own lock and the same root can be acquired N times concurrently. The lock provides no actual protection under fanout.Sub-bug B: Manifest write-coordination under worktree fanout
RunManifestat.polyphony/run.yamlis worktree-local until merged. Today writes serialize throughfeature/{root_id}so works-in-flight don't clobber each other, but this is implicit and easily broken.Proposed structural fix
<git-common-dir>/polyphony/<root_id>/. (git rev-parse --git-common-dirreturns the shared.giteven from a worktree.)fcntl.flockon Linux/macOS,LockFileExon Windows) on the manifest path.RunLockPathResolverandRunManifestto the new location simultaneously.This collapses two sub-bugs into one structural change.
References
.polyphonyops state is per-root, gitignored, never trackedSubsumed scope
This issue intentionally subsumes:
Track those as two checkboxes inside this issue rather than as separate filings — the structural fix is one PR.