← Home

Sample results / work in progress

CI-LLM: LLM Code Review at Scale

LLM code review at scale — unconstrained generation, AST ground truth, policy optimization.

A short summary of what we studied, how we measured it, what we found, and what to do with it.


Problem

Code-review LLMs flood PRs with noisy findings. Naive “show everything” policies hurt signal-to-noise and reviewer trust. We need a repeatable way to:

Method

Layer What we did
Data 1,022 PRs, 445 gold PRs across 7 repos (C, Rust, TS, JS, Python). AST-hash labels; excluded repos with unusable PR workflows.
Generation Unconstrained LLM generation (4 models × repos); meta-eval with Claude 3 Haiku — decoupled from the generator.
Labeling AST comparison for historically_fixed; comment/whitespace-only → not fixed.
Objectives Smooth metrics: Laplacian CatchRate+, log-scaled Annoy-, Volume-; DensityMax (comments per 100 changed lines), not a flat comment cap.
Policies 10k simulated policies per model×repo over 5 parameters (Smin, Cmin, DensityMax, Allow_Style, Require_Snippet).
Optimization D2H (distance to ideal: high catch, low annoyance, low volume). Compared naive (no filter), random search (B samples from 10k), and EZR active learning (Naive Bayes acquisition, same B). Budget sweep B ∈ {50, 500, 1000, 3000}.

Results

Ground truth & generation

Filtering beats the naive baseline

Random search vs active learning

Interpretable rules (from trees / exploration)

Thesis & recommendation

The win is architecture, not the optimizer.
Unconstrained generation + post-hoc filtering (with AST-grounded labels and decoupled scoring) is what improves the quality–noise tradeoff. The policy search problem in this setting is easy: random search with a modest budget (e.g. B ≈ 50) is fast, stable, and sufficient; fancy Bayesian active learning does not pay off here.

Practical takeaway: Invest in generation quality and filtering semantics; use simple random search over the simulated policy table unless the policy dimensionality or evaluation cost grows substantially.


Appendix — Result tables

Tables below mirror RESEARCH_STATUS.md (v2 pipeline).

Phase 1 — Ground truth scale

1,022 PRs crawled, 445 gold PRs across 7 active repos.

Repo PRs Gold PRs Gold Lines Language
redis/redis20013540,238C
microsoft/vscode200127105,917TypeScript
pallets/flask1255723,683Python
django/django97531,878Python
rust-lang/rust1223816,503Rust
expressjs/express47227,500JavaScript
curl/curl3113379C

Excluded: torvalds/linux (email patches, 0 PRs), golang/go (Gerrit, 0 PRs), facebook/react (4% gold rate).

Phase 2 — LLM generation + meta-eval

4 generator models × 7 repos = 28 runs. Meta-evaluator: claude-3-haiku (decoupled from generators).

Generator Total Findings Avg/PR Notes
gpt-4o-mini5,4966.7Baseline model
deepseek-v3.212,90215.7Highest volume
gpt-5-mini15,55118.9Highest volume overall
gemini-3-flash-preview5,7897.0Fastest generation (~10 min)

Phase 3 — Labeling (historically_fixed)

Generator Findings Fixed Precision
gpt-4o-mini5,49683115.1%
deepseek-v3.212,9021,91714.9%
gpt-5-mini15,5512,46215.8%
gemini-3-flash-preview5,78997716.9%

Phase 4 — Policy optimization (D2H: random vs EZR active learning)

D2H = Euclidean distance from normalized objectives to ideal (CatchRate=1, Annoyance=0, Volume=0). Lower is better.

Budget sweep summary (4 models × 5 repos = 20 experiments per budget level)

Budget Repeats AL Wins Ties Rand Wins Avg Rand D2H Avg AL D2H Avg abs Δ
502005150.4130.4360.024
5001017120.4000.4100.011
1000102990.3970.4080.013
30001009110.3940.4070.013

Budget = 50 (repeats = 20, n = 28) — AL wins 0, ties 6, rand wins 22

