Background
PR #10 introduced a saveLocks: Map<string, Promise<void>> mutex in persistence.ts (used by upsertEntry and removeEntry) to serialize concurrent writes per cwd. The key is the raw cwd string. Two callers passing /repo and /repo/ get distinct mutex entries, defeating serialization for the same physical path.
Flagged during the six-pass adversarial review for #2 and accepted as a future improvement so we could land the worktree plugin.
Fix
Normalize the lock key via path.resolve(cwd) before lookup/insert. resolve('/repo') and resolve('/repo/') both return /repo on POSIX, and standardize Windows separators.
import { resolve as pathResolve } from 'node:path';
// inside upsertEntry/removeEntry:
const key = pathResolve(cwd);
const prev = saveLocks.get(key) ?? Promise.resolve();
// ...
saveLocks.set(key, prev.then(() => next));
// ...
if (saveLocks.get(key) === next) saveLocks.delete(key);
Apply consistently to all saveLocks.get/set/delete call sites.
Acceptance criteria
Out of scope
- Cross-process locking (this is in-process only by design)
- Symlink resolution beyond
path.resolve defaults
Related
PR #10 (worktree plugin foundation), Fixes #2 closed.
Background
PR #10 introduced a
saveLocks: Map<string, Promise<void>>mutex inpersistence.ts(used byupsertEntryandremoveEntry) to serialize concurrent writes percwd. The key is the rawcwdstring. Two callers passing/repoand/repo/get distinct mutex entries, defeating serialization for the same physical path.Flagged during the six-pass adversarial review for #2 and accepted as a future improvement so we could land the worktree plugin.
Fix
Normalize the lock key via
path.resolve(cwd)before lookup/insert.resolve('/repo')andresolve('/repo/')both return/repoon POSIX, and standardize Windows separators.Apply consistently to all
saveLocks.get/set/deletecall sites.Acceptance criteria
saveLocksaccesses usepath.resolve(cwd)as the keyupsertEntrycalls usingtestDirandtestDir + '/'(ortestDir.slice(0, -1)) both succeed and both entries land inworktrees.jsonOut of scope
path.resolvedefaultsRelated
PR #10 (worktree plugin foundation), Fixes #2 closed.