Skip to content

fix(code-review-gate): give the headless and user lanes the root's range - #234

Merged
ultimatile merged 2 commits into
mainfrom
fix/229-code-review-gate-range
Sep 30, 2026
Merged

ultimatile merged 2 commits into
mainfrom
fix/229-code-review-gate-range

Conversation

@ultimatile

Copy link
Copy Markdown
Owner

Summary

code-review-gate ran Claude Code's built-in /code-review in its headless lane (Lane 1) and its user-run lane (Lane 2) with an effort level and nothing else, so the built-in chose its own base. It reaches for @{upstream}...HEAD first; once the branch is pushed that range is empty, and it then reviews against the default branch or reviews the working tree alone. The gate held the root, the branch the work merges into, but used it only to keep those two lanes to runs whose root is the default branch, which ruled out one wrong base without supplying the right one. Both lanes now pass the root's range, so the base no longer depends on what the reviewer infers.

Closes #229

Changes

  • The gate scope is defined once: the branch's committed diff against the root (git diff <root-rev>...HEAD, where <root-rev> is origin/<root> for a branch root, after a fetch of the root), plus uncommitted changes, plus untracked files. The subagent lane (Lane 3) is handed it by reference.
  • Lane 1 runs claude -p --model opus "/code-review <effort> <root-rev>...HEAD" --output-format text, and Lane 2 asks the user to run /code-review <effort> <root-rev>...HEAD.
  • The chain is Lanes 1, 2, 3 for every root, except that while the gate scope has untracked files it is Lane 3 alone. Lanes 1 and 2 are then neither entered nor abandoned, so they return on an iteration with nothing untracked.
  • When the gate scope is empty, the gate halts before any lane and tells the user so. This is neither a lane failure nor exhaustion, so no reviewer is ever handed an empty range whose (none) would read as a clean pass.

Verification

Each run below is claude -p --model opus "/code-review <effort> <target>" --output-format text in a scratch repository whose root and branch were pushed to a bare origin:

  • A branch cut from an integration branch int carrying its own planted bug, target origin/int...HEAD: at low and again at medium the review reported only the branch's own bug. The same repository with no target reported both bugs.
  • Planted bugs in a committed file, an uncommitted edit, and an untracked file, target origin/main...HEAD: two low runs and one medium run each reported the committed and uncommitted bugs. The untracked bug was reported in one low run; the medium run named it but did not report it, stating the file was untracked and outside the diff. With no target, the committed bug was missed, since the pushed branch left @{upstream}...HEAD empty.
  • Only an untracked file changed, target origin/main...HEAD: two medium runs each reported its bug.
  • A correct change, target origin/main...HEAD: the output was (none) alone, without naming the range read.

pre-commit (mdformat) passed on skills/code-review-gate/SKILL.md and .claude-plugin/marketplace.json.

Notes

  • Output validity is unchanged: a review is not required to name the range it read, because a genuine clean pass can be (none) alone.
  • Lanes 1 and 2 now also run for work whose root is not the default branch. Each such run draws on the headless session, or on the user.

The headless and user-run lanes invoked /code-review with an effort
level only, so the built-in picked its own base. It tries
@{upstream}...HEAD first; once the branch is pushed that range is
empty, and it either falls back to the default branch or reviews the
working tree alone, missing the branch's committed work. The gate held
the root but used it only to restrict those lanes to default-branch
roots, which excluded one wrong base without supplying the right one.

Both lanes now append <root-rev>...HEAD, which the built-in honors: a
branch cut from an integration branch is reviewed without that
branch's commits. With the base supplied, the chain is the same three
lanes for every root.

The gate scope - the committed range, uncommitted changes, and
untracked files - is now defined once and handed to the subagent lane
by reference. When all three are empty the gate halts before any lane,
so an empty range never reaches a reviewer whose "(none)" would pass
as a clean review.

Closes #229
Given a range alongside a non-empty committed diff, the built-in
reviews the range and the uncommitted changes but can leave untracked
files out of its findings, stating they are outside the diff. The
subagent lane reads untracked contents explicitly, so while untracked
files exist the chain is that lane alone; the other two lanes are
neither entered nor abandoned and return once nothing is untracked.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The Lane 1 command permits shell evaluation of metacharacters in a substituted root ref.

Review effort: Balanced
Findings: 1 High severity

Open (1)
What changed in this PR

Updates code-review-gate so every review lane uses the caller-supplied diff root.

Changes:

  • Defines gate scope and empty-scope handling.
  • Passes <root-rev>...HEAD to review lanes.
  • Bumps the plugin version.
File Description
skills/​code-review-gate/​SKILL.md Revises review scope and lane selection.
.claude-plugin/​marketplace.json Bumps version to 2026.9.9.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread skills/code-review-gate/SKILL.md
@ultimatile
ultimatile merged commit 49ef1f3 into main Sep 30, 2026
1 check passed
@ultimatile
ultimatile deleted the fix/229-code-review-gate-range branch September 30, 2026 05:37
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.

code-review-gate: two lanes leave the review base to the reviewer

2 participants