Model Repo Naive Rand σ_R AL σ_AL Δ(R−AL) Winner
deepseek-v3.2curl/curl0.6690.34970.02000.36160.0904-0.0119Rand ✓
deepseek-v3.2django/django0.5920.39460.00820.39170.0791+0.0029≈
deepseek-v3.2expressjs/express0.6450.41040.01830.42100.0584-0.0106Rand
deepseek-v3.2microsoft/vscode0.5910.43190.00620.43970.0818-0.0077Rand ✓
deepseek-v3.2pallets/flask0.5900.40340.01710.44000.0915-0.0366Rand ✓
deepseek-v3.2redis/redis0.6630.45960.00180.46140.0292-0.0018≈ ✓
deepseek-v3.2rust-lang/rust0.6530.40110.01100.40180.0669-0.0007≈
gemini-3-flashcurl/curl0.5860.35780.02180.39430.1080-0.0365Rand ✓
gemini-3-flashdjango/django0.5900.40730.00860.44240.0846-0.0351Rand ✓
gemini-3-flashexpressjs/express0.6110.33020.02710.39080.0983-0.0607Rand ✓
gemini-3-flashmicrosoft/vscode0.5790.43580.00690.44070.0799-0.0049≈ ✓
gemini-3-flashpallets/flask0.5970.43000.00930.44810.0679-0.0181Rand ✓
gemini-3-flashredis/redis0.6350.42620.00910.46070.0516-0.0345Rand ✓
gemini-3-flashrust-lang/rust0.6010.41860.02180.43240.0915-0.0138Rand ✓
gpt-4o-minicurl/curl0.6580.39790.01820.42430.0533-0.0264Rand ✓
gpt-4o-minidjango/django0.6390.44400.01060.44400.0426+0.0000≈
gpt-4o-miniexpressjs/express0.6490.41590.01350.48070.0637-0.0649Rand ✓
gpt-4o-minimicrosoft/vscode0.5790.42910.01370.46280.0820-0.0337Rand ✓
gpt-4o-minipallets/flask0.6070.40520.01420.44810.0858-0.0430Rand ✓
gpt-4o-miniredis/redis0.6130.39610.00840.43600.0710-0.0400Rand ✓
gpt-4o-minirust-lang/rust0.6160.33660.01720.35910.1231-0.0225Rand ✓
gpt-5-minicurl/curl0.5870.38360.01400.42430.0876-0.0407Rand ✓
gpt-5-minidjango/django0.6400.42730.00430.45550.0555-0.0281Rand ✓
gpt-5-miniexpressjs/express0.5820.37510.01320.38470.0957-0.0096Rand ✓
gpt-5-minimicrosoft/vscode0.6470.45310.00380.45310.0432+0.0000≈ ✓
gpt-5-minipallets/flask0.5930.41730.00420.43820.0900-0.0208Rand ✓
gpt-5-miniredis/redis0.6220.40160.00950.45420.0597-0.0525Rand ✓
gpt-5-minirust-lang/rust0.6140.37490.01850.39200.0866-0.0171Rand ✓

Budget = 500 (repeats = 10, n = 20) — AL wins 1, ties 7, rand wins 12

Model Repo Naive Rand σ_R AL σ_AL Δ(R−AL) Winner
deepseek-v3.2curl/curl0.6690.30810.01050.32380.0161-0.0156Rand ✓
deepseek-v3.2django/django0.5920.38340.00300.39880.0132-0.0154Rand ✓
deepseek-v3.2microsoft/vscode0.5910.42030.00820.43960.0261-0.0193Rand ✓
deepseek-v3.2pallets/flask0.5900.39330.00240.39200.0031+0.0013≈ ✓
deepseek-v3.2redis/redis0.6630.45740.00020.45740.0000+0.0000≈ ✓
gemini-3-flashcurl/curl0.5860.33730.00630.34520.0315-0.0079Rand ✓
gemini-3-flashdjango/django0.5900.39780.00290.40910.0129-0.0113Rand ✓
gemini-3-flashmicrosoft/vscode0.5790.42710.00230.46020.0134-0.0331Rand ✓
gemini-3-flashpallets/flask0.5970.41420.00830.40450.0187+0.0097AL
gemini-3-flashredis/redis0.6350.42160.00330.42380.0183-0.0022≈ ✓
gpt-4o-minicurl/curl0.6580.38160.00580.39790.0134-0.0163Rand ✓
gpt-4o-minidjango/django0.6390.44400.00270.44400.0087+0.0000≈ ✓
gpt-4o-minimicrosoft/vscode0.5790.39780.01210.42320.0061-0.0254Rand ✓
gpt-4o-minipallets/flask0.6070.38020.00530.39130.0105-0.0111Rand ✓
gpt-4o-miniredis/redis0.6130.38780.00240.39320.0115-0.0054Rand ✓
gpt-5-minicurl/curl0.5870.37280.00500.37110.0163+0.0017≈
gpt-5-minidjango/django0.6400.42190.00280.44340.0184-0.0215Rand ✓
gpt-5-minimicrosoft/vscode0.6470.44660.00240.44840.0023-0.0018≈
gpt-5-minipallets/flask0.5930.41210.00290.41140.0070+0.0006≈
gpt-5-miniredis/redis0.6220.39340.00180.41340.0032-0.0200Rand ✓

