Stop the AI review failing on a large PR, and point it at the right files - #1108
Conversation
…ht files Three defects, one visible and two that the visible one uncovered. THE FAILURE. `gh pr diff` reads an endpoint that caps at 20,000 lines and answers HTTP 406 above it. #1107 is 21,366 changed lines, so the step died with "PullRequest.diff too_large" under `bash -e` and took the job with it -- the only hard-fail path in a workflow whose every other error (missing key, non-200, empty content) is a warning and exit 0. #1106 failed the same way hours earlier. The per-file endpoint has no such cap: measured on #1107 it returns all 278 files, 3 without a patch (the .bson fixtures). The diff is now rebuilt from those patches, and a fetch problem downgrades the review rather than failing the PR. WHAT THE REVIEW ACTUALLY SAW. `head -c 80000` truncates by BYTES over an alphabetically ordered diff. Measured on #1107, whose full diff is 1.29 MB: the window covered 3 of 275 files, and all three were .claude/skills/fix-issue/findings/*.jsonl -- append-only evidence logs. Zero Go code. #1095 was cut to 23% and #1090 to 19% the same way, so this is what every large review has been looking at. Selection is now file-aware: generated, fixture and append-only paths are skipped, whole file patches are taken most-changed-first, and no single file may exceed a tenth of the budget. That last clause is load-bearing -- ordering by size with no cap put three files in the budget and nothing else, while ordering alphabetically missed mdl/backend/mpr/backend.go, the 1,163-line change this PR is named after. With both, #1107 yields 11 source files including that one. A manifest of all 278 changed files goes in the prompt regardless, and the note tells the model to say when a finding needs a file it cannot see rather than assume absence. A normal PR is unaffected: #1098 comes through as 13 of 14 files, nothing over budget. Not fixed here, because it is not in this repo: every "successful" run since at least 2026-09-04 got HTTP 401 from OpenRouter and posted nothing, so the green checks were not reviews. The key has been rotated; this PR is the first run that can reach the model. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BNDe35kDNsMX5cz4Ahn4rk
AI Code ReviewCritical IssuesNone found. Moderate IssuesNone found. Minor Issues
What Looks Good
RecommendationApprove. This PR effectively fixes the issue where the AI review was failing on large PRs due to the diff endpoint's line limit. The solution is well-designed, properly tested against real API payloads, and maintains review quality while avoiding hard failures on large PRs. The changes are scoped appropriately to the review workflow only. Automated review via OpenRouter (Nemotron Super 120B) — workflow source |
Two defects in the matcher, found reviewing my own script after the AI review (which raised neither). "/testdata/" as a plain substring skipped the per-package fixtures and NOT the repo's ROOT testdata/, because that path has no leading slash — the one directory whose name says fixtures most plainly. Matching the bare word "testdata/" instead fixes that and over-fires: docs/notes-testdata/ is prose, not fixtures. Patterns are now matched against "/" + filename and every one starts with "/", so each matches on a path-segment boundary and both cases come out right. Eight cases checked, including the two that motivated this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BNDe35kDNsMX5cz4Ahn4rk
AI Code ReviewReview SummaryThis PR modifies the AI review infrastructure to handle large PRs by switching from the GitHub diff API (which has a 20,000-line limit) to the per-file API endpoint, then intelligently selecting which files to include in the review diff based on a byte budget and file type priority. Critical Issues
Moderate Issues
Minor Issues
What Looks Good
RecommendationApprove. The PR fixes a critical blocker for reviewing large PRs with minimal risk. The minor issues (clipping edge case, missing script tests) are low-impact and can be addressed in follow-up work. The solution has been validated against the problematic PRs (#1107, #1106) and maintains existing behavior for normal PRs. Note: The OpenRouter authentication issue mentioned in the PR description is external to this repository and correctly out of scope. This PR solely addresses the diff retrieval mechanism. Automated review via OpenRouter (Nemotron Super 120B) — workflow source |
reviewfailed on #1107 and #1106. The diagnosis is the one in the title, plus two things it uncovered.The failure
gh pr diffreads an endpoint capped at 20,000 lines. #1107 is 21,366 changed lines, 1,366 over.ghexits 1, the step runs underbash -e, the job dies — and it is the only hard-fail path in a workflow whose every other error (missing key, non-200, empty content) is a warning plusexit 0.The per-file endpoint has no such cap. Measured on #1107 it returns all 278 files, 3 without a patch (the
.bsonfixtures). The diff is rebuilt from those, and a fetch problem now downgrades the review instead of failing the PR.What the review was actually reading
head -c 80000truncates by bytes across an alphabetically ordered diff. #1107's full diff is 1.29 MB, so the window covered 3 of 275 files — all of them.claude/skills/fix-issue/findings/*.jsonl, the append-only evidence logs. Zero Go code. #1095 was cut to 23% and #1090 to 19%, so this is what every large review has been looking at.Selection is now file-aware (
.github/scripts/build_review_diff.py):mdl/grammar/parser/,testdata/,findings/*.jsonl, binaries)That last clause is load-bearing. Ordering by size with no cap put three files in the budget and nothing else; ordering alphabetically missed
mdl/backend/mpr/backend.go, the 1,163-line change #1107 is named after. With both, #1107 yields 11 source files including that one.A manifest of every changed file goes into the prompt regardless of budget, and the note tells the model to say when a finding needs a file it cannot see rather than assume absence.
Normal PRs are unaffected — #1098 (752 lines) comes through as 13 of 14 files, nothing over budget.
Verification
Both rehearsed locally against the real API payloads:
Note
pull_request_targetruns the workflow from the base branch, so this PR is reviewed by the old workflow — which is useful: it is the first run since the key rotation that can reach the model, so it tests that independently. The new path takes effect for PRs opened after merge.Not fixed here
Every "successful" run since at least 2026-09-04 got HTTP 401 from OpenRouter and posted nothing — the green checks were not reviews. The key has been rotated, which is outside this repo.
🤖 Generated with Claude Code
https://claude.ai/code/session_01BNDe35kDNsMX5cz4Ahn4rk