Skip to content

Optimize review: small-PR and incremental fast paths - #4

Merged
don-petry merged 3 commits into
mainfrom
review-optimizations
Apr 10, 2026
Merged

Optimize review: small-PR and incremental fast paths#4
don-petry merged 3 commits into
mainfrom
review-optimizations

Conversation

@don-petry

Copy link
Copy Markdown
Collaborator

Summary

  • Small PRs (<10 lines): single Opus call instead of full 3-member council (1 invocation vs 4)
  • Re-reviews (prior marker exists): single Opus call with prior review context, focused on delta
  • First review of non-small PRs: full council (unchanged)
  • New config: SMALL_PR_THRESHOLD repo variable (default 10)

Cost impact

  • Small docs PRs (like .github#101): ~1 min instead of ~5 min, 1 invocation instead of 4
  • Re-reviews after Claude fixes: ~1 min focused check instead of full re-analysis
  • Full council: unchanged for substantive first reviews

Test plan

  • Let the automation review and merge this PR
  • Verify mode detection in logs (mode: small|incremental|full)
  • Verify small PR uses single Opus path
  • Verify re-review after new commits uses incremental path

🤖 Generated with Claude Code

PRs are now routed to the cheapest review path:
- Small PRs (<10 lines): single Opus call (1 invocation vs 4)
- Re-reviews (prior marker at different SHA): single Opus call with
  prior review context, focused on what changed since last review
- First review of non-small PRs: full 3-member council (unchanged)

New files:
- prompts/single-review.md: combined council+synth prompt for single
  reviewer mode, handles both small and incremental paths

New config:
- SMALL_PR_THRESHOLD repo variable (default 10)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 10, 2026 11:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR optimizes the PR-review agent’s orchestration path to reduce cost/latency by using a single-reviewer “fast path” for small PRs and for re-reviews (when a prior review marker exists), while keeping the existing full 3-member council flow for first reviews of larger PRs.

Changes:

  • Add review-mode detection (small|incremental|full) in the per-PR orchestrator script and short-circuit to a single Opus invocation for non-full modes.
  • Introduce a new prompts/single-review.md prompt that combines council + synthesizer behavior into one agent for small/incremental reviews.
  • Document and wire up SMALL_PR_THRESHOLD as a workflow/repo variable.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
scripts/review-one-pr.sh Adds mode selection and a single-reviewer execution path before the existing council workflow.
prompts/single-review.md New prompt defining the single-reviewer behavior, including incremental re-review behavior using prior review context.
AGENT.md Updates documentation to describe the new optimized review modes and the new threshold variable.
.github/workflows/pr-review.yml Exposes SMALL_PR_THRESHOLD to the job environment with a default.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/review-one-pr.sh Outdated
Comment on lines +81 to +91
# - "small" : PR has < SMALL_PR_THRESHOLD lines changed → single Opus call
# - "incremental" : prior review exists at different SHA → single Opus call with prior context
# - "full" : first review of a non-small PR → 3-member council + synthesizer
SMALL_PR_THRESHOLD="${SMALL_PR_THRESHOLD:-10}"
PR_SIZE=$(gh pr view "$PR_URL" --json additions,deletions --jq '.additions + .deletions')
export PR_SIZE

if [ "$PR_SIZE" -lt "$SMALL_PR_THRESHOLD" ]; then
REVIEW_MODE="small"
elif [ -n "${EXISTING_MARKER_SHA:-}" ]; then
REVIEW_MODE="incremental"
Comment thread scripts/review-one-pr.sh Outdated
Comment on lines +84 to +90
SMALL_PR_THRESHOLD="${SMALL_PR_THRESHOLD:-10}"
PR_SIZE=$(gh pr view "$PR_URL" --json additions,deletions --jq '.additions + .deletions')
export PR_SIZE

if [ "$PR_SIZE" -lt "$SMALL_PR_THRESHOLD" ]; then
REVIEW_MODE="small"
elif [ -n "${EXISTING_MARKER_SHA:-}" ]; then
Comment thread scripts/review-one-pr.sh Outdated
Comment on lines +103 to +107
# Extract the full body of the review/comment containing our marker for the prior SHA.
PRIOR_REVIEW_BODY=$(
gh pr view "$PR_URL" --json reviews,comments \
--jq "((.reviews // []) + (.comments // [])) | .[].body | select(. != null) | select(test(\"sha=$PRIOR_REVIEW_SHA\"))" 2>/dev/null \
| head -1 || true
Comment thread scripts/review-one-pr.sh Outdated
Comment on lines +103 to +110
# Extract the full body of the review/comment containing our marker for the prior SHA.
PRIOR_REVIEW_BODY=$(
gh pr view "$PR_URL" --json reviews,comments \
--jq "((.reviews // []) + (.comments // [])) | .[].body | select(. != null) | select(test(\"sha=$PRIOR_REVIEW_SHA\"))" 2>/dev/null \
| head -1 || true
)
export PRIOR_REVIEW_BODY
echo " prior review SHA: $PRIOR_REVIEW_SHA (body: ${#PRIOR_REVIEW_BODY} chars)"
Comment thread prompts/single-review.md Outdated
- If `isDraft` → skip. Print `{"pr":"...","decision":"skip","reason":"draft"}` and exit.
- Verify `headRefOid == $PR_HEAD_SHA`. If not → skip with `"reason":"head-sha-changed"`.
2. `gh pr diff "$PR_URL"` — read the diff.
- **Incremental mode**: also get the diff since the prior review:
Haiku triage → Sonnet deep review → Opus security audit, where each
tier only fires if the previous one escalated. This replaces the
3-parallel-members + synthesizer architecture.

Cost impact:
- ~80% of PRs: Haiku + Opus confirm (2 calls, ~30s vs 4 calls, ~5 min)
- ~15%: + Sonnet (3 calls, ~2.5 min)
- ~5%: full cascade (4 calls, ~5.5 min)

Haiku works by receiving pre-fetched context (no tool use needed),
which sidesteps the agentic limitations found earlier.

New files:
- prompts/triage.md       — Tier 1: Haiku fast classification
- prompts/deep-review.md  — Tier 2: Sonnet full review
- prompts/security-audit.md — Tier 3: Opus security audit
- prompts/cascade-action.md — posts review from any resolving tier

Re-reviews (prior marker at different SHA) pass prior review context
to the triage, enabling faster incremental checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@don-petry don-petry left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Automated review — NEEDS HUMAN REVIEW

Risk: MEDIUM
Reviewed commit: bab010f29438d21527bddf9c045733346b603b11
Council vote: security=MEDIUM · correctness=MEDIUM · maintainability=MEDIUM

Summary

The PR replaces the parallel 3-member review council with a cascading Haiku→Sonnet→Opus tier architecture, but the two commits contain two sequential and conflicting designs — the final HEAD is entirely undocumented in the PR description and test plan. Three functional bugs exist at HEAD: the repository JSON field is invalid for gh pr view (causing silent empty metadata), REVIEW_MODE="triage-approved" is unhandled in single-review.md, and PRIOR_REVIEW_BODY/PRIOR_REVIEW_SHA extraction uses inconsistent head/tail selectors. A dangling reference to the retired synthesize.md breaks the escalation delegation path in single-review mode.

Linked issue analysis

No linked issue found in PR metadata.

Findings

Major

  • [major] scripts/review-one-pr.sh:608 (correctness) — repository is not a valid gh pr view --json field; valid alternatives are headRepository/headRepositoryOwner. The || echo '{}' fallback silently gives downstream agents an empty metadata object, stripping all PR context and likely causing spurious escalations. Same invalid field appears in prompts/deep-review.md and prompts/security-audit.md.
  • [major] scripts/review-one-pr.sh:641 (correctness) — REVIEW_MODE="triage-approved" set by the orchestrator is not handled in prompts/single-review.md, which only documents small and incremental modes. The template renders a literal <small-pr|incremental> placeholder and incremental delta analysis is skipped.
  • [major] prompts/single-review.md:483 (correctness) — Dangling reference: instructs agents to follow synthesize.md step 9a, but synthesize.md is being retired by this PR in favour of cascade-action.md. The escalation delegation path is undefined in single-review mode.
  • [major] scripts/review-one-pr.sh:591 (correctness) — PRIOR_REVIEW_BODY is selected with head -1 (oldest match) while PRIOR_REVIEW_SHA reflects the most-recent marker. Under any multi-review history these point to different review cycles, giving agents stale body context paired with the current SHA. Should use tail -1 for the body selector.

Minor

  • [minor] scripts/review-one-pr.sh:89 (security) — PRIOR_REVIEW_BODY export creates a prompt-injection surface: any commenter could post a fake <!-- pr-review-agent v1 sha=<SHA> --> marker followed by crafted content ingested as prior review context. Consider validating the full HTML comment structure in the match.
  • [minor] prompts/council/ (maintainability) — Orphaned prompt files (correctness.md, maintainability.md, security.md) are no longer referenced by the script but were not deleted.
  • [minor] scripts/review-one-pr.sh (maintainability) — SONNET_RC=$? captures the Sonnet exit code but is never referenced; the script checks the output file instead. Dead variable.
  • [minor] (correctness) — PR title and description describe the commit-1 architecture (small-PR threshold, incremental fast path); final HEAD replaced that with the cascade tier system. The test plan items do not match the final code.
  • [minor] (correctness) — No CI checks ran against HEAD (statusCheckRollup is empty). There is no automated test suite verifying the script logic or prompt correctness.

Info

  • [info] .github/workflows/pr-review.yml:48 (security · maintainability) — SMALL_PR_THRESHOLD is exposed in the workflow env: block (safe, admin-controlled) but the cascade script never reads it. Dead configuration from the first commit's approach.
  • [info] (security) — Haiku triage runs with --permission-mode plan (no tool access) — good least-privilege practice.
  • [info] (security) — jq filter interpolation of $PRIOR_REVIEW_SHA is safe; value is constrained to [a-f0-9]+.
  • [info] prompts/deep-review.md, prompts/security-audit.md (maintainability) — These prompts instruct agents to run gh pr view --json ...repository..., an invalid field. Agents following these prompts will encounter metadata fetch errors.
  • [info] (maintainability) — Tier-2 Sonnet failure exits hard (exit 1) without posting any review, while Haiku failure falls back gracefully to escalation. Consider symmetric fallback behaviour.
  • [info] (correctness) — 5 Copilot inline comments (COMMENTED state) remain unaddressed at HEAD, including the head -1 vs tail -1 mismatch and a repos/<owner>/<repo> placeholder in single-review.md.

CI status

No CI checks ran against HEAD commit bab010f29438d21527bddf9c045733346b603b11statusCheckRollup is empty.


Reviewed automatically by the don-petry PR-review council (security: opus 4.6 · correctness: sonnet 4.6 · maintainability: sonnet 4.6 · synthesis: sonnet 4.6). The marker on line 1 lets the agent detect new commits and re-review. Reply with @don-petry if you need a human.

@don-petry

Copy link
Copy Markdown
Collaborator Author

Review council — fix requested (cycle 1/3)

The automated review council identified the following issues. Please address each one:

Findings to fix

  • [major] scripts/review-one-pr.sh:608repository is not a valid gh pr view --json field. Replace with headRepository (or headRepositoryOwner where owner is needed) in scripts/review-one-pr.sh, prompts/deep-review.md, prompts/security-audit.md, and prompts/single-review.md.
  • [major] scripts/review-one-pr.sh:641REVIEW_MODE="triage-approved" is passed to single-review.md but that prompt only handles small and incremental modes. Either rename the value to align with an existing mode, or add a triage-approved branch in prompts/single-review.md so the template renders a meaningful mode label and delta analysis activates correctly.
  • [major] prompts/single-review.md:483 — Dangling reference to synthesize.md step 9a. Update to reference the correct file (cascade-action.md or equivalent) so the escalation delegation path in single-review mode is valid.
  • [major] scripts/review-one-pr.sh:591PRIOR_REVIEW_BODY uses head -1 (picks oldest match) but PRIOR_REVIEW_SHA reflects the most-recent marker. Under any multi-review history these point to different cycles. Change the body selector to tail -1 (or a jq last) to keep body and SHA in sync.
  • [minor] scripts/review-one-pr.sh:89 — Add validation that a matched body contains the full <!-- pr-review-agent v1 sha=... --> HTML comment before exporting PRIOR_REVIEW_BODY, to reduce prompt-injection surface area.
  • [minor] prompts/council/ — Delete orphaned files prompts/council/correctness.md, prompts/council/maintainability.md, and prompts/council/security.md; they are no longer referenced by the script.
  • [minor] scripts/review-one-pr.sh — Remove the dead variable assignment SONNET_RC=$? (or wire it into the subsequent check in place of the output-file inspection).

Additional tasks

  1. Resolve all unresolved review thread comments from other reviewers (CodeRabbit, Copilot, etc.)
  2. Ensure all CI checks pass after your changes
  3. Rebase on main if the branch is behind
  4. Do NOT modify files unrelated to the findings above

The review council will automatically re-review after new commits are pushed.

Major fixes:
- Replace invalid 'repository' gh field with 'headRepository'/'headRepositoryOwner'
  across script and all prompts
- Add 'triage-approved' as valid REVIEW_MODE in single-review.md with
  dedicated mode description
- Fix PRIOR_REVIEW_BODY selector: head -1 → tail -1 to match most-recent SHA
- Update dangling 'synthesize.md step 9a' reference to cascade-action.md

Minor fixes:
- Validate PRIOR_REVIEW_BODY contains marker before exporting (anti-injection)
- Write prior review body to temp file to avoid E2BIG on large reviews
- Remove dead SONNET_RC=$? variable; add || true for set -e safety
- Delete orphaned prompts/council/ files (no longer referenced by cascade)
- Fix incremental-mode compare command: document how to derive owner/repo
  from headRepository metadata

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@don-petry
don-petry merged commit ec774b9 into main Apr 10, 2026
@don-petry
don-petry deleted the review-optimizations branch April 10, 2026 16:58
don-petry pushed a commit that referenced this pull request Apr 25, 2026
Question 4 was ambiguous — users confused "Max miles?" (meant odometer)
with search radius. Now asks zip and radius as separate questions (#4 and
#5) and renames the variable to MAX_ODOMETER with explicit "(highest
mileage on the car itself)" clarification.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
don-petry added a commit that referenced this pull request May 17, 2026
* Add review mode optimization: small-PR and incremental fast paths

PRs are now routed to the cheapest review path:
- Small PRs (<10 lines): single Opus call (1 invocation vs 4)
- Re-reviews (prior marker at different SHA): single Opus call with
  prior review context, focused on what changed since last review
- First review of non-small PRs: full 3-member council (unchanged)

New files:
- prompts/single-review.md: combined council+synth prompt for single
  reviewer mode, handles both small and incremental paths

New config:
- SMALL_PR_THRESHOLD repo variable (default 10)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Replace parallel council with cascading review tiers

Haiku triage → Sonnet deep review → Opus security audit, where each
tier only fires if the previous one escalated. This replaces the
3-parallel-members + synthesizer architecture.

Cost impact:
- ~80% of PRs: Haiku + Opus confirm (2 calls, ~30s vs 4 calls, ~5 min)
- ~15%: + Sonnet (3 calls, ~2.5 min)
- ~5%: full cascade (4 calls, ~5.5 min)

Haiku works by receiving pre-fetched context (no tool use needed),
which sidesteps the agentic limitations found earlier.

New files:
- prompts/triage.md       — Tier 1: Haiku fast classification
- prompts/deep-review.md  — Tier 2: Sonnet full review
- prompts/security-audit.md — Tier 3: Opus security audit
- prompts/cascade-action.md — posts review from any resolving tier

Re-reviews (prior marker at different SHA) pass prior review context
to the triage, enabling faster incremental checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix review council findings: 4 major + 3 minor issues

Major fixes:
- Replace invalid 'repository' gh field with 'headRepository'/'headRepositoryOwner'
  across script and all prompts
- Add 'triage-approved' as valid REVIEW_MODE in single-review.md with
  dedicated mode description
- Fix PRIOR_REVIEW_BODY selector: head -1 → tail -1 to match most-recent SHA
- Update dangling 'synthesize.md step 9a' reference to cascade-action.md

Minor fixes:
- Validate PRIOR_REVIEW_BODY contains marker before exporting (anti-injection)
- Write prior review body to temp file to avoid E2BIG on large reviews
- Remove dead SONNET_RC=$? variable; add || true for set -e safety
- Delete orphaned prompts/council/ files (no longer referenced by cascade)
- Fix incremental-mode compare command: document how to derive owner/repo
  from headRepository metadata

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: DJ <dj@Rachels-Air.localdomain>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
don-petry pushed a commit that referenced this pull request May 17, 2026
Question 4 was ambiguous — users confused "Max miles?" (meant odometer)
with search radius. Now asks zip and radius as separate questions (#4 and
#5) and renames the variable to MAX_ODOMETER with explicit "(highest
mileage on the car itself)" clarification.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
don-petry added a commit that referenced this pull request May 17, 2026
* Add review mode optimization: small-PR and incremental fast paths

PRs are now routed to the cheapest review path:
- Small PRs (<10 lines): single Opus call (1 invocation vs 4)
- Re-reviews (prior marker at different SHA): single Opus call with
  prior review context, focused on what changed since last review
- First review of non-small PRs: full 3-member council (unchanged)

New files:
- prompts/single-review.md: combined council+synth prompt for single
  reviewer mode, handles both small and incremental paths

New config:
- SMALL_PR_THRESHOLD repo variable (default 10)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Replace parallel council with cascading review tiers

Haiku triage → Sonnet deep review → Opus security audit, where each
tier only fires if the previous one escalated. This replaces the
3-parallel-members + synthesizer architecture.

Cost impact:
- ~80% of PRs: Haiku + Opus confirm (2 calls, ~30s vs 4 calls, ~5 min)
- ~15%: + Sonnet (3 calls, ~2.5 min)
- ~5%: full cascade (4 calls, ~5.5 min)

Haiku works by receiving pre-fetched context (no tool use needed),
which sidesteps the agentic limitations found earlier.

New files:
- prompts/triage.md       — Tier 1: Haiku fast classification
- prompts/deep-review.md  — Tier 2: Sonnet full review
- prompts/security-audit.md — Tier 3: Opus security audit
- prompts/cascade-action.md — posts review from any resolving tier

Re-reviews (prior marker at different SHA) pass prior review context
to the triage, enabling faster incremental checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix review council findings: 4 major + 3 minor issues

Major fixes:
- Replace invalid 'repository' gh field with 'headRepository'/'headRepositoryOwner'
  across script and all prompts
- Add 'triage-approved' as valid REVIEW_MODE in single-review.md with
  dedicated mode description
- Fix PRIOR_REVIEW_BODY selector: head -1 → tail -1 to match most-recent SHA
- Update dangling 'synthesize.md step 9a' reference to cascade-action.md

Minor fixes:
- Validate PRIOR_REVIEW_BODY contains marker before exporting (anti-injection)
- Write prior review body to temp file to avoid E2BIG on large reviews
- Remove dead SONNET_RC=$? variable; add || true for set -e safety
- Delete orphaned prompts/council/ files (no longer referenced by cascade)
- Fix incremental-mode compare command: document how to derive owner/repo
  from headRepository metadata

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: DJ <dj@Rachels-Air.localdomain>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
don-petry pushed a commit that referenced this pull request May 17, 2026
Question 4 was ambiguous — users confused "Max miles?" (meant odometer)
with search radius. Now asks zip and radius as separate questions (#4 and
#5) and renames the variable to MAX_ODOMETER with explicit "(highest
mileage on the car itself)" clarification.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This was referenced Aug 2, 2026
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.

2 participants