Typed decision models as code-review judges

Jev and every open-source Jev-class alternative, asked the same typed questions about the same 150 review cases, scored against verdicts fixed before any of them ran.

Ten systems · five reviewer roles · 1,834 questions · Claude as the reference · 2026-09-25, CLM-8B added 2026-09-27

STATE · inputs inlined by name ### inputs/review_package.diff + def refund(self, cid, amount): + if amount <= 0: return 25 ### inputs/task_brief.md non-positive amount raises ValueError noul · a defect a reviewer must block?probability of yes choice · what does the test assert?requirement · nothing · detail · wrong noul · public-interface contract kept?probability of yes ANSWERS · probabilities, no text defect · 0.89 nothing · 0.96 contract kept · 0.14
150
known-verdict cases, ten clean, ten planted, ten argued, per role
1,834
typed questions, every raw answer recorded by state hash
1
system that reads the case on four of five roles

Two things came out of it that matter more than the leaderboard.

The first number was wrong, instructively.A typed judge that never saw the diff scored 30 of 30 because the file paths it was handed carried the corpus label. Inlining the files and dropping the directory turned that into 25 of 30.
30 → 25after the leak fix
Scores can be earned without reading.The grader accepted a defect as caught when any lens question answered 0.5 or above, path or no path. A constant answer scores 20 of 30 that way. Only the clean cases and the per-question probabilities separate reading from guessing.
20/30for a constant answer

What was measured

A code-review pipeline has five reviewer roles, each answering a bounded question about a piece of state. For each role there is a corpus of thirty cases whose verdict was fixed before any system ran. Cases were authored by hand; none is public, so no system could have trained on them.

rolestate the judge seesthe question
test reviewerthe tests a writer produced, the task brief, the acceptance criteriadoes each test prove a requirement, or merely run?
spec alignmenta diff, the spec, the accumulated changedoes the change drift from or contradict the spec?
task alignmenta diff, the task brief, the builder's reportdoes the change do what the task said, and only that?
code reviewa diff with context, the brief, the reportwhat defects does the diff contain?
plan reviewa plan of tasks, the specper lens: sign off, defer, ask, or block?

Each corpus has three kinds of case, ten of each. A positive is clean; any blocking or major finding is a false fail. A negative plants a defect at a named path. A pressure case plants one and argues for it in the brief or a comment; the judge must flag it anyway.

How the questions were chosen

Jev-class systems take a state and typed questions, a yes/no with a probability, a choice over named options with a distribution, an ordered score, and return no text. The rule used to turn each reviewer prompt into questions: the judgement the schema asks for becomes the question; lenses become secondary questions.

Test reviewerOne choice per test id over the four labels the schema already used, requirement, nothing, implementation detail, wrong requirement, with the schema's own definition of each as the option description. One yes/no per lens.
Spec and task alignmentOne yes/no, "the change contains a defect a reviewer must block". One yes/no per lens. A choice for the verdict and a choice for the kind of misalignment.
Code reviewThe defect yes/no, one yes/no per lens (public-interface contract, modular decomposition, test-tier isolation), the verdict choice.
Plan reviewOne choice per lens over the four plan verdicts.

An earlier attempt that asked only the lens questions produced honest 0.5s and never asked for the judgement. For the test reviewer the per-test choice is the judgement; the lens is context.

How the state was built

1 · WHAT THE FIRST RUN SENT Read first: `/evals/code_reviewer/negative-file-handle-leak/inputs/review_package.diff` The prompt with paths in it. No file contents: the model has no tools to open them. The directory name carries the corpus label. A model that never saw a diff can read "negative". 2 · WHAT IT SCORED code reviewer corpus: 30 / 30 · every planted defect "caught", every clean case "passed" Published as a result. It measured the label, not the model. Found by asking what the state actually contained, not by reading the score. 3 · THE FIX, AND THE HONEST NUMBER ### inputs/review_package.diff + file contents inlined · directory dropped from the text Pinned by a test: the state carries the contents and never the case name. Same corpus, same model: 25 / 30. Five clean diffs over-flagged, no planted defect missed.

Text-generating judges get their inputs by reference, file paths and tools to open them. A typed model has no tools, so the state must carry the content. Every referenced file is inlined under a neutral name and the directory is removed from the text; that is the leak fix. The file a test id names is inlined too. For small budgets the inputs go before the prompt text, so what a 512-token window drops is boilerplate, not evidence. Systems with a hard limit get a character cap after that ordering; code tokenizes at about 2.3 characters per token.

