Observed behavior: The reconciliation lock is published by pathname before the journal parent is retained. A directory replacement after lock acquisition but before the execute callback can cause the callback to authenticate the replacement while its original lock remains in the displaced directory. Lock-release detection happens after callback writes.
Expected behavior: Bind the reconciliation lock publication and its later mutation callback to one authenticated directory identity, preserving secure first-use creation, normal contention, and cleanup semantics.
Root cause: reconcileWorktrees nests withProjectMapReconciliationLock(execute) inside withPrivateMutationLock(reconciliationLockPath(...)). The generic lock wrapper acquires the lock, invokes the callback, and validates release afterward without passing retained parent identity into the callback. This ordering predates PR #1126 and remains present on main parent a04b14137111ff4f3ff564c43fa20fb5f4959323.
How to reproduce safely: Use a private synthetic HOME and a deterministic filesystem seam between reconciliation-lock acquisition and the execute callback (during project-map lock acquisition/read). Rename the private reconciliations directory and create a private replacement; observe whether callback writes precede lock-release refusal. This report is based on static source/control-flow evidence; no live HOME, daemon, credentials, or production data was used and no runtime reproduction is claimed.
Scope and provenance: Separate pre-existing lock-to-directory binding boundary identified in review of #1059 / PR #1126 at 4530766408aad584b155042e6cf9f551765be69f: #1126 (comment). #1059 binds journal transitions after parent admission; its approved scope explicitly excluded pre-acquisition replacement and mutation-lock parent binding. This issue is not claimed fixed by that PR. It remains outside the campaign frozen inventory; no campaign parenting is requested.
Environment:
- Agent: Codex owner static review
- Connector: repository/GitHub review
- OS: Fedora Linux
Observed behavior: The reconciliation lock is published by pathname before the journal parent is retained. A directory replacement after lock acquisition but before the execute callback can cause the callback to authenticate the replacement while its original lock remains in the displaced directory. Lock-release detection happens after callback writes.
Expected behavior: Bind the reconciliation lock publication and its later mutation callback to one authenticated directory identity, preserving secure first-use creation, normal contention, and cleanup semantics.
Root cause:
reconcileWorktreesnestswithProjectMapReconciliationLock(execute)insidewithPrivateMutationLock(reconciliationLockPath(...)). The generic lock wrapper acquires the lock, invokes the callback, and validates release afterward without passing retained parent identity into the callback. This ordering predates PR #1126 and remains present on main parenta04b14137111ff4f3ff564c43fa20fb5f4959323.How to reproduce safely: Use a private synthetic HOME and a deterministic filesystem seam between reconciliation-lock acquisition and the execute callback (during project-map lock acquisition/read). Rename the private reconciliations directory and create a private replacement; observe whether callback writes precede lock-release refusal. This report is based on static source/control-flow evidence; no live HOME, daemon, credentials, or production data was used and no runtime reproduction is claimed.
Scope and provenance: Separate pre-existing lock-to-directory binding boundary identified in review of #1059 / PR #1126 at
4530766408aad584b155042e6cf9f551765be69f: #1126 (comment). #1059 binds journal transitions after parent admission; its approved scope explicitly excluded pre-acquisition replacement and mutation-lock parent binding. This issue is not claimed fixed by that PR. It remains outside the campaign frozen inventory; no campaign parenting is requested.Environment: