How ReviewGate handles big PRs

ReviewGate is built for the "AI changed many files at once" reality, so it has an adaptive pipeline for diffs that exceed the model's context window. The design goal: rather mark the review as unfinished than let a big PR through as a clean PASS.

Mechanism

  1. Review units (plan_units) — the input budget is the provider's max_input_tokens (default 200k). A diff within budget is one unit (zero degradation for normal PRs); over budget, files are bin-packed by directory proximity into multiple units reviewed separately.
  2. Fixed-overhead reservation — splitting reserves room for the system prompt and dimension focus (plan_budget = budget − overhead), guaranteeing every unit can be sent on its first round. With the default 200k budget this is an invisible no-op.
  3. Sampling pinned to 1 for multi-unit reviews — big PRs don't get multiplied by --samples; multi-sampling is reserved for single-unit (normal) PRs where it stabilizes flaky recall.
  4. Per-unit adaptive degradation — a unit's prompt starts with full new-file context; if over budget it falls back to diff-only; if a single file's diff alone exceeds the budget, that unit is skipped and marked oversized — counted as incomplete, never silently passed.
  5. Pre-flight check every agent round — during review the agent pulls context on demand (read_file / grep / navigation). If the conversation would exceed budget, the next round gracefully wraps up: findings gathered so far are kept, nothing crashes or truncates silently.

The guarantee: never a silent pass

If any unit is skipped, timed out, failed, or wrapped up early, the run always ends with incomplete = true plus explicit warnings (oversized / timed_out / failed), the verdict degrades to WARN (never PASS), and with --fail-on the process exits non-zero so CI cannot misread "unfinished" as "clean".

Stress tests (2026-06-27)

TargetLangSizeBudgetUnitsFirst-round over-budgetFindingsVerdict
axios 847d89bJS9 files4k8013WARN + incomplete
requests f8bec2fPython19 files6k202WARN + incomplete
axios HEAD~30..HEADJS55 files / ~5,000 lines16k8012WARN + incomplete
ripgrep HEAD~40..HEADRust28 files12k406*WARN + incomplete
gin HEAD~80..HEADGo46 files / ~2,500 lines16k6013**BLOCK + incomplete
curl HEAD~30..HEADC132 files / ~2,400 lines12k (tight)11015***WARN + incomplete

* Includes a real hallucinated-API catch (as_bytes_mut() doesn't exist on [u8]).
** Includes a real Slowloris DoS (a #nosec G112 suppression with no timeout set) and copy-paste residue referencing a nonexistent maskHeaders() — big PRs can BLOCK, not just WARN.
*** The honest counter-example: 12k budget is too tight for 132 dense C files; most units exhausted budget while fetching context, so real findings ≈ 0. Still safe — WARN + incomplete, not a silent pass. Match max_input_tokens to diff density (see tuning).

Takeaways

The oversized-single-file path

When one file's diff alone exceeds the budget (nothing left to split), it is individually skipped and named. Tested on axios de1a8100 with a 2,467-line package-lock.json at an 8k budget: three lockfiles (~53k / 11k / 11k tokens each) were skipped one by one with per-file callouts, the small files in the same commit were reviewed normally with no false positives, and the run ended WARN, incomplete = true. When AI touches a huge generated file: no crash, no silent pass — you're told exactly which files went unreviewed, with the suggestion to split the change or raise max_input_tokens.

Tuning

KnobEffect
max_input_tokens (provider config)The input budget that decides when to split. Match it to diff density: too tight and units exhaust budget while fetching context (see the curl row). Small-context models can lower it; large models keep the 200k default.
--samples NPer-dimension sampling for single-unit PRs (union of runs, cost ×N); automatically pinned to 1 for multi-unit reviews.
--timeout SWall-clock cap per dimension; a timed-out dimension is skipped, the rest are kept, and the run counts as incomplete.
--fail-on block|warn|neverWhich verdict makes CI exit non-zero; unfinished reviews degrade to WARN.

Per-run raw records live in docs/evals/ (files named 2026-06-27__bigpr-*.md). 中文原版在这里