Repository navigation
LLM review: check what the gates can't, and route non-content PRs away - #293
Conversation
An audit of all 148 reviews the bot has posted, against what actually happened to those PRs, says the project review is looking in the wrong place. Three findings drove this change. **It approved a duplicate.** #275 (de Bruijn-Erdos compactness) came back `approve` / `good_fit` / 0 findings and was closed by hand: the headline follows in a few lines from Mathlib's `Finsubgraph`. #225 was likewise subsumed by the pool's own `Incompleteness`. `REVIEW_RULES.md` has never had a duplication check — only the challenge rules do — so the model had no way to reach the reason both PRs were rejected. **It cannot see what the axiom gate misses.** #225's diagonal lemma was postulated as an `inductive` constructor, invisible to `#print axioms`; the review filed it as a card-wording nit. The same class covers #215 (a rescaled surrogate tableau proved in place of the real one), #240 (a card informal that was simply false), #265 (a synthetic residue model presented as the geometry it models), and #199 (NP-hardness claimed for a reduction-correctness result). Every defect human audits have caught here lives in the gap between what the card claims and what the Lean proves, and nothing in the rules asked about it. **Infra PRs were graded for mathematical fit.** A `.lean` file under `scripts/` clears the workflow's "touches Lean?" filter, so the exposition PRs landed on the project rules: #279 and #282 came back `not_a_fit` / `undergraduate`, #283 came back `good_fit` / `graduate` / `approve` over a summary opening "This is not a mathematics contribution." All three merged. `classify_pr` now returns `infra` for these and posts a note instead of calling the model. So the project rules gain the four checks the challenge rules already had, adapted for finished proofs — claim-vs-Lean faithfulness, what is assumed rather than proved, prior art, and source fidelity — plus the generated-bulk criterion #278 was closed on after a 0-finding approval, and an AI-slop list, since half the pool is AI-written and fluent prose is not evidence. Comparable projects converge on the same shape: Tau Ceti gates on `correctness` and `reuse` before anything else and tells its reviewers not to defer to plausible-looking work; ArkLib forbids a docstring from being the sole basis of a correctness claim. Two calibration fixes fall out of the same audit. `obscure_problem` was `no` in all 147 project reviews and is gone; card metadata moves to out-of-scope, since `quality.py` gates it and #216 and #243 were rejected on nothing else and merged unchanged; a partial review may no longer `approve`, because `code_quality` cannot be scored on elided files; and the sticky comment now says plainly that `request_changes` is an ask, not a close — 39% of those verdicts were merged after a human looked, while 20 of 28 closures cited the bot. Two of the four approve-calibration examples (sphere packing, Erdos 124) were not in the pool at all. Replaced with real slugs, and with the pool's actual size distribution. Separately, the reviewer now receives the PR title and description. The rules have always allowed a source anchor to live in the "PR description", which the model was never shown. Because that text and the diff are both contributor-written — and the pool accepts AI-generated projects by design — they are fenced with a per-request random token and framed as claims to verify, never as instructions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Descriptions are Markdown: newlines, tabs, and backslashes all appear in them, and unescaping a `@tsv` row by hand would rewrite a literal \n inside a code block. Select a JSON object and let json.loads do it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Greptile SummaryThis PR makes three improvements to the LLM review pipeline: it adds four correctness-focused checks to the project review prompt (claim-vs-Lean mismatch, assumed inputs, duplication, source accuracy), fixes infra PRs being routed to the mathematical-fit rubric, and passes the PR title and description to the model as fenced, per-request-tokenised contributor evidence.
Confidence Score: 5/5Safe to merge: routing logic is correct, all new code paths are tested, and the fencing approach for PR descriptions is sound. The infra routing fix only activates after all existing challenge/solution/refactor checks have returned, leaving those paths unchanged. Files Needing Attention: No files require special attention.
|
| Filename | Overview |
|---|---|
| python/lean_pool/review.py | Adds touches_reviewable_content, PullRequestContext, fetch_pr_context, render_pr_context, and render_infra_skip_comment; updates classify_pr, build_user_content, request_review, and render_project_assessment. Logic is correct: refactor/challenge/solution early returns precede the new infra check, and touches_reviewable_content correctly excludes generated root indices. |
| .github/REVIEW_RULES.md | Adds structured checks 1–5, updates calibration examples to real pool slugs, removes obscure_problem, adds not_applicable fit value, and clarifies the partial-review rule. Output schema and narrative are consistent with the Python rendering changes. |
| python/tests/test_review.py | New tests cover infra routing, touches_reviewable_content edge cases, trust-boundary presence across all review modes, PR context inclusion and truncation, round-trip Markdown fidelity, assessment table ordering, the request_changes footer, and the infra skip comment. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[classify_pr called] --> B{new challenge added?}
B -- yes --> C[return 'challenge']
B -- no --> D{solution file touched?}
D -- yes --> E[return 'solution']
D -- no --> F{challenge modified without pool content?}
F -- yes --> G[return 'challenge']
F -- no --> H{only existing projects, no new?}
H -- yes --> I[return 'refactor']
H -- no --> J{touches_reviewable_content?}
J -- no --> K[return 'infra — post skip note']
J -- yes --> L[return 'project']
style K fill:#ffcccc,stroke:#cc0000
style L fill:#ccffcc,stroke:#00aa00
Reviews (3): Last reviewed commit: "Lead the assessment table with the ungat..." | Re-trigger Greptile
The closing sentence still promised a "project" fallback that the function no longer takes. Caught by Greptile on #293. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Fixed the stale |
The docstring already claimed "fit and level restate the verdict and sit below", but the code still put Fit in the top row — directly under the verdict line it echoes, and above the rows nothing else in CI checks. Build the list in display order rather than inserting at index 3, so the optional prior-art and assumption rows land where they read. Prompted by Greptile on #293. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Acted on the row-ordering note too (b478385). The docstring already said |
Follow-up to #293, from watching its first production run. The review of #285 came back `approve` while the assessment table showed `Already formalized | 🛑 unverifiable from the supplied diff`. The model answered the prior-art question in a field specified to hold a declaration name or nothing, and the renderer stamped 🛑 on whatever it found — so a PR the review approved carried a red row reading "this is a duplicate". Prior art is a request_changes ground, so the row is not cosmetic. _prior_art_cell now renders a multi-word value as a hedge and keeps the stop icon for an actual declaration. The challenge renderer had the same latent bug and shares the helper. Both rules docs now say the field is a bare declaration name, to leave it empty when nothing was found or it could not be checked, and never to use it to report unverifiability — source_match already has a value for that. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Audits the review prompts against the pool as it actually is (141 projects), against all 148 reviews the bot has posted and what happened to those PRs afterwards, and against how Tau Ceti and ArkLib review contributions. Three things came out of it.
The project review never asked the question that decides these PRs
Every defect a human audit has caught in this repository lives in the gap between what a card claims and what its Lean proves — and nothing in
REVIEW_RULES.mdasked about it.statement-mismatchappears only as an example tag in the output schema, never as a check.approve,good_fit, 0 findingsFinsubgraphinductiveconstructor (invisible to#print axioms), and subsumed by the pool's ownIncompletenessapprove, 4/5, 0 findings on a 710k-token partial diffSo the project rules gain the four checks the challenge rules have always had, adapted for finished proofs: does the Lean prove what the card claims, what is assumed rather than proved, is it already done, and does the cited source support it. Plus a generated-bulk criterion and an AI-slop list — half the pool is AI-written, and fluent prose is not evidence.
Both comparison repos converge on this shape. Tau Ceti runs
correctnessandreusefirst because they block most often per dollar, and tells reviewers not to "defer to fluent prose, confident docstrings, plausible-looking names"; ArkLib forbids a docstring from being the sole basis of a blocking correctness claim. Their bigger structural ideas — a reviewer with a checkout and grep, per-angle agents, deterministic verdicts — are noted below as follow-ups, not done here.Infra PRs were being graded for mathematical fit
A
.leanfile underscripts/clears the workflow's "touches Lean?" filter, andclassify_prthen fell through toproject. The exposition PRs landed on the fit rubric: #279 and #282 came backnot_a_fit/undergraduate; #283, the next increment of the same pipeline, came backgood_fit/graduate/approveover a summary that opened "This is not a mathematics contribution." All three merged.classify_prnow returnsinfraand posts a note instead of calling the model.Calibration, from the same audit
obscure_problemwasnoin 147 of 147 project reviews — removed.quality.pyalready gates the schema.approve—code_qualitycannot be scored on files the model never saw, which is exactly what happened on Import Erdos97ConvexOctagon: convex-octagon case of Erdős Problem 97 #278.request_changesis an ask, not a close: 39% of those verdicts were merged after a human looked, while 20 of 28 closures cited the bot.The reviewer can now read the PR description
REVIEW_RULES.mdhas always allowed the source anchor to live in the "PR description" — which was never sent to the model. It is now, along with the title.Both are contributor-written, and so is the diff, so they are fenced with a per-request random token and framed as claims to verify rather than instructions. A static delimiter can be closed by the text it delimits; a fresh one cannot be guessed by whoever writes the PR. Every review mode also gets an explicit trust boundary, with
prompt-injectionas a finding tag.Not done here
Worth discussing separately: giving the reviewer a checkout and grep so "is this already in Mathlib?" is answerable rather than guessed; splitting the monolithic prompt into per-angle agents; computing the verdict from the findings instead of asking for it; and an adversarial pass that tries to refute each finding. The refactor and solution rules have never once run in production (0 invocations each) — worth checking that routing separately.
Tested with 302 Python tests; new coverage for the routing fix, the fenced PR context, the trust boundary across all four modes, the reordered assessment table, and the
request_changesfooter.🤖 Generated with Claude Code