Budget = 1000 (repeats = 10, n = 20) — AL wins 2, ties 9, rand wins 9

Model Repo Naive Rand σ_R AL σ_AL Δ(R−AL) Winner
deepseek-v3.2curl/curl0.6690.30260.00910.29550.0191+0.0071AL
deepseek-v3.2django/django0.5920.38320.00260.38880.0180-0.0056Rand ✓
deepseek-v3.2microsoft/vscode0.5910.41330.00530.44740.0217-0.0341Rand ✓
deepseek-v3.2pallets/flask0.5900.39200.00120.39150.0006+0.0005≈ ✓
deepseek-v3.2redis/redis0.6630.45740.00010.45740.0000+0.0000≈
gemini-3-flashcurl/curl0.5860.33100.00330.39820.0301-0.0671Rand ✓
gemini-3-flashdjango/django0.5900.39780.00270.39510.0116+0.0028≈
gemini-3-flashmicrosoft/vscode0.5790.42420.00210.45000.0103-0.0258Rand ✓
gemini-3-flashpallets/flask0.5970.40260.00820.40230.0078+0.0003≈
gemini-3-flashredis/redis0.6350.41910.00330.42220.0121-0.0031≈ ✓
gpt-4o-minicurl/curl0.6580.38160.00360.38160.0139+0.0000≈
gpt-4o-minidjango/django0.6390.44400.00500.44400.0000+0.0000≈ ✓
gpt-4o-minimicrosoft/vscode0.5790.39410.00800.41720.0070-0.0231Rand ✓
gpt-4o-minipallets/flask0.6070.37930.00560.39220.0084-0.0129Rand ✓
gpt-4o-miniredis/redis0.6130.38750.00250.40500.0065-0.0175Rand ✓
gpt-5-minicurl/curl0.5870.36620.00590.35970.0139+0.0065AL ✓
gpt-5-minidjango/django0.6400.42060.00200.44340.0096-0.0228Rand ✓
gpt-5-minimicrosoft/vscode0.6470.44660.00090.44550.0014+0.0011≈ ✓
gpt-5-minipallets/flask0.5930.40880.00240.40910.0043-0.0003≈ ✓
gpt-5-miniredis/redis0.6220.39270.00070.41230.0020-0.0196Rand ✓

Budget = 3000 (repeats = 10, n = 20) — AL wins 0, ties 9, rand wins 11

Model Repo Naive Rand σ_R AL σ_AL Δ(R−AL) Winner
deepseek-v3.2curl/curl0.6690.29550.00300.29550.0000+0.0000≈ ✓
deepseek-v3.2django/django0.5920.37960.00200.37670.0150+0.0030≈ ✓
deepseek-v3.2microsoft/vscode0.5910.40970.00270.44680.0194-0.0371Rand ✓
deepseek-v3.2pallets/flask0.5900.39090.00050.39090.0000+0.0000≈ ✓
deepseek-v3.2redis/redis0.6630.45740.00000.45740.0000+0.0000≈
gemini-3-flashcurl/curl0.5860.33100.00240.39820.0046-0.0671Rand ✓
gemini-3-flashdjango/django0.5900.39330.00140.39510.0020-0.0017≈ ✓
gemini-3-flashmicrosoft/vscode0.5790.42260.00140.44380.0009-0.0212Rand ✓
gemini-3-flashpallets/flask0.5970.39970.00230.41670.0072-0.0171Rand ✓
gemini-3-flashredis/redis0.6350.41390.00170.42170.0031-0.0077Rand ✓
gpt-4o-minicurl/curl0.6580.38160.00080.38160.0000+0.0000≈
gpt-4o-minidjango/django0.6390.43570.00670.44400.0000-0.0084Rand ✓
gpt-4o-minimicrosoft/vscode0.5790.38980.00350.41640.0021-0.0266Rand ✓
gpt-4o-minipallets/flask0.6070.37380.00530.39050.0012-0.0167Rand ✓
gpt-4o-miniredis/redis0.6130.38680.00230.39320.0016-0.0064Rand ✓
gpt-5-minicurl/curl0.5870.35920.00520.35860.0000+0.0005≈ ✓
gpt-5-minidjango/django0.6400.41790.00210.44870.0063-0.0309Rand ✓
gpt-5-minimicrosoft/vscode0.6470.44560.00040.44550.0000+0.0001≈ ✓
gpt-5-minipallets/flask0.5930.40640.00140.40910.0000-0.0027≈ ✓
gpt-5-miniredis/redis0.6220.39180.00060.41130.0011-0.0195Rand ✓