Every exchange is recorded with the questions, the raw per-option probabilities, the model, the endpoint and the SHA-256 of the state; the state text is stored once by hash. That is what allowed the replay below: identical bytes to every system.

How answers were graded

A positive passes with no finding at or above major. A negative or pressure case passes with a finding on the planted path at or above the floor, or, for a judge that cannot name a path, a verdict of fail.

The fix

For the test-review role the grader originally accepted any major finding as a catch, including a pathless lens answer at 0.5, and counted the same against clean cases. It now reads the per-test labels and findings that name a path; a pathless lens answer counts neither way. The change moved Jev 30 to 29, Nimble 20 to 24, Kev 4B 26 to 17, Laya 24 to 20. The diff-based roles keep the original rule, which still admits the flag-everything route; read their clean-case column, not the score.

The systems

systemwhat it ishow it ran
Claude judgethe pipeline's text-generating reviewer, with toolsinputs by reference, as in production
Jev (TypeSafe)hosted decision modelAPI, full inlined state
LayaModernBERT-large, 421Min-process; 512-token budget, evidence first
VonModernBERT-large, 395Min-process
Kev 0.8BQwen3.5-0.8B with a pointer headlocal server on MLX
Kev 4BQwen3.5-4B with a pointer headthe author's Hugging Face Space
Rizzo Flow 1.7BSpark-X2.5 over llama.cpplocal server on MLX; the 4B took 120 s a question
SemIfoption logits of a frozen base LLM, no decision modelbatch scorer over Qwen3.5-0.8B on MLX
Bespoke Nimble 9Bcandidate-logit scoring, 9BHugging Face Space; 2,048-token limit, state capped at 3,400 characters
NanoJevQwen3-0.6B with decision headsnot run: requires a CUDA device; no Space, no endpoint
CLM-8Bfrozen Qwen3-8B encoder with ~20M-parameter contrastive heads, Stanford and NVIDIA, released 2026-09-23local 8-bit MLX port of the encoder, upstream clm-serve; 8,192-token window; added 2026-09-27

Results

Test reviewer, the role every system ran

Accuracy is of the per-test probability against the known kind; 0.67 is what a constant "defect" answer earns on a 20 to 10 split. Read the last column: a judge that reads the case has a low first number and high second and third.

systemgradedclean passedaccuracyBrierP(defect) clean → planted → argued
Claude judge30/3010/10———
Jev29/3010/100.970.050.15 → 0.88 → 0.93
Nimble 9B, 3,400 chars24/309/100.830.150.14 → 0.75 → 0.81
Nimble 9B, test + brief only25/309/100.830.160.11 → 0.74 → 0.72
Laya20/306/100.670.210.68 → 0.69 → 0.72
Kev 0.8B20/300/100.670.250.84 → 0.86 → 0.88
SemIf20/300/100.670.230.78 → 0.78 → 0.79
Kev 4B, test + brief only18/309/100.630.340.15 → 0.35 → 0.51
Kev 4B17/308/100.570.340.21 → 0.44 → 0.56
Von10/3010/100.670.230.59 → 0.58 → 0.58
Rizzo Flow 1.7B10/3010/100.330.450.19 → 0.19 → 0.19

The other four roles

roleJevLayaKev 4BNimble 9B
spec alignment30/30 · clean 10 · acc 0.8020/30 · clean 0 · acc 0.6710/30 · clean 10 · acc 0.3325/30 · clean 5 · acc 0.37
task alignment26/30 · clean 10 · acc 0.8326/30 · clean 7 · acc 0.6310/30 · clean 10 · acc 0.3323/30 · clean 10 · acc 0.53
code review26/30 · clean 6 · acc 0.9028/30 · clean 8 · acc 0.6721/30 · clean 1 · acc 0.3321/30 · clean 1 · acc 0.60
plan review8/30 · clean 2 · acc 0.332/30 · clean 2 · acc 0.3310/30 · clean 10 · acc 0.33refused: over 2,048 tokens

Laya's 28 of 30 on code review against Jev's 26 is the flag-everything route the diff-role grader still allows: its probability of a defect is 0.73 on clean diffs and 0.70 on defective ones. Kev 4B on the diff roles puts 0.03 to 0.15 on everything, clean or not. Plan review is the role neither reads, and its grader wants a block on a named task id, which a per-lens judge cannot give.

Head to head on identical questions: Jev and Laya

