feat(review-fix-loop): implement local locking, isolated attempts, and recovery - #109
Merged
Merged
Conversation
…d recovery ## Summary - Add `skills/review-fix-loop/scripts/local_execution.py`, a dependency-free module implementing the local execution substrate design/review-fix-loop.md describes in "Local ownership and checkpointing": non-blocking common-Git-common-directory candidate locking (local-ref lock before the optional `update_pr` remote-target lock, released in reverse order), isolated attempt worktrees created from the exact canonical head, verified fast-forward-only canonical promotion that fails closed on a dirty or advanced canonical worktree, atomic schema-validated checkpoint persistence and resume reconciliation, preserved failed-attempt artifacts, namespace-safe cleanup, and recovery of an interrupted attempt against a checkpoint's own history. - Loads `scripts/validate.py` (the #96 contract leaf) via `importlib` instead of duplicating any schema or cross-field check, per this ticket's dependency to build on the merged contracts leaf. - Add `skills/review-fix-loop/scripts/tests/test_local_execution.py`: 41 deterministic unit tests against real temporary Git repositories covering lock contention (including cross-policy and shared-PR-ref contention, and kernel-driven release when the holding descriptor closes), checkpoint atomicity/round-trip/resume reconciliation, isolated-attempt creation and commit, promotion success and every fail-closed path (dirty canonical, advanced canonical, wrong branch), discard/cleanup safety (refusing to touch anything outside the `review-fix-loop/attempt/` namespace), and interrupted- attempt recovery including ambiguous-state rejection. - Update `skills/review-fix-loop/SKILL.md` additively: describe the new local execution module and narrow the remaining non-goals to what issues #98–#100 still own (running a reviewer, selecting/writing a fix's content, publishing). - Record the change in `CHANGELOG.md`, backfilling the prior entry's SHA per this repository's changelog convention. ## Why - Issue #97 (child of epic #95) requires the local execution substrate so later children (#98 reviewer isolation, #99 `local_commit`, #100 `update_pr`) can build the complete review-fix loop on top of a safe, tested Git-native foundation rather than each reimplementing locking, attempt isolation, and recovery independently. ## Acceptance criteria - Conflicting local invocations cannot both own the same target: non-blocking `flock`-backed locks keyed by common directory and ref. - Lock ordering avoids self-induced deadlocks for multi-target `update_pr` work: acquisition never blocks, so no invocation can wait on another. - Attempts occur outside the canonical worktree and leave it unchanged until promotion: `create_attempt` uses `git worktree add` into a dedicated path and branch. - Interrupted attempts can be recovered or reported without losing commits: `recover_interrupted_attempts` reconciles leftover attempt branches against checkpoint history. - Dirty or advanced canonical state fails closed and preserves the candidate: `promote_attempt` verifies cleanliness and expected head before any merge. - Cleanup never deletes user-owned work or reference branches: `cleanup_attempt` refuses any branch outside the `review-fix-loop/attempt/` namespace. ## Validation - `python3 -m unittest discover -s skills/review-fix-loop/scripts/tests -p 'test_*.py'` — 154 tests, OK (run 3x for flake-freedom) - `just test` — all skill and review-suite test suites pass (571 tests total) - `just format` — all checks pass, no diffs beyond this change - `just lint` — `lint-py`, `lint-md`, `lint-skills` (skills-ref validate), and `validate-plugins` all pass
This was referenced Jul 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the local execution substrate
review-fix-loopneeds before anycaller can run an end-to-end loop: common-Git-common-directory locking,
isolated attempt worktrees, durable checkpoint persistence and resume
reconciliation, verified fast-forward-only canonical promotion, and recovery
of an interrupted attempt.
skills/review-fix-loop/scripts/local_execution.py(dependency-free,loads the merged
scripts/validate.pycontract leaf viaimportlibratherthan duplicating any schema or cross-field check):
acquire_candidate_locks— non-blocking, common-directory-keyed local-reflock plus the optional
update_prremote-target lock, acquired in thatfixed order and released in reverse; every acquisition fails fast rather
than waiting, so no invocation can ever form a circular wait.
create_attempt/commit_attempt— isolatedgit worktree-basedremediation attempts created from the exact canonical head, entirely
outside the canonical worktree and branch.
promote_attempt— verified fast-forward-only canonical promotion:checks the canonical worktree is clean and at the expected old head and
that the attempt's parent matches before merging, and verifies the
resulting HEAD/tree/cleanliness afterward. Any failure leaves canonical
state exactly as it was.
discard_attempt/cleanup_attempt— preserves a failed attempt's patchand reason for operator inspection; cleanup refuses to touch anything
outside the
review-fix-loop/attempt/branch namespace it creates.write_checkpoint_atomic/read_checkpoint/reconcile_checkpoint_for_resume— atomic, schema-validated checkpointpersistence and the complete design-required resume precondition set (no
active lock holder, matching cross-document identity via Define review-fix-loop invocation, checkpoint, and terminal-result contracts #96's own
validator, a clean candidate, live head/base agreement).
recover_interrupted_attempts— reconciles attempt branches aninterrupted invocation left behind against a checkpoint's own history,
returning each uniquely identifiable leftover and raising rather than
guessing when reconciliation is ambiguous.
skills/review-fix-loop/scripts/tests/test_local_execution.py: 41deterministic tests against real temporary Git repositories (no mocked Git
state) covering lock contention (same-ref, cross-policy, shared remote
target, cross-linked-worktree), kernel-driven lock release, checkpoint
atomicity/round-trip/resume reconciliation and every resume-rejection path,
isolated attempt creation/commit, promotion success and every fail-closed
path (dirty canonical, advanced canonical, wrong branch), discard/cleanup
safety, and interrupted-attempt recovery including ambiguous-state
rejection.
skills/review-fix-loop/SKILL.mdadditively: document the newmodule and narrow the remaining non-goals to what issues Implement review-fix-loop reviewer isolation and complete-review orchestration #98–Deliver and evaluate review-fix-loop update_pr #100 still
own (running a reviewer, selecting/writing a fix's content, publishing).
CHANGELOG.md.Why
Issue #97 (child of epic #95, blocked by the now-merged contract leaf #96)
requires this substrate so later children (#98 reviewer isolation, #99
local_commit, #100update_pr) can assemble the complete review-fix loopon a tested, Git-native foundation instead of each reimplementing locking,
attempt isolation, and recovery independently. Per the epic's design
(
design/review-fix-loop.md, "Local ownership and checkpointing"), thiscovers Workflow steps 1 (acquire the lock before any mutation), 6 (validate,
commit, and promote or preserve on failure), and 9 (checkpoint, release,
return).
Non-goals (unchanged, per ticket)
does not touch reviewer-orchestration code.
remote-target lock, not the
update_prpush itself.Acceptance criteria (all pre-merge)
non-blocking
flock-backed lock keyed by common directory and ref.update_prwork — acquisition never blocks, so no invocation can waiton another.
until promotion —
create_attemptusesgit worktree addinto adedicated path and branch.
commits —
recover_interrupted_attempts.candidate —
promote_attempt's precondition checks.cleanup_attemptrefuses any branch outside thereview-fix-loop/attempt/namespace.Validation
Review
A fresh, read-only
review-code-changepass (independent agent, raw evidenceonly — no implementation transcript) returned aggregate verdict clean
(solution-simplicity, correctness, code-simplicity all clean) against this
exact head. One
defer-severity, non-gating correctness observation wasrecorded and intentionally not acted on: this module does not itself reread
the comparison-base ref during a live remediation cycle (only at resume,
via
reconcile_checkpoint_for_resume); the reviewer agreed this iscorrectly out of this ticket's scope, since driving repeated remediation
cycles and rebuilding review evidence after base drift requires the reviewer
orchestration this ticket's non-goals explicitly exclude (issue #98). Noted
here for whichever child assembles the full loop.
Refs #97
Supports #95