Skip to content

Stop the AI review failing on a large PR, and point it at the right files - #1108

Merged
ako merged 2 commits into
mainfrom
fix/ai-review-large-diffs
Sep 16, 2026
Merged

ako merged 2 commits into
mainfrom
fix/ai-review-large-diffs

Conversation

@ako

@ako ako commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

review failed on #1107 and #1106. The diagnosis is the one in the title, plus two things it uncovered.

The failure

could not find pull request diff: HTTP 406: Sorry, the diff exceeded the maximum number of lines (20000)
PullRequest.diff too_large

gh pr diff reads an endpoint capped at 20,000 lines. #1107 is 21,366 changed lines, 1,366 over. gh exits 1, the step runs under bash -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 plus exit 0.

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 rebuilt from those, and a fetch problem now downgrades the review instead of failing the PR.

What the review was actually reading

head -c 80000 truncates 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):

  • generated / fixture / append-only paths skipped (mdl/grammar/parser/, testdata/, findings/*.jsonl, binaries)
  • whole file patches, most-changed first
  • no 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; 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:

PR before after
#1107 (21,366 lines) job fails at step 1 11 source files, 278-file manifest
#1098 (752 lines) 14 files 13 files, unchanged behaviour

Note pull_request_target runs 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

…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
@github-actions

Copy link
Copy Markdown

AI Code Review

Critical Issues

None found.

Moderate Issues

None found.

Minor Issues

  • In .github/scripts/build_review_diff.py, the SKIP tuple contains "mdl/grammar/parser/" which is correct to skip generated parser files, but the comment in CLAUDE.md says to "note but skip" these files. The implementation correctly skips them, so this is just a minor observation.
  • The SKIP_SUFFIX includes .lockb (likely meant for LevelDB lock files) but this seems unrelated to the project. However, it's harmless to include.

What Looks Good

  • The solution correctly addresses the root cause: the GitHub diff API's 20,000 line limit that was causing HTTP 406 errors on large PRs.
  • The new script .github/scripts/build_review_diff.py implements a smart selection strategy:
    • Uses per-file API endpoint (no line limit)
    • Prioritizes code files (.go, .g4) over other types
    • Skips noise paths (generated code, fixtures, append-only logs)
    • Enforces per-file limits to prevent a few large files from dominating the budget
    • Includes a manifest of all changed files so the model knows what it's missing
  • The workflow updates handle failure cases gracefully:
    • If fetching PR files fails, it downgrades the review instead of failing the PR
    • If no reviewable diff is available, it exits cleanly
    • Provides clear notes to the model about the selection process
  • Local verification shows the fix works correctly:
  • The implementation follows the principle described in the PR: "a fetch problem now downgrades the review instead of failing the PR"
  • The solution is minimal and focused - only touches the review workflow without changing core functionality

Recommendation

Approve. 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
@github-actions

Copy link
Copy Markdown

AI Code Review

Review Summary

This 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

  • None found.

Minor Issues

  • Script clipping logic: In build_review_diff.py, when a patch lacks newlines within the first PER_FILE bytes, patch.rfind("\n", 0, PER_FILE) returns -1, resulting in patch[:0] (empty string). While this edge case didn't manifest in testing (PR Sync ako/mxcli: retire the legacy engine (sdk/mpr importers 27 → 0), workflow authoring, layouts, MCP fixes #1107 worked), it could produce confusing output for patches without newlines in the budget window. Consider improving the clipping logic to handle this case (e.g., take first PER_FILE bytes when no newline found).
  • Missing script tests: As infrastructure code, the script lacks unit tests. While manually verified against real PRs, adding test coverage would improve robustness (e.g., testing edge cases like empty patches, noise filtering, budget allocation).

What Looks Good

  • Effective solution: Switching to the per-file endpoint eliminates the hard line limit failure. The selection strategy (most-changed files first, skipping noise/generated files, per-file byte cap) ensures the review focuses on meaningful changes.
  • Manifest inclusion: Providing a complete file manifest in the prompt allows the reviewer to note when findings depend on unseen files rather than assuming absence.
  • Robust error handling: Fetch failures downgrade to an empty diff (warning) rather than failing the job, maintaining CI stability.
  • Normal PRs unaffected: Verified that small PRs (like feat(describe): Mode 2 — describe crossed branches faithfully by default #1098) continue to work identically.
  • Clean implementation: The Python script is well-commented, follows the budget logic described, and integrates cleanly with the workflow.

Recommendation

Approve. 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

@ako
ako merged commit 05d8536 into main Sep 16, 2026
13 checks passed
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