train_snapshots calls arl.train_rl in chunks of ten steps and keeps a frozen copy after each chunk. Each call restarts the Adam optimizer and uses its own seed, a small departure from one uninterrupted 80-step run that does not matter for what this chapter measures.
17.1 What a pass rate estimates
An evaluation estimates a property of a policy under a harness. The harness is everything except the weights: the task set, the prompt template, the environment and its budgets (turns, edits, context length), the sampling temperature, and the success criterion. For a task , write The benchmark’s pass@1 is the task average . It is not “the fraction of episodes that passed” unless every task gets the same number of episodes, and it is not a property of the weights alone: change and every changes. The success criterion here is the one Chapter 4 fixed for evaluation, independent of any training reward: the agent submitted and every hidden test passed. The raw data of an evaluation are therefore per-task success counts: draw episodes on each of tasks and record , the number that succeeded. Everything else in this chapter (pass@1, pass@, intervals, paired tests) is a function of the vector .sample_counts produces it with the training harness cfg, through the same sample_groups that training uses, so the template, renaming, edit budget, turn budget, and temperature cannot silently differ.
under_cap in 17 of 32, and speed in 1 of 32. A single number hides that one task is essentially unsolved, and the statistics below will show that this heterogeneity, not the number of episodes, sets the uncertainty of the trained agent’s score.
17.2 pass@ and its unbiased estimator
Coding systems are often allowed several attempts: sample patches and keep one that passes, given a verifier. pass@ is the probability that at least one of independent attempts succeeds, averaged over tasks: It needs an oracle to pick the passing attempt, so it measures coverage, an upper bound on what any selector can achieve, not a deployable success rate (Chapter 20 distinguishes it from Best@). The plug-in estimator is biased. The obvious estimate replaces by . For the map is strictly concave on , so by Jensen’s inequality whenever : the plug-in systematically underestimates pass@, most for small and large . The unbiased estimator. Chen et al. (2021) draw samples and ask a different question of them: if we picked of the samples uniformly at random without replacement, what is the probability that all fail? With successes, it is , so Unbiasedness takes one line. For any fixed set of sample indices, the event “every sample in fails” has probability , because samples are independent. The estimator’s failure term is the average of that event’s indicator over all sets . Expectation is linear, so its expected value is exactly. (It is a U-statistic, the minimum-variance unbiased estimator built from the sample.) Unbiasedness holds per task, and averaging over tasks keeps it. A stable form. The binomial coefficients overflow floating point long before is large: has 600 digits. Writing both coefficients as factorials and cancelling, a product of factors in when . When , every -subset contains a success and the estimate is exactly 1.17.3 Confidence intervals
A pass rate without an interval cannot be compared with anything. Three intervals cover the cases this book meets.Binomial intervals for one task
For independent episodes with success probability , has standard error . The Wald interval plugs in , and it fails exactly where agent evaluations live: at or its width is zero, and near the edges it undercovers. The Wilson interval inverts the test instead of plugging in. It collects every that the score test would not reject, . Squaring gives a quadratic in whose roots are The center is pulled toward 1/2 and the width never collapses, which is what a small needs.The bootstrap, and which unit to resample
The bootstrap estimates the sampling distribution of a statistic by recomputing it on data resampled with replacement from the observed data. The percentile interval takes the and quantiles of the recomputed values. The one assumption that matters is that the resampled units are independent draws from the population of interest.bootstrap_ci takes one value per unit; paired_bootstrap_diff resamples the same units for two systems.
bootstrap_ci applied to per-task rates.
Which interval is right depends on the question, as Miller (2024) emphasizes for language-model evals. “How well does this checkpoint do on these ten tasks?” conditions on the tasks, and only episode sampling is random. “How well will it do on tasks like these?” treats the tasks as a sample. The second is almost always the question. A simulation with a known population separates the two: task pass rates drawn from a U-shaped Beta(0.4, 0.3) distribution (most tasks nearly always or nearly never solved, as in agent benchmarks), ten tasks, 32 episodes each.
17.4 Comparing two runs
Two kinds of randomness separate two numbers. Evaluation noise comes from sampling episodes from a fixed checkpoint, and more episodes shrink it. Training noise comes from the seed of the run (task order, sampled groups, minibatch order), and it is a property of the recipe: two runs of the same recipe end at different checkpoints. Whether training noise belongs in the error bar depends on the claim. “Checkpoint B is better than checkpoint A” is a claim about two fixed checkpoints. “Recipe B is better than recipe A” is a claim about distributions of checkpoints, and its unit of replication is the seed. We train three more seeds of the default recipe for 30 steps, a point at which the runs have not saturated, and evaluate each of the four step-30 checkpoints twice, with independent episodes (320 per evaluation). The duplicate evaluations measure the evaluation noise; the spread across seeds contains both kinds.Paired comparisons
When two systems run on the same tasks, compare them task by task. The per-task difference removes the task’s difficulty, which both systems share, so and the covariance term, large when tasks differ in difficulty, is what an unpaired comparison throws away. We compare the checkpoints at steps 60 and 80 on the same ten tasks, and we also give both the same random generator. Two similar policies driven by the same random numbers tend to sample the same episodes, which correlates their outcomes further. This is the common random numbers technique from simulation; it is legitimate for a paired comparison, and it is why the same generator must not be reused when the goal is to measure evaluation noise, as in the block above.How many tasks or seeds?
A power calculation turns the comparison around: given an effect we want to detect, how many units do we need? For a two-sided test at level with power , the mean of paired differences with per-unit standard deviation must satisfy , so For two independent groups (unpaired tasks, or two recipes with separate seeds), the difference of two means has per-unit standard deviation , and the formula gives the size of each group.In production. The same arithmetic sets the size of real benchmarks. On SWE-bench Verified’s 500 tasks, the binomial standard error of a pass rate near 0.4 is about 0.022 for one attempt per task, so the difference of two independent single-attempt runs has a standard error of about 0.031, and a 2-point gap is well inside it. Per-task pairing, several attempts per task (as DeepSWE’s average of 16 runs does, Chapter 20), and multiple training seeds are the levers. This is arithmetic from the binomial formula, not a measurement.
17.5 The harness defines the number
A harness choice is any setting outside the weights that changes . If training and evaluation, or two evaluations being compared, differ in one, the comparison measures the harness. We evaluate the same two checkpoints under the training harness and under seven one-field changes.Greedy versus sampled evaluation
Greedy decoding (temperature 0) evaluates the mode of the policy; sampled evaluation at the training temperature evaluates the distribution that training optimized and that a best-of- system would draw from. They answer different questions, and the per-task counts show how.compare and zero tasks, and only for some names, while its sampled behavior spreads over all five repair ops. For the trained agent, greedy decoding removes the residual mistakes on most tasks (under_cap rises from 25 to 30) and turns speed, where the trained agent occasionally succeeds, into a hard zero. Greedy pass@1 is the right number for a deployment that decodes greedily. It is the wrong number for a sampled deployment or a best-of- system, and it hides exactly the low-probability successes that the pass@ debate of Section 17.7 is about. The book’s default is sampled evaluation at the training temperature, with the temperature reported.
17.6 Held-out splits and leakage
A held-out set answers a generalization question, and the question depends on what is held out. The default split of Chapter 4 holds out variants: two of the six variants of every bug family, with different function names, constants, and tests. It measures whether the agent generalizes across surface forms of bugs it was trained on. Holding out a family asks whether it generalizes to a kind of bug it has never been rewarded for fixing. We train for 30 steps on the four families other thanzero (missing zero guard) and evaluate on all six zero tasks and on the eight held-out variants of the other families.
build_tokenizer(make_tasks('all'))), so held-out words have embeddings; a word that never occurs in training keeps its random initialization, which is harmless for the answer but is a leak of vocabulary. The base agent was behavior-cloned on training tasks only. The third channel is the one Chapter 9’s Exercise 3 points out: randomize_names draws from all 30 function names, so held-out names appear in training episodes as random names. The block measures how often, and then tests whether it matters by evaluating with the renaming pool restricted to training names or to held-out names.
17.7 Does RL narrow the distribution? pass@ on TinyAgent
Chapter 20 summarizes a public debate. Yue et al. (2025) report that on math benchmarks RLVR-trained models win at small but “base models achieve a higher pass@k score when k is large”, and read this as RL sharpening the base model’s distribution rather than adding capability; ProRL (2025) reports the opposite after longer training with reference resets. Both are reported by their authors on math with large models, not reproduced here. The measurement itself is cheap with the tools of this chapter: unbiased pass@ on held-out tasks for the base agent and for RL checkpoints, from the same 64 episodes per task. We add a reference curve, a uniform guess among the five repair ops, which passes with probability 0.2 per attempt.speed. The base agent solves it in 10 of 64 episodes, the 20-step checkpoint in 13, and the 80-step checkpoint in 3. Its pass@32 on speed is therefore about 0.88 against essentially 1 for the base agent, and that one task produces the whole deficit at large . What did training do on that task?
speed contains both a multiplication and an integer division; its bug is the missing zero guard. The base agent’s first edit on it is spread over all six edit ops, add_zero_guard in 13 of 64 episodes. The trained agent applies fix_comparison in 59 of 64 episodes and the right op in 4. Somewhere between steps 20 and 80, the policy’s mapping from source to op became confident and wrong for this task, and the probability of the right op fell from about 0.2 to 0.06. This is narrowing in the precise sense of the debate: RL concentrated probability on the behavior that its other experiences rewarded and removed most of the mass from an alternative that occasionally worked. Figure 17.3 shows the mean curves and the speed task.
Evidence. Measured here: one 80-step GRPO run of a 158k-parameter model, ten held-out tasks, 64 episodes per task per checkpoint. Reported by sources: Yue et al. and ProRL (math, large models; Chapter 20). The tiny-scale result illustrates the measurement and one mechanism of narrowing; it is not evidence for either side of the debate at scale.
17.8 Choosing a checkpoint without touching the test set
Every choice made by looking at a number turns that number into a training signal. Choosing the checkpoint with the highest test score, then reporting that score, reports the maximum of several noisy estimates, which is biased upward: the winner’s curse. With checkpoints of equal true skill and evaluation noise , the expected maximum is about , which is for . The fix is the one used for hyperparameters: split the held-out tasks into a validation set used for every decision and a test set evaluated once, for the final report. With ten held-out tasks we can afford only five and five, one variant of each family in each.speed and the validation half does not: with five tasks per split, the composition of the split decides the level. Choosing by validation picks step 80, whose test score, 0.744, is an unbiased estimate for the chosen checkpoint because the test set played no part in the choice. Choosing by test picks step 70 and reports 0.762. Whether that particular number is inflated cannot be read from one evaluation. The winner’s curse is a statement about the expected value of the procedure, so we measure it by repeating the procedure: ten small test evaluations (8 episodes per task), each used to pick a checkpoint, and each pick scored on the nine evaluations that did not choose it.
17.9 Design problems in practice
Problem: evaluation noise larger than the effect. Symptom: an ablation table where arms differ by a few points, a periodic eval curve that zigzags, or a “win” that disappears on rerun. Cause: the evaluation’s standard error, computed at the right unit (Section 17.3), is as large as the effect, and the comparison is unpaired or unreplicated.train_rl’s periodiceval_passuses 4 episodes per task, 40 on the held-out set; the block re-evaluates one checkpoint eight times at that size. Options: (a) more episodes per task, which helps until the task term dominates; (b) more tasks, the only fix for that term; (c) paired comparisons on the same tasks, with common random numbers when comparing checkpoints; (d) more training seeds when the claim is about a recipe. Default: before running an ablation, compute the paired standard deviation from a pilot evaluation and userequired_unitsto size it; report intervals at the task level.
Problem: harness drift. Symptom: a checkpoint’s number changes between two dashboards, a reproduction misses a paper’s number by several points, or an improvement appears exactly when the eval code changed. Cause: depends on the harness, and some harness field differs: temperature, budgets, template, the environment’s rules, or the success criterion (Section 17.5). Drift is most dangerous when the changed field is one a weak policy can exploit. The block runs a skill-free policy that applies three fixed ops and submits, under the training harness and under the plainBugFixEnvthat allows unlimited edits. Chapter 15’spass_ratehelper evaluates in the plain environment, which matches Chapter 15’s own training setup but not the default setting of Chapter 9 onward, so numbers from the two are not directly comparable. Options: (a) build evaluation from the training configuration object, assample_counts(..., cfg)does, so that every field is shared by construction; (b) version the harness and record it with every number; (c) run a fixed reference policy (scripted or a frozen checkpoint) through every harness change and require its number to stay put. Default: (a) and (c). A canary policy whose score is known catches drift that no amount of looking at the evaluated model will.
Problem: an evaluation that reuses the training reward. Symptom: the training reward and the evaluation number rise together, and the behavior behind them is not the intended skill. Cause: when the evaluation computes success with the same function the policy was optimized against, it inherits every flaw the optimizer found: public tests that can be special-cased, a judge that can be flattered, a format check that can be satisfied without solving anything (Chapter 11). The block runs Chapter 4’s scripted hacker, which special-cases the public test inputs, through the gym with the public-test reward and the hidden-test reward. Options: (a) evaluate with a stronger, held-out verifier than the training reward (hidden tests, more tests, a different test generator); (b) audit samples of passing trajectories by hand or with behavior statistics; (c) track the gap between the training reward and the held-out verifier as a dashboard metric. Default: (a) always, and (c) as an alarm.sample_countsscores with the hidden tests whatevercfg.rewardsays, so an RL run trained on a hackable reward is still evaluated honestly.
Problem: choosing the checkpoint by the test set. Symptom: the reported test score is never matched again, by a rerun, by a fresh test set, or by users. Cause: every decision made by looking at test numbers (the checkpoint, the decoding temperature, the prompt, which of several runs to report) selects on noise, and the reported maximum is biased upward by roughly (Section 17.8, where it was 0.03 to 0.04). Options: (a) a validation split for all decisions and a test split used once; (b) when tasks are too few to split, report the pre-registered final checkpoint rather than the best one; (c) report the number of models evaluated on the test set, so readers can discount. Default: (a), with the selection rule written down before the test evaluation. For long-lived benchmarks, refresh the test set periodically, since a team’s accumulated decisions leak into it even when each one is careful.
Summary
- An evaluation estimates , a per-task success probability under a harness, and its raw data are per-task success counts.
sample_countsproduces them with the training configuration, scoring with hidden tests whatever the training reward was. - pass@ needs the unbiased estimator , computed as a product; the plug-in underestimated pass@5 by 0.04 to 0.08 at .
- Episodes of one task are correlated. With the trained agent’s heterogeneous tasks the design effect was 20, and the task-level interval was 4.4 times as wide as the episode-level one; resampling episodes covered the population mean in 38% of simulated evaluations. Use Wilson for single tasks and the task-level bootstrap for benchmarks.
- Compare on the same tasks: pairing cut the standard error of a checkpoint difference from 0.132 to 0.023. Size comparisons with a power calculation (17 paired tasks for 5 points, 533 per arm unpaired) and measure seed variance with independent evaluations; at step 30 it was indistinguishable from evaluation noise here.
- One harness field moved the trained agent’s held-out pass rate by up to 0.13, and a looser environment tripled a skill-free policy’s score. Held-out variants (0.93) and a held-out family (0.03) gave opposite verdicts on one checkpoint.
- The base agent overtook the 80-step checkpoint at (0.998 against 0.988) because RL drove the right op on one task from 13 to 4 of 64 episodes; at large enough, a guesser in a five-op space covers everything. Selecting on the test set inflated a reported score by about 0.03; decide on validation and report test once.
Exercises
- Prove that is the minimum-variance unbiased estimator of from Bernoulli samples, using the fact that is a complete sufficient statistic. Then compute its variance for , , by simulation and compare it with .
- Change an assumption: rerun Section 17.7 with episodes per task and up to 128, and with the 40-step checkpoint added. Does the crossing move? Does any task other than
speedlose coverage? Plot per-task success counts across all checkpoints and find the step at whichspeedstarts to fall. - Implement a Bayesian alternative to the task-level bootstrap: a Beta prior per task and a hierarchical model for task pass rates, sampled with simple Gibbs or importance sampling in torch. Compare its interval with
bootstrap_cion the counts of Section 17.1. - Repeat the held-out family experiment of Section 17.6 for each of the five families. Is the collapse below the base agent’s guessing rate universal? Relate the result to the entropy of the first edit at the start of an unseen-family episode (Chapter 10).
- Write a harness canary: a function that runs a fixed set of scripted policies (
oracle,blind, thestackerof Section 17.9) throughmake_env(cfg)and asserts their pass rates. Which fields ofRLConfigdoes it detect a change in, and which can it miss? - Common random numbers: compare the paired standard error of the step-60 versus step-80 difference with the same generator for both checkpoints and with different generators. Explain the difference with the variance formula of Section 17.4.
- Design review: a teammate reports that a new advantage estimator improves SWE-bench Verified pass@1 from 41.0% to 43.4%, from one training run per arm and one sample per task, and that the checkpoint was “the best of the last five”. Using this chapter, list what you would ask for before accepting the claim, estimate the standard error of the reported difference under an unpaired and a paired analysis, and say how many seeds and samples you would request.