All 449 recorded exchanges were replayed through both in one sitting, 1,834 questions each, byte-identical state and questions.

32%
agreement on choice labels
70%
agreement on yes/no side, mean probability gap 0.19
$0.07
Jev's cost for all 1,834 questions; Laya ran locally for nothing
role, stateJev accuracyJev BrierJev P(defect) clean → defectiveLaya accuracyLaya BrierLaya P(defect) clean → defective
test reviewer, full0.930.070.18 → 0.880.670.220.71 → 0.73
test reviewer, minimal0.770.120.16 → 0.790.670.260.85 → 0.84
task alignment0.890.090.23 → 0.760.640.230.62 → 0.61
code review0.890.110.37 → 0.750.670.240.77 → 0.75
spec alignment0.720.180.70 → 0.910.670.230.70 → 0.68
plan review0.330.360.14 → 0.280.330.420.22 → 0.23

The 3,306 recorded questions, replayed through the two kept models

Nine systems answered 3,306 questions in total, most of them the same question about the same case asked of different systems. Deduplicated by state hash and question set, that is 449 unique exchanges and 1,834 unique questions, each case in up to three recorded state variants. Both kept models, Jev and Laya, answered every one in one sitting on byte-identical input.

3,306
questions answered across nine systems
1,834
unique questions after deduplication by state hash
2
models asked all of them: Jev and Laya
rolechoice: same labelyes/no: same sidemean yes/no gap
test reviewer36 / 128 · 28%79 / 120 · 66%0.20
task alignment96 / 180 · 53%115 / 180 · 64%0.20
code review44 / 90 · 49%225 / 360 · 63%0.20
spec alignment51 / 178 · 29%170 / 178 · 96%0.15
plan review95 / 420 · 23%——
all32%70%0.19
Agreement is mostly on the easy side.The 96% on spec alignment is both models putting a high probability of a defect on nearly every spec case, clean ones included, 0.70 each. Agreement where both say yes to everything carries no information.
96%spec, same side
Laya's per-test labels are close to a fixed answer.Of 128 per-test choices, 78 are "implementation detail" and none is "nothing". Jev's labels spread 56 / 26 / 23 / 23 and track the cases. Laya's mean top-option probability is 0.39, barely above a uniform guess over four options; Jev's is 0.74.
78 / 128one label, Laya
Laya's yes/no answers move less, and not with the case.Standard deviation 0.15 across 838 yes/no answers against Jev's 0.20; the movement it does have is uncorrelated with clean versus defective.
0.15 vs 0.20stdev of P(yes)
Plan review is where both are lost.23% label agreement over 420 per-lens choices; neither reads the plan, and the grader wants a task id a per-lens judge cannot name.
23%plan, same label
What the replay settles, and what it cannot.On identical input the two are not interchangeable: the disagreement is a reader against a near-constant answer, not noise between two readers. Whether Laya's errors are independent of a text-generating judge's on live work, the only reason to keep a cheap second vote, needs the live disagreement rate, not more corpus questions.
$0.07Jev, all 1,834

All 1,834 questions again, with Claude as the reference

The replay above shows Jev and Laya disagree; it does not say who is right. So a third system answered the same 449 exchanges: Claude Opus 5, the model behind the text-generating judge, asked the identical typed questions about the identical state bytes, through the Claude Code CLI with a JSON schema enforcing the answer shape.

Model, exactly

Every Claude answer in this section came from claude-opus-5 (Claude Opus 5), requested by that ID on every call, run on 2026-09-25. It is not Claude Opus 5.5 or Claude Fable 5.1, the newer and more capable Claude models available on that date; they were not tested, and they may score higher. Read the Claude numbers as Opus 5's, not as the best Claude can do.

Of the 1,834 questions, 726 have a known right answer, because the case kind fixes it: the 269 defect yes/no questions, the 269 verdicts, the 128 per-test labels, and for plan review whether any lens says block, 60 in all. Lens questions and misalignment kinds have no ground truth and are not scored. Accuracy is the probability against 0.5; Brier is the squared error of the probability, lower is better.

91.5%
Claude Opus 5 (claude-opus-5), right on the 726 gradable questions, Brier 0.066
85.4%
Jev, Brier 0.107, at about one three-thousandth of the price
63.4%
Laya, Brier 0.249, the same probability on clean and defective cases
rolegradedClaude acc / BrierJev acc / BrierLaya acc / Brier
test reviewer1280.95 / 0.040.90 / 0.080.63 / 0.26
task alignment1800.97 / 0.040.92 / 0.060.66 / 0.23
code review1800.92 / 0.070.88 / 0.100.68 / 0.23
spec alignment1780.88 / 0.080.76 / 0.160.67 / 0.24
plan review600.75 / 0.180.75 / 0.180.33 / 0.36
all7260.915 / 0.0660.854 / 0.1070.634 / 0.249

Probability of a defect, clean → defective

A system that reads the case has a low first number and a high second.

roleClaudeJevLaya
test reviewer0.22 → 0.960.15 → 0.860.75 → 0.76
task alignment0.21 → 0.900.15 → 0.830.60 → 0.59
code review0.38 → 0.940.33 → 0.780.69 → 0.69
spec alignment0.46 → 0.960.61 → 0.900.68 → 0.66
plan review0.65 → 0.820.66 → 0.810.29 → 0.29

Who got each question right

correctof 726
all three400
Claude and Jev190
Claude and Laya41
Claude only33
Jev only27
none16
Laya only16
Jev and Laya3
pairsame sideboth wrong
Claude and Jev622 / 726 · 86%32
Claude and Laya484 / 726 · 67%43
Jev and Laya452 / 726 · 62%49
Claude Opus 5 · claude-opus-5JevLaya
price, all 1,834 questions$194 API-equivalent, run on a subscription, not charged≈ $0.07$0, local
median time per exchange19.7 s0.35 s0.45 s
wall clock, 449 exchanges91 min, four at a time, with rate-limit pauses164 s221 s
errors000
Claude is the clear winner on correctness.First or tied on every role, and a Brier score 40% lower than Jev's. The gap is widest on spec alignment, 0.88 against 0.76, where Jev puts 0.61 on clean specs and Claude 0.46.
0.915Claude accuracy
Jev is the clear winner on value.93% of Claude's accuracy for about one three-thousandth of the price, fifty times faster. On test review and task alignment it is within five points of Claude.
93%of Claude, Jev
Laya does not read the case.Its probability of a defect is the same on clean and defective cases in every role, and it is right alone on only 16 questions.
0.634Laya accuracy
Plan review is a tie the question forces.Claude and Jev each flag 15 of the 20 clean plans and miss none of the defective ones. "Any of seven lenses says block" is too easy to trip; the question is the limit, not the model.
15 / 20clean plans flagged, both
Jev's errors overlap Claude's, but not completely.32 questions are missed by both. Jev alone catches 27 that Claude misses, so as a second opinion to Claude it would add a little, not a lot.
32missed by both
This is Claude in the typed judges' seat.Here it answers typed questions without tools, one reply per exchange. The production judge reads files with tools and writes findings; on the test-review corpus it scored 30 of 30.
30/30production judge, test review

The same questions, put to CLM-8B

Four days after this report, Stanford and NVIDIA released CLM-v0.1-8B: a frozen Qwen3-8B encoder with two contrastive projection heads of about 20M parameters, scoring a state against candidate actions with no text generation, Apache 2.0. It is the first open model pitched directly at Jev's job, so on 2026-09-27 it was put on the same questions.

How it ran, exactly

Nobody hosts it, so it ran on the 16 GB M2 Pro through an 8-bit MLX port of the encoder (decisive top-1 agreement with the full weights measured at 1.0000) with upstream's clm-serve unchanged in front. Upstream serves the encoder at 2,048 tokens; this arm raised that to 8,192 so the whole state fits, in the order Jev sees. A 2,048-token arm was stopped at 192 of 443 exchanges once it was clear it trailed the 8k arm, and is not reported.

Six plan-review positives were rewritten after the Claude replay, so 443 of the 449 exchanges are reproducible today and 720 questions are gradable, not 726. Jev was re-run on the same 443 on 2026-09-26, which is why its figures here differ by a point from the section above: a fresh run on a slightly different corpus, not a re-grade.

86.5%
Jev, right on the 720 gradable questions, Brier 0.101
56.1%
CLM-8B at 8k, Brier 0.283; a coin flip scores about 50% and 0.25
48
questions CLM-8B gets right that Jev misses; Jev alone gets 267
rolegradedJev acc / BrierCLM-8B acc / Brier
test reviewer1280.88 / 0.080.63 / 0.37
task alignment1800.93 / 0.060.50 / 0.27
code review1800.90 / 0.100.64 / 0.25
spec alignment1780.76 / 0.160.44 / 0.29
plan review540.83 / 0.130.74 / 0.22
all7200.865 / 0.1010.561 / 0.283

Probability of a defect, clean → defective

CLM-8B's two numbers are within 0.02 of each other in every role, and on test review it returns 1.0 for every per-test label.

roleJevCLM-8B
test reviewer0.15 → 0.851.00 → 1.00
task alignment0.15 → 0.840.53 → 0.54
code review0.32 → 0.790.70 → 0.70
spec alignment0.60 → 0.900.49 → 0.48
plan review0.60 → 0.810.90 → 0.91
correctof 720
both356
Jev only267
neither49
CLM-8B only48
JevCLM-8B · 8k window
median time per exchange0.22 s58.9 s, one at a time on the laptop
sum of per-exchange time, 443 exchangesunder 2 min7.2 h
same side as Jev405 / 720 · 56%
errors00
CLM-8B does not read the case either.The same probability of a defect on clean and defective states in every role. That is the Laya pattern at ten times the parameters.
0.561CLM-8B accuracy
The window is not the explanation.The 8k arm saw the whole state and beat the 2k arm; more context did not turn the probabilities into a reader's.
8k > 2kon the shared 284
Quantization is unlikely to be either.The 8-bit port agrees with the full weights on every decisive top-1 in the parity check; a 30-point gap is not an 8-bit artefact.
1.0000top-1 parity
The heads were trained for a different question.They rank an agent's candidate actions against a state; the release's own DeepSWE heads had to be fine-tuned for code selection. Only the heads train, so tuning on these corpora is cheap, but this section reports the model out of the box. A CLM-35B is announced for October.
~20Mtrainable parameters

Why a typed judge at all

A text-generating judge costs about $0.57 and 45 seconds per case. Re-running a thirty-case corpus after a prompt edit is $17 and 25 minutes; recalibrating five roles is about $90 and two and a half hours. Jev answers a corpus for half a cent in twelve seconds, the local models for nothing in a similar time. That is what makes prompt iteration on judges affordable, whichever typed model is chosen.

Findings

  1. Check what the state leaks before believing a score. Paths, IDs and filenames are text to a model. The first 30 of 30 was the label.
  2. A score a constant answer can earn is not a score. Report the clean-case column and the per-question probabilities; the graded total alone ranked Kev 4B first among open models when its per-test judgement was at chance.
  3. Sub-1B encoders do not discriminate on review-sized states. Laya, Von and Kev 0.8B give the same probability whatever the case. Shrinking the state to the test file and the brief did not help them.
  4. Nimble 9B reads the test but is starved. Its 2,048-token limit removes the brief and criteria on every role but the minimal one; it is the only open model with a calibrated per-test judgement.
  5. Kev 4B is confident and wrong on diffs. Decisive probabilities, near-zero probability of a defect on planted defects in the alignment and code roles.
  6. Jev is the reference among typed models. Accuracy 0.89 to 0.97 with Brier 0.05 to 0.11 on four roles, and the only model whose lens answers stay low on clean tests.
  7. Claude is the most accurate; Jev is the best value. On all 1,834 replayed questions, Claude is right on 91.5% of the 726 gradable ones, Jev on 85.4%, Laya on 63.4%. Jev costs about one three-thousandth as much and answers fifty times faster.
  8. CLM-8B, the open model built for this job, does not do it out of the box. On the same 720 gradable questions it is right on 56.1% with a Brier of 0.283, and its probability of a defect does not move between clean and defective states. Jev is right on 86.5%.
  9. Two judges are worth their cost only if their errors are independent. No case was missed by both Jev and the text-generating judge; that is a hint, and the real measurement is the disagreement rate on live runs, which this benchmark does not contain.

Reproducing

The harness records, for every case, the questions, the raw answers, the cost, the time and the state hash, pinned to the digest of the judge definition; the state text is stored once by hash. A new system is a transport and a model name. It answers the same questions on the same bytes and is compared case by case and question by question against any earlier record. Regrading is a re-read of stored replies, not a re-run.

Read the full written report · data summaries in data/, including the three-way comparison with Claude and the CLM-8B head-to-head

Limitations: thirty cases per role, hand-authored; run-to-run variance of about one case in thirty for the hosted model; the diff-role grader still admits the flag-everything route; local latencies were measured with other models loaded; Nimble and Kev 4B ran on a shared free-tier GPU with capped or reordered state; NanoJev was not run; CLM-8B ran as an 8-bit quantization of its encoder on a laptop, past its published 2,048-token window, so its latency is the laptop's.