Skip to content

pr-review: PRs with >300 changed files hard-fail the cascade (gh pr diff 406); define org standard for oversized PRs #574

Closed

Description

@don-petry

Summary

PRs with more than 300 changed files can never be auto-reviewed. review-one-pr.sh prefetches the diff with gh pr diff (line ~422); GitHub's unified-diff endpoint returns a hard HTTP 406 above 300 files, and the script treats that as fatal (exit 1) instead of falling back. The PR fails the cascade and is never reviewed.

This limitation holds (confirmed below), so this issue also proposes defining an org standard for oversized PRs.

Reproduction (#567, 2026-06-11)

#567 has 905 changed files (gh pr view 567 --json changedFiles → 905).

$ gh pr diff 567
could not find pull request diff: HTTP 406: Sorry, the diff exceeded the
maximum number of files (300). Consider using 'List pull requests files'
API or locally cloning the repository instead.

Live run failure (pr-review-trigger.yml workflow_dispatch, run 27373261247):

::error::gh pr diff failed during prefetch for .../pull/567
::error::Review failed for .../pull/567 (exit code 1)
Summary: 0 reviews posted, 0 no-ops skipped, 1 failures (processed 1/1 candidates)

Offending code — scripts/review-one-pr.sh:422-436:

if gh pr diff "$PR_URL" > "$_gh_diff_tmp" 2>"$_gh_diff_err"; then
  PR_DIFF=$(head -"$_diff_limit" "$_gh_diff_tmp")
else
  ...
  echo "::error::gh pr diff failed during prefetch for $PR_URL"
  ...
  exit 1          # <-- fatal; no fallback for the 406 "too large" case
fi

The limitation is hard, but workable

  • The unified-diff endpoint (Accept: application/vnd.github.v3.diff) is a hard GitHub cap at 300 files — not configurable.
  • But the per-file REST API still works above the cap:
    $ gh api "repos/.../pulls/567/files?per_page=1" --jq '.[0] | {filename, has_patch: (.patch != null)}'
    {"filename":".gitattributes","has_patch":true}
    
    Each entry carries its own patch, so a (truncated) diff can be assembled by paginating /pulls/{n}/files. gh pr view --json files (already used in the metadata prefetch) also returns the changed-file list.

Proposed fix (code)

When gh pr diff returns the 406 "diff exceeded the maximum number of files" error specifically (distinct from rate-limit, which is already handled):

  1. Fall back to the REST files API, assembling per-file patches up to _diff_limit, or
  2. Review against the changed-file summary only (paths + add/del counts) with a clear note that the diff was truncated, or
  3. Post a "too large to auto-review" comment and request the PR be split — see org standard below.

Proposed org standard (this is the part to ratify)

The 300-file diff cap is a real ceiling on what the agent can mechanically review. We should codify how the org handles it, in AGENTS.md:

  • A PR-size guideline / cap — e.g. PRs over N changed files should be split; optionally enforce via a CI/compliance check that flags oversized PRs.
  • Defined agent behavior for oversized PRs — partial review (files API) vs. summary-only review vs. explicit "split this PR" request — so the outcome is consistent and never a silent cascade failure.
  • Whichever we pick, the agent must degrade gracefully (post something actionable) rather than exit 1.

Related


Filed from an investigation into "pr-review agent not working — many PRs pending review."

Activity

  1. don-petry commented on Jun 12, 2026

    @don-petry
    CollaboratorAuthor

    Dev-Lead Implementation Plan

    Issue: #574 — pr-review: PRs with >300 changed files hard-fail the cascade (gh pr diff 406); define org standard for oversized PRs

    Scope

    Add graceful 406-fallback to review-one-pr.sh (assemble diff via REST files API when gh pr diff hits GitHub's 300-file cap) and codify the oversized-PR org standard in AGENTS.md.

    Implementation Checklist

    • scripts/engine.sh — add is_diff_too_large helper (mirrors is_rate_limited pattern; detects "HTTP 406 / exceeded the maximum number of files")
    • scripts/review-one-pr.sh — in the gh pr diff else-branch: after the rate-limit check, detect the 406 case and fall back to paginating /pulls/{n}/files REST API to assemble a truncated diff; set PR_DIFF to the assembled content so the cascade continues normally
    • AGENTS.md — add Oversized PRs subsection under Project-Specific Standards: PR-size guideline (≤300 changed files for full automated review), defined agent behavior (REST files API fallback, never exit 1 on 406)
    • tests/test_oversized_pr.bats — unit tests for is_diff_too_large (true for "HTTP 406 / exceeded the maximum number of files", false for rate-limit and CLI errors)
    • .github/workflows/lint.yml — add tests/test_oversized_pr.bats to the bats test list per AGENTS.md exception rule

    Tests to Write

    • is_diff_too_large: returns true for "HTTP 406" in error text
    • is_diff_too_large: returns true for "exceeded the maximum number of files"
    • is_diff_too_large: returns true for the full GitHub 406 error message
    • is_diff_too_large: returns false for rate-limit errors (no false positives)
    • is_diff_too_large: returns false for CLI invocation errors (no false positives)
    • is_diff_too_large: returns false for generic diff failure messages

    Test Command

    bats tests/test_oversized_pr.bats

    (Full suite from lint.yml: bats tests/fleet_report.bats tests/token_report.bats ... tests/test_oversized_pr.bats)

  2. don-petry commented on Jun 12, 2026

    @don-petry
    CollaboratorAuthor

    Dev-Lead: Implementation Complete

    Plan Execution

    • scripts/engine.sh — added is_diff_too_large helper (matches "HTTP 406", "exceeded the maximum number of files", "diff exceeded the maximum")
    • scripts/review-one-pr.sh — added 406 fallback: after the rate-limit check, detects the 406 case via is_diff_too_large, paginates /pulls/{n}/files REST API to assemble a truncated diff, sets PR_DIFF and continues the cascade normally (no exit 1)
    • AGENTS.md — added Oversized PRs subsection: PR-size guideline (≤300 files for full review), defined agent behavior (REST files API fallback, never exit 1 on 406)
    • tests/test_oversized_pr.bats — 10 unit tests for is_diff_too_large (true-positive cases for 406 errors, false-positive guards for rate-limit/CLI errors)
    • .github/workflows/lint.yml — added tests/test_oversized_pr.bats to the bats test list per AGENTS.md exception rule

    Test Results

    1..206
    ...
    ok 197 is_diff_too_large: 'HTTP 406' in error text returns true
    ok 198 is_diff_too_large: 'exceeded the maximum number of files' returns true
    ok 199 is_diff_too_large: full GitHub 406 error message returns true
    ok 200 is_diff_too_large: 'diff exceeded the maximum' returns true
    ok 201 is_diff_too_large: rate-limit error returns false
    ok 202 is_diff_too_large: HTTP 429 error returns false
    ok 203 is_diff_too_large: CLI invocation error returns false
    ok 204 is_diff_too_large: generic diff failure returns false
    ok 205 is_diff_too_large: empty string returns false
    ok 206 is_diff_too_large: unrelated 406 text without diff context returns false
    
    206 tests, 0 failures. ShellCheck (severity=warning) and agent profile validation: all passed.
    

    Files Changed

    • scripts/engine.sh: is_diff_too_large function added after is_cli_error
    • scripts/review-one-pr.sh: 406-specific else branch added inside the gh pr diff failure handler; assembles fallback diff from per-file REST API instead of calling exit 1
    • AGENTS.md: new Oversized PRs subsection under Project-Specific Standards
    • tests/test_oversized_pr.bats: new unit test file (10 tests)
    • .github/workflows/lint.yml: new test file added to bats list

    Notes

    • The fallback diff is assembled with gh api repos/.../pulls/.../files --paginate --slurp | jq -r 'add | ...', matching the advisory-comments pattern already in the script. 2>/dev/null || true guards all fallback API calls so a network failure degrades to an empty diff (with a header note) rather than a script failure.
    • Option 2 (summary-only) and Option 3 (split-PR comment) from the issue are not implemented — the REST files API fallback (Option 1) was chosen as the most informative response, consistent with the issue's stated preference for actionable reviews.
    • The changedFiles count in the log/note comes from the already-prefetched PR_METADATA JSON — no extra API call required.
  3. added 2 commits that reference this issue on Jun 12, 2026
  4. added 7 commits that reference this issue on Jun 13, 2026
  5. 6 remaining items

  6. added a commit that references this issue on Jun 25, 2026
  7. added 14 commits that reference this issue on Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugBug reportsdev-leadFor dev-lead agent pickupenhancementFeature requests

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions