Skip to content

feat(review-fix-loop): implement reviewer isolation and complete-review orchestration - #110

Merged
shaug merged 7 commits into
mainfrom
claude/98-review-fix-loop-reviewer-orchestration
Jul 31, 2026
Merged

feat(review-fix-loop): implement reviewer isolation and complete-review orchestration#110
shaug merged 7 commits into
mainfrom
claude/98-review-fix-loop-reviewer-orchestration

Conversation

@shaug

@shaug shaug commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

Implements complete-review orchestration for review-fix-loop, with fresh
read-only reviewer subagents by default and an explicit in-agent override —
the "reviewer isolation and complete-review orchestration" child of epic
#95, building on the merged contract leaf (#96) and the merged local
execution substrate (#97).

  • scripts/reviewer_orchestration.py (dependency-free, bundles the canonical
    review-suite contract and review_gate.py, kept in sync via
    just sync-contracts):
    • resolve_review_lenses() — the fixed, non-selectable lens set a
      complete review must cover.
    • resolve_review_execution_mode()fresh_subagent by default, an
      explicit in_agent_override only when authorized, missing_capability
      with no automatic fallback when a host can't spawn a fresh context.
    • evaluate_review_result() — rejects an incomplete or misbound raw
      review-code-change packet/result pair (lens completeness for clean,
      packet-evidence completeness for any verdict).
    • detect_worktree_mutation() — before/after snapshot comparison
      (head_sha, local refs excluding refs/remotes/*,
      tracked/staged/unstaged/untracked paths; ignored is captured but never
      compared, since authorized validation commands legitimately touch it),
      failing closed on an incomplete snapshot.
    • build_review_record() — builds one checkpoint-shaped review_records
      entry, forcing write_isolation: "violated" on any detected mutation so
      it fails that cycle closed.
    • normalize_findings() / select_next_finding() — deterministic finding
      ordering for later fix-cycle selection and checkpointing.
    • build_reviewer_briefing() / REVIEWER_PROHIBITIONS — the literal
      instruction text prohibiting worktree mutation and implementation that
      travels with every review pass.
  • references/reviewer-orchestration.md — the full behavioral contract this
    module implements, plus a documented blocked/reviewer_integrity_failure
    stop instruction for an attributable reviewer mutation.
  • skills/review-fix-loop/agents/claude-code.md and agents/openai.yaml
    new discovery adapters.
  • Extracted review_gate.evaluate_bound in canonical
    review-suite/scripts/review_gate.py (schema validation plus
    candidate/lens-execution binding, generalized to accept any verdict),
    reused unchanged by the existing evaluate_aggregate; added
    review-fix-loop to the review-suite/review_gate.py bundling loops so
    it shares the same drift-tested contract copies as implement-ticket and
    babysit-pr.
  • Updated SKILL.md additively (frontmatter tool grants, a new "Run a
    complete review" section, narrowed non-goals) and CHANGELOG.md.
  • 232 new/updated tests in
    skills/review-fix-loop/scripts/tests/test_reviewer_orchestration.py and
    the bundled test_review_gate.py.

Non-goals (explicitly out of scope, per design)

Test plan

  • python3 -m unittest discover -s skills/review-fix-loop/scripts/tests -p 'test_*.py' — 232 tests pass
  • just test — all skill suites and review-suite/scripts/tests (318 tests) pass
  • just lint — ruff, mdformat, skills-ref validate (all 9 skills), plugin packaging validation pass
  • just format — no diffs
  • Repository-owned review-code-change review: clean aggregate at head fd690248670c6acecfb2d335e70e347d4d4390desolution_simplicity, correctness, and code_simplicity all fresh and clean for this exact head/base (7 review cycles; earlier cycles found and fixed refs-mutation detection gaps, a contract-legal blocked-result rejection, duplicated binding logic, an ignored-worktree false-positive, fail-open snapshot validation, a dead packet-less evaluator path, a rebase-introduced changelog SHA issue, and doc/test verbosity — all resolved)

Refs #98

shaug added 7 commits July 30, 2026 18:42
…ew orchestration

- Add `scripts/reviewer_orchestration.py`: fixed lens resolution, rejection of
  an incomplete/misbound review-code-change result (both a lens-completeness
  check via `evaluate_review_result` and a packet-evidence check via
  `evaluate_review_pair`), default fresh-subagent review-execution resolution
  with an explicit in-agent override and no automatic fallback, reviewer
  identity generation, before/after worktree mutation detection, checkpoint-
  shaped review-record construction that fails a cycle closed on any detected
  mutation, and deterministic finding normalization/selection.
- Add `references/reviewer-orchestration.md`, implementing design's "Review
  execution" and "Reviewer write prevention" sections and workflow step 3.
- Bundle the canonical review-suite contract into
  `references/review-suite/` (added review-fix-loop to `just sync-contracts`
  and to `review-suite/scripts/tests/test_bundled_contracts.py`'s
  `BUNDLING_SKILLS`), matching every other review-code-change consumer.
- Update `SKILL.md` (frontmatter tool grants, description, a new "Run a
  complete review" section, and the non-goals list) and add `agents/
  claude-code.md`/`agents/openai.yaml` adapters, mirroring review-code-change
  and implement-ticket's conventions.
- Add `scripts/tests/test_reviewer_orchestration.py` (52 new tests).

- Issue #98 (child of epic #95): reviewer isolation and complete-review
  orchestration is the next rollout step after the merged contract leaf
  (#96), and is required before either fix-cycle child (#99 local_commit,
  #100 update_pr) can run a trustworthy review.

Refs #98
## Summary
- `detect_worktree_mutation` now compares local `refs` (excluding
  `refs/remotes/*`) between before/after snapshots, not only `head_sha` and
  the tracked/staged/unstaged/untracked/ignored path lists — a reviewer that
  runs `git stash` or force-moves a branch without touching HEAD or any
  tracked path is now caught.
- `evaluate_review_pair` no longer rejects a contract-legal `blocked` result
  that omits candidate identity already present in the packet (it stopped
  reusing the bundled `validate_pair`'s stricter packet/result identity
  check for that reason); it now additionally binds the *packet's own*
  candidate identity to the current cycle's expected head/base directly.
- Extracted canonical `review_gate.evaluate_bound` (schema validation plus
  candidate/lens-execution binding, generalized to accept any verdict) in
  `review-suite/scripts/review_gate.py`, reused by `evaluate_aggregate`
  unchanged; `reviewer_orchestration.py` now delegates to it instead of a
  second, independently-maintained binding implementation. Added
  `review-fix-loop` to the `review_gate.py`/`test_review_gate.py` bundling
  loop (`just sync-contracts`, `GATE_BUNDLING_SKILLS`), matching
  `implement-ticket`/`babysit-pr`.
- Updated `SKILL.md` and `references/reviewer-orchestration.md` to match:
  refs capture, preferring `evaluate_review_pair` (packet-bearing) over
  `evaluate_review_result`, and the shared `review_gate` dependency.

## Why
- First review-code-change pass on #98 found: refs-only mutation went
  undetected (acceptance criterion 6 unproven for that class), a
  contract-legal blocked result was rejected on the packet-bearing path
  (SKILL.md's own recommended path), and the binding logic duplicated the
  canonical, drift-tested `review_gate` implementation used by two other
  consumers.

Refs #98
… incomplete snapshots, collapse dual evaluators

- `detect_worktree_mutation` no longer compares `ignored` worktree state
  (still required to be captured, per design, via `REQUIRED_SNAPSHOT_KEYS`,
  but never compared): authorized recorded validation commands legitimately
  create or change ignored build artifacts (`__pycache__/`, `.ruff_cache/`,
  `.venv/`), so comparing it made every review pass that ran validation
  falsely report a mutation and made `converged` permanently unreachable.
- `detect_worktree_mutation` now raises `ValueError` when either snapshot is
  missing a required capture key (`head_sha`, `refs`, or any worktree
  category), instead of silently treating an uncaptured dimension as
  unchanged.
- Collapsed the packet-less `evaluate_review_result(result, ...)` path into
  the single mandatory `evaluate_review_result(packet, result, ...)`:
  review-fix-loop's own checkpoint/terminal-result contract never persists a
  raw packet or raw result without the other, so the weaker path had no
  legitimate caller and could otherwise let a `clean` verdict with
  actually-failed packet validation slip through by omission.
  `build_review_record`'s `packet` parameter is now required accordingly.
- Backfilled the two prior commits' SHAs into the changelog and removed a
  fabricated changelog entry from the prior fix-cycle commit.

- Second review-code-change pass on #98 found: the `ignored`-comparison
  defect made `converged` unreachable in this repository's own worktree
  (every validation command run creates `__pycache__/`); a mutation-detection
  function silently passing on missing capture keys defeats the point of
  requiring the capture; and the packet-less evaluator path was unreachable
  by any real caller and duplicated the packet-plus-result path's logic.

Refs #98
…ng prose

## Summary
- Removed a byte-identical duplicate test
  (`test_changes_required_with_partial_lens_executions_is_still_accepted`
  duplicated `test_current_changes_required_with_partial_lens_executions_is_accepted`).
- Trimmed `evaluate_review_result`'s docstring and the `COMPARED_WORKTREE_CATEGORIES`
  module comment to state current behavior once instead of narrating a removed
  earlier revision and repeating the `ignored`-is-captured-but-uncompared
  rationale in full three times; the Python module comment and
  `detect_worktree_mutation`'s docstring now point to
  `references/reviewer-orchestration.md`'s "Reviewer write prevention" tier 4
  as the one full explanation.

## Why
- Third review-code-change pass on #98 (code-simplicity lens): a duplicate
  test and history-narrating/triplicated rationale prose (0.50 docstring/
  comment density vs. 0.11-0.12 for sibling `validate.py` modules) with no
  behavioral change needed.

Refs #98
…ngelog SHA

## Summary
- Rebased onto origin/main (now including the merged #97 local-execution
  substrate at 26b4cf4), resolving conflicts in `CHANGELOG.md` and
  `SKILL.md` by combining both children's content.
- Documented that a mutation attributable to a review pass must stop the
  invocation immediately with `blocked/reviewer_integrity_failure`, rather
  than relying solely on the `write_isolation: "violated"` /
  `_check_converged_requires_clean_evidence` backstop to catch it later.
  Design assigns this judgment to "the phase that observed it" — this is
  that phase's explicit routing instruction, in both
  `references/reviewer-orchestration.md` and `SKILL.md`.
- Corrected a changelog SHA left stale by the rebase (a rebased commit's own
  hash changes, so a prior cycle's backfilled SHA referencing the
  pre-rebase hash was wrong).
- Confirmed (no code change) that the review_gate.evaluate_bound extraction
  from cycle 1 is the deliberate design going forward: correctness verified
  it changes no accept/reject outcome for implement-ticket/babysit-pr.

## Why
- Fourth review-code-change pass on #98: sibling ticket #97 merged to main
  mid-review, requiring a rebase; the same pass also found the mutation-stop
  routing was implicit rather than explicit, and that the rebase itself
  introduced a stale changelog SHA.

Refs #98
## Summary
- The previous fix cycle's rebase cleanup left two adjacent changelog
  entries carrying each other's SHA: the "remove a byte-identical duplicate
  test" entry (commit 7663b2c) was stamped with the next, older commit's
  hash, and the "stop comparing ignored worktree state" entry (commit
  18991dd) carried no SHA at all. Corrected both.

## Why
- Fifth review-code-change pass on #98 found the off-by-one; a two-token
  attribution correction with no code, test, or schema impact.

Refs #98
… tests

## Summary
- Removed three subsumed/redundant tests:
  `test_override_is_honored_even_when_fresh_subagent_would_be_available`
  (strict subset of `test_explicit_override_is_honored_and_recorded`),
  `test_different_sequence_yields_a_different_identity` (entailed by
  `test_default_identity_matches_example_convention`, which already pins
  both exact values), and `test_identical_refs_report_no_mutation`
  (identical to `test_identical_snapshots_report_no_mutation` once `refs`
  is part of the shared `CLEAN_STATE` fixture).
- Cut `reviewer_orchestration.py`'s docstring/comment prose from roughly
  parity with its own code length down to sibling-module levels: every
  function docstring now states its rationale once, briefly, and points to
  `references/reviewer-orchestration.md` for the full explanation instead
  of restating it (previously repeated across the module docstring, inline
  comments, and multiple function docstrings, including one circular
  in-file pointer pair).

## Why
- Sixth review-code-change pass on #98 (code_simplicity, run for the first
  time since the rebase onto #97): both findings were test/documentation
  hygiene only, no behavioral change.

Refs #98
@shaug
shaug merged commit 8ef6db1 into main Jul 31, 2026
1 check passed
@shaug
shaug deleted the claude/98-review-fix-loop-reviewer-orchestration branch July 31, 2026 04:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant