refactor(locks): route with-scoped lock opens through open_lock_file (#9267) - #9647
Conversation
…9267) Migrate the four with-scoped copies of the non-truncating lock-open preamble onto platform_compat.open_lock_file (merged in #9316): session_pid._session_pid_file_lock, session_pid._pid_file_lock, webhooks.locked, and mcp_tools.control.register_hook. Each site keeps its own parent mkdir (the helper does not create dirs), drops its touch + "r+" preamble, and replaces its rationale comment with a one-line pointer to the helper docstring, which now holds the reasoning once. Deliberately left inline, each with a pointer comment stating why: - work_ledger._open_lock: PR #9374 (open, MERGEABLE) edits the same file; it follows after that lands so two of my PRs do not chain on one file. - _McpFileLock / _McpFileLockSync: acquire-now/release-later fd stored on self._fd, so it must outlive __aenter__/__enter__; the with-scoped helper would close it at method return. - session_pid._periodic_pid_sweep: takes a SHARED read lock; the helper serves exclusive with-scoped acquisition only. The repo-wide contract scan (test_no_lock_site_opens_truncating) already guarantees every site opens non-truncating, so what is left here is deduplication, not a bug fix. ## Pattern harvest A duplication issue's stated copy count is a lower bound, and the SHAPES hiding inside it decide whether consolidation is even possible. #9267 named four copies; inspection found seven open-sites across three shapes (with-scoped, acquire-later, shared-read), and the shared helper serves only one, so five sites could never collapse onto it regardless of who tried. Rule candidate: when consolidating N hand-rolled copies of an idiom, first enumerate the copies by GREP (the stated count is a floor) and classify each by the calling shape it needs (lifetime of the resource, exclusive vs shared acquire). Migrate only the shape the shared helper serves; leave the others inline with a pointer comment naming the shape mismatch, and put the coverage gap on the issue rather than widening the helper to fit every shape. Refs #9267
Design Review (Fable 5) — ✅ PASSDesign-level review of The helper yields a raw int fd, matching the migrated call sites that dropped Design-Verdict: PASS Root-cause consolidation at the right layer, with disciplined restraint about which shapes the helper actually serves — no design-level concerns. [DESIGN-REVIEWED] 25e0bde |
Opus 4.8 Review — ✅ no blocking findingsReviewed Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
First Principles Review (Fable 5) — 🟡 CONCERNSPremise-level review of All evidence gathered. Composing the review. First-Principles-Verdict: CONCERNS "Seven open-sites" is the tree's lower bound, not its census: ~28 sibling lock-file Not justified as shippedAll inventory items are justified; the concern is the census the description rests on, not any shipped item — see Watch. What this change shipsInventory (7 items) — 7 justifiedIntent: remove the duplicated non-truncating lock-open preamble by routing sites through the existing
Watch
Subtractions
[FIRST-PRINCIPLES-REVIEWED] 25e0bde |
GPT 5.6 Review — ✅ no blocking findingsGPT 5.6 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
NicholasRBowers
left a comment
There was a problem hiding this comment.
Tier 1 auto-approve: refactor (5 files). Criteria: no conflict, no requested changes, security path denylist clean, design-doc gate clean, SAST annotations clean, security checklist all-NO, AI reviewers green. Category: code-move-only refactor routing with-scoped lock opens through the existing platform_compat.open_lock_file helper, no behaviour change.
Two comment-only fixes to the sites #9647 left inline: - session_pid._periodic_pid_sweep: delete the false clause claiming the with-scoped helper "serves exclusive acquisition only". open_lock_file only OPENS non-truncating; the lock mode is chosen at file_lock(fd, exclusive=...), and this sweep acquires shared read twelve lines below. The real reason it stays inline is fd lifetime -- the fd is held across the try/finally, not a `with` block -- which the original clause already stated; keep that, drop the added falsehood. - _McpFileLockSync.__enter__: shrink to a pointer at _McpFileLock above, whose kept-inline rationale already states the fd-lifetime reason fifty lines up. Repeating it is the duplication this item exists to reduce. No code change; the migrations #9647 landed are untouched. Refs #9267
What is the problem?
The non-truncating lock-open preamble (parent
mkdir, then open the lock fileWITHOUT truncating, then acquire) exists as hand-rolled copies in several places.
platform_compat.open_lock_filewas added in #9316 to hold that idiom once, butthe pre-existing copies were never migrated onto it, so the duplication #9267
describes is still in the tree.
Why this issue matters to the user
Duplicated preambles are how the
hooks.jsonpair drifted in the first place:two modules locking the SAME file, each with its own open, each carrying its own
rationale comment that a later edit can update in one place and miss in the other.
Every copy is a place a future edit can reintroduce the Windows lock-loss defect
(#9248) that the helper's
O_RDWR | O_CREATwas written to prevent.How our fix solves it
Symptom: four-plus hand-rolled copies of the preamble. Root cause: no shared entry
point, so each site open-codes it. Fix: route the sites the helper can actually
serve through
open_lock_file, and point the rest at it.Inspection found the "four copies" in #9267 are really seven open-sites across
three calling shapes, and the helper serves only one:
with) -- migrated onto the helper:session_pid._session_pid_file_lock,session_pid._pid_file_lock,webhooks.locked,mcp_tools.control.register_hook.self._fd, released in__aexit__/__exit__, so it must outlive the method) -- left inline with apointer comment:
dashboard/handlers/mcp.py::_McpFileLockand its sync sibling_McpFileLockSync. A yielding context manager would close the fd at methodreturn.
try_acquire_lock(exclusive=False)) -- left inline with apointer comment:
session_pid._periodic_pid_sweep. The helper serves exclusiveacquisition; forcing a shared lock through it would be a behaviour change dressed
as cleanup.
Each migrated site keeps its own
parent.mkdir(...)(the helper does not createparent dirs), drops its
touch+"r+"preamble, and replaces its rationalecomment with a one-line pointer to the helper docstring, which now holds the
reasoning once.
work_ledger._open_lockis deliberately excluded. PR #9374 is open,MERGEABLE, and edits
work_ledger.py. Consolidating there would chain two openPRs on the same file for no benefit a follow-up would not get, and a review change
on #9374 would cost a second rebase. Its canonical docstring stays as the pointer
target until it lands; migrating it is a clean follow-up afterward.
The gap that
open_lock_filecovers only the with-scoped exclusive shape isopen_lock_file's own design (jeeshofone, #9316); this PR does not extend thehelper and notes the gap on the issue instead.
What tests we did
test/test_platform_compat.py-- the repo-wide contract scantest_no_lock_site_opens_truncatingstill passes (275 passed).test/test_pid_lifecycle.py(172 passed),test/test_hooks_json_shared_file.py(15 passed),
test/test_webhooks_store.py(47 passed),test/test_mcp_core_coverage.pyincludingTestRegisterHook(164 passed).webhooks.locked) to a truncatingopen(lock_path, "w")turned the contract scan RED withwebhooks.py:192; thescan is load-bearing, not decorative. Restored, green again.
Any other suggestions on the work
The taxonomy is the finding: a duplication issue's stated copy count is a lower
bound, and the shapes hiding inside it decide whether consolidation is even
possible. Five of the seven sites here were never going to collapse onto the
shared helper regardless of who tried. Whoever owns
open_lock_filecan decidewhether to grow it toward the acquire-later and shared-read shapes; that is a
separate item.
Refs #9267