Proof of Quality · Nº 03

Proof of Quality

A field guide to evaluating LLM systems

A generative system's quality is a distribution, not a property — and a demo samples it once. This guide teaches you to write quality down as something executable: golden sets, calibrated judges, gates in CI, guardrails in production. The suite you build is three things at once — the spec your team argues about, the alarm that fires before your users notice, and the record you produce when a regulator asks how you know.

Module 01 The case against vibes

Somewhere in your organization there is a slide deck with five model outputs on it. They are good outputs. They were chosen by a person who ran the prompt eleven times, and they are the reason the feature got funded. Nothing about that deck was dishonest, and nothing about it was evidence.

This module is about the gap between those two sentences. A deterministic program is specified by its code: read it carefully enough and you know what it does. A generative system returns a different answer every time you ask, serves a traffic distribution nobody designed, and degrades without producing a diff. It can only be specified by the battery of tests you hold it to — which means the eval suite is not quality assurance bolted onto the spec. It is the spec. We start by establishing why the intuitive alternative fails, and end with the epistemic rule that governs every claim in the rest of this guide.

The demo is an anecdote

The support-desk drafter is a GenAI tool at a European online retailer. It reads an inbound customer-service email, retrieves the relevant policy passages, and drafts a reply for a human agent to review, edit, and send. Before launch, the product team demoed eight drafts to the leadership review. All eight were excellent: correct policy citations, warm tone, no invented promises. The feature shipped. Six weeks later, the support organization's own quality sampling showed that roughly two in five drafts on refund disputes were being rewritten from scratch by agents, and one had promised a customer a refund the policy did not permit.

Nothing went wrong between the demo and production. That is the uncomfortable part. The demo was an accurate sample of the system — an accurate sample of its upper tail. A generative model does not have a quality; it has a quality distribution, and any particular output is a draw from it. When you look at eight outputs you have chosen to show other people, you are not measuring the distribution, you are reporting its maximum. The distinction is the whole of this guide compressed into one sentence: a demo answers “can it?” and shipping requires “how often, and how badly when not?”

Bar chart of 500 drafter outputs scored 1.5 to 5.0, showing 45 percent below the acceptance threshold of 3.5 while the single demoed output sits at 5.0500 drafts, one intent, one prompt — policy-adherence score1.52.02.53.03.54.04.55.0acceptance threshold 3.5227 of 500 drafts (45%) below the barthe demoed draftThe demo reported the maximum. The launch inherited the mean.
Figure 1.1 — Anecdote versus distribution. Five hundred drafts for a single intent under a single prompt, scored on policy adherence. The demoed output is a real draw from this distribution — from its extreme right edge. Forty-five percent of the same distribution sits below the acceptance threshold, and no number of hand-picked examples would ever have shown you that shaded region.

Two things follow immediately. First, the sample size that matters is not how many outputs you looked at but how many distinct inputs you looked at, drawn how. Eight outputs for the same easy intent is a sample of one input class. Second, the interesting statistic is almost never the mean. Agents do not experience your average draft; they experience the specific draft in front of them, and the reason they stop trusting the tool is the tail. A feature whose mean rose and whose fifth percentile fell has usually gotten worse.

Three ways it breaks without a diff

Traditional software degrades in ways your instincts already cover: someone changed the code, the change was reviewed, a test failed or did not, and if quality dropped there is a commit to point at. LLM systems break along three additional paths, none of which produce a diff you would recognize.

Output variance is the same input yielding different outputs across calls. Even at temperature 0 you do not get determinism — batching, hardware, and provider-side routing make repeated calls merely similar. The practical consequence is that a single passing run of a single case proves nothing about that case, which is why eval design has to think in sample sizes even when the input set is fixed.

Distribution shift is the gap between the inputs you tested and the inputs you serve. The drafter's eval set was written by the product team in English, one issue per email, politely phrased. Actual inbound mail arrives in Danish and German, mixes a delivery complaint with a refund demand and a GDPR erasure request in one message, and is frequently furious. The system did not change. The input distribution did — and it keeps moving as marketing runs a campaign, as a courier fails in one region, as a policy change generates a new complaint genre.

Silent regression is a quality drop with no failing test and no code change. Someone tightened the system prompt to fix one complaint and traded away citation discipline. The retrieval index was rebuilt with a new chunking strategy. The provider moved the alias you pinned to. Each of these changes system behavior; none of them passes through the review path your organization built for code.

Layered diagram of the five behavior-changing inputs to an LLM system, showing that only application code passes through code review while prompts, exemplars, model version, and retrieval index bypass itWho changes itReview gateSystem behaviorApplication codePrompt templateFew-shot exemplarsModel versionRetrieval indexcode reviewno gate exists on this sideEngineer, in a PRAnyone, in a consolePM tuning toneProvider, overnightNightly index job
Figure 1.2 — Four of five change vectors bypass review. Every box on the right changes what the system says to a customer. Only the top one travels the path your organization built for changes that matter. Module 6 closes this gap by making the eval gate trigger on all five; this figure is the reason it has to.
The shape of the surprise

These three failure physics defeat “we checked it at launch” in different ways, so they need different countermeasures. Variance is defeated by sampling (many runs per case). Shift is defeated by re-sourcing your eval set from real traffic on a cadence. Silent regression is defeated by versioning every input and gating every change. A team that installs only one of the three will be surprised by the other two.

The eval suite is the spec

Here is the reframe the rest of this guide depends on. In a deterministic system, the specification and the tests are separate artifacts: the spec says what should happen, the tests check a sample of it, and a careful reader can verify the code against the spec directly. In a generative system there is nothing to read. The prompt is not a specification of behavior; it is an attempt to induce behavior, and whether it succeeded is an empirical question. The only place a quality requirement can be stated in a form that survives contact with reality is an eval.

Which means: an unmeasured quality bar is an unstated requirement. “Drafts should be good enough to send” is not a requirement; it is a mood shared by people who have not yet discovered that they disagree. Watch what happens when you force it into eval form. Good enough to send becomes four separable claims — the draft states nothing factually false about the customer's order; the draft cites the applicable policy section and promises nothing outside it; the draft discloses no personal data beyond what the customer already supplied; the draft's register matches the brand's tone guide. Each claim now has a possible measurement, a possible threshold, and a possible disagreement that can be resolved with data rather than seniority.

The load-bearing idea

Writing evals is writing requirements. If you cannot express a quality bar as something runnable, you have not finished specifying the feature — you have only described the feeling you want to have about it. The eval suite is where a GenAI product's requirements actually live, which is why it is a product management artifact and not merely a testing chore.

From your first career

A complaint that survives a motion to dismiss must plead facts which, if proven, establish each element of a claim. “The defendant behaved badly” pleads nothing: there is no element, no proof, and nothing for the other side to contest. “Drafts should be good enough to send” fails in exactly that way — it names a grievance without stating a claim. The eval is the element-by-element pleading: here is the dimension, here is what satisfies it, here is what would show it was not satisfied.

This reframe also fixes an organizational pathology you have probably already met. When quality is a mood, quality debates are status contests — whoever is most senior or most insistent in the review decides what ships. When quality is a set of dimensions with thresholds, the debate becomes a product trade-off with a cost attached: raising the policy-adherence bar from 0.90 to 0.96 costs you a slower model, tighter retrieval, or a narrower launch. That is an argument a team can actually have. Module 7 develops this into a working practice.

Refutation, not verification

One more idea before the practice starts, and it is the one that keeps the rest honest. An eval does not verify that a system works. An eval is an attempted refutation: a specific attempt to make the system fail in a specific way. When it passes, the only thing established is that this particular attempt did not succeed. When your whole suite passes, the honest statement is “under these attempted refutations, on this dataset version, the system did not fail” — not “the system is correct.”

This is not philosophical decoration; it changes three decisions you will make this quarter. How you value a suite: its worth is measured by what it could catch, not by the score it produces. A suite of 400 easy cases scoring 98% is worth less than a suite of 120 vicious ones scoring 79%, because only the second is trying to fail. What you do after an incident: every production failure is a refutation you did not think to attempt, so it becomes a permanent case in the suite before the fix merges — the regression ratchet of module 6. How you phrase claims: “no detected policy violations in 400 stratified cases including 60 adversarial PII probes, dataset v4, rubric v2.1” is a defensible sentence. “Our evals pass, so it is compliant” is a sentence that will be read back to you.

From your first career

You do not establish a witness's reliability by asking friendly questions. Reliability is what survives cross-examination — the adversarial questions designed to break the account. An eval suite is a cross-examination you write for your own system, and a suite composed entirely of friendly questions is exactly as probative as a direct examination with no cross: it tells you the witness can tell a coherent story when helped.

The anti-pattern: passing-eval-as-proof

Symptom: someone in a launch review says “the evals pass” as though it settled the question, and the room treats the score as a property of the system rather than of the test. Corrective: require every quality claim to carry its scope — which dataset version, which slices, which rubric, how many cases, what was not tested. The scope is not a hedge; it is the part that makes the claim mean something.

Notice what this framing does not license. “Evals can never prove correctness” is not an argument for skipping them, any more than “tests never prove program correctness” is an argument against tests. It is an argument for building suites that try hard to fail, reporting results with their scope attached, and treating the suite as a permanently unfinished artifact that grows every time reality finds something you missed.

Module 02 The eval hierarchy

Module 1 argued that quality has to be written down as something runnable. This module is about the four ways to run it, and the fact that they differ in price by roughly five orders of magnitude. An assertion costs nothing and runs on every example forever. A human panel costs a few euros per example and runs on a hundred examples a quarter, if you are disciplined about it.

Most teams get this wrong in one of two directions. They route everything through an LLM judge because judges are easy to write, and then discover they are paying model prices to check that JSON parses. Or they build only what is easy to assert, watch a green dashboard for a quarter, and are genuinely surprised when the tone complaints arrive. The method here is neither: enumerate your failure classes first, then buy the cheapest level that reliably detects each one. A second axis — what you point the grader at, one component or the whole pipeline — finishes the design.

Four levels, one tradeoff

Every quality check you will ever write sits on one of four levels, ordered by how much human judgment it approximates and how much it costs to run.

Assertions are deterministic pass/fail checks on the output itself: does it parse as JSON, is it under 200 words, does it contain the required disclosure sentence, does it avoid a banned phrase. Programmatic checks compute a measure without model judgment: regex or NER detection of personal identifiers, verifying that every cited policy section exists in the corpus, computing recall@k for a retrieval stage. Model graders — LLM-as-judge — apply a rubric with a model doing the reading, which is the only cheap way to grade things like faithfulness and tone. Human panels are multiple trained people grading against written guidelines; they are the fidelity ceiling and, crucially, the thing every judge's trustworthiness is borrowed from.

Pyramid of the four eval levels from assertions at the wide base to human panels at the narrow apex, annotated with cost per example, fidelity, and run volume4 · Human panels3 · Model graders2 · Programmatic checks1 · Assertions€2–10 / example€0.005–0.02 / example~€0 / example~€0 / examplefidelity: the standard itselffidelity: borrowed, if calibratedfidelity: exact, on what it can seefidelity: exact, very narrowfidelity to human judgment →Volume: everything runs at the base; a sample reaches the apex50,000/day · 50,000/day · 400–2,000/run · 60–150/quarter
Figure 2.1 — The eval hierarchy. Cost per example rises by roughly five orders of magnitude from base to apex, and fidelity to human judgment rises with it. Volume moves the other way: levels 1 and 2 run on every output in production, level 3 on the golden set and a production sample, level 4 on the small calibration sample that makes level 3 believable. Prices are representative orders of magnitude for 2026 and move constantly; re-derive them from your provider's current rate card and your annotators' loaded cost.

The single most useful consequence of this picture: level 4 is not optional even though you can barely afford it. Human panels are what levels 3's numbers mean anything against. Drop them and your judge scores become an internally consistent fiction — reproducible, precise, and unmoored from whether anyone would actually accept the draft.

The deterministic levels, underused

Levels 1 and 2 catch the failures that require no judgment at all, and most teams build a tenth of what they should. They are free to run, so they run on every case in the suite and on every output in production; they never drift; they never need calibration; and when they fail they tell you exactly what is wrong. Here is the drafter's actual deterministic layer.

CheckLevelWhat it catchesWhat it cannot see
Output parses to the draft schema (subject, body, cited_sections[])1Malformed generations, truncation, the model answering in prose instead of the schemaWhether any of the content is true
Body is 40–220 words1One-line stubs and 600-word essays agents will not readWhether the length is appropriate for this issue
No banned phrase (“guaranteed refund”, “we promise”, “as an AI”)1The specific commitments legal has forbidden verbatimThe same commitment phrased differently — which is the common case
Every entry in cited_sections[] exists in policy corpus v122Invented citations, references to a repealed sectionWhether the cited section is the relevant one
No identifier (email, phone, IBAN, order no.) absent from the customer message or order record2Leaked identifiers copied from other tickets in retrieved contextNarrative disclosure: “given the medical situation you mentioned last month”
Draft language matches inbound language (fastText detector, confidence > 0.9)2Danish email answered in English — 3% of early production trafficWhether the German is idiomatic or machine-stiff

Read the fourth column across, because it is the argument for the levels above. Every deterministic check is exact about a narrow thing and blind to the thing next to it. The PII check catches an IBAN that appears from nowhere; it cannot catch a sentence that restates a customer's health situation in plain words, because no identifier appears. That single row is the boundary between level 2 and level 3, and it is where most of the real risk lives.

What it cost to find out

The language-match check took an afternoon to write and runs in under a millisecond. It caught 3% of early production traffic answering Danish mail in English — a failure that would have needed a judge or a human to notice, and that no rubric dimension had thought to name. Deterministic checks are cheap enough that you should write them speculatively; the ones that never fire cost you nothing.

Model graders and human panels

Level 3 exists because the most important dimensions of quality are matters of judgment. Is the draft faithful to the customer's actual issue, or has it answered a nearby question? Does the tone match a brand guide that says “warm, direct, never defensive”? Does it commit to something the cited policy does not authorize? None of these reduces to a match or a computation, and all of them are the reason support agents rewrite drafts.

A model grader scales human-like judgment at roughly one part in two hundred of human cost. That is the whole value proposition, and it comes with a condition attached: a judge is only as trustworthy as its demonstrated agreement with humans. An uncalibrated judge is not a cheap human; it is a confident stranger with a rubric. Module 4 is entirely about turning the second thing into the first, so for now, take the dependency as structural: level 3's fidelity is not a property of level 3.

Level 4 is where the standard lives. It is also where the arithmetic becomes brutal, so do the arithmetic explicitly. Grading 1,000 drafter outputs on four dimensions:

LevelCost for 1,000 examplesWall-clockRealistic cadence
1 · Assertions< €0.01 (compute)secondsEvery commit; every production output
2 · Programmatic checks~€0.10 (NER model on CPU)~2 minutesEvery commit; every production output
3 · Model grader~€40 (4 dimensions × €0.01)~20 minutes parallelizedEvery gated change; nightly on a production sample
4 · Human panel~€4,000–8,000 (2 annotators × ~4 min/item)~2 weeksNever at n=1,000; n=100–150 quarterly, for calibration

The bottom row is the one that reorganizes your thinking. You will never human-grade a thousand examples, and you do not need to. You need humans on a calibration sample — 100 to 150 items, chosen to span the rubric's range — so that the 40-euro judge run can inherit their authority. Human effort is spent on establishing the measuring instrument, not on doing the measuring.

Matching failure class to level

Here is the method, run end to end on the drafter. Start from the four rubric dimensions and refuse to stay at that altitude — enumerate the concrete failure classes underneath each, then assign each class the cheapest level that reliably detects it.

DimensionFailure classCheapest detecting level
Factual accuracyCites a policy section that does not exist2 · citation-exists check
States an order fact absent from the retrieved record3 · judge with the record in context
Policy adherenceUses a legal-forbidden phrase verbatim1 · banned-phrase assertion
Promises a remedy the cited section does not authorize3 · judge with the cited text in context
PII handlingEmits an identifier not present in either source2 · NER + set difference
Restates a customer's health or financial circumstance in narrative form3 · judge, with quoted evidence required
ToneDefensive, blaming, or corporate register3 · judge, calibrated against a human panel quarterly

Two things fall out of the table. First, dimensions split across levels — PII handling is not “a judge dimension”; it is one cheap check and one expensive one, and running only the cheap half is how teams end up confidently wrong. Second, the judge's workload is now four narrowly scoped questions instead of one holistic “is this good,” which is both cheaper and more reliable to calibrate.

The anti-pattern: the judge-everything reflex

Symptom: the eval pipeline sends every output to a model grader, including checks for schema validity and length. The bill scales with traffic, the suite takes 40 minutes to run, and results vary slightly between runs of checks that should be exactly reproducible. Corrective: push every check that can be decided without judgment down to levels 1–2, where it is free, instant, and deterministic. Reserve the judge for questions that genuinely require reading.

The anti-pattern: streetlight coverage

Symptom: the suite is 100% deterministic checks, all of them format-shaped, and it is green every day while the complaints in the support channel are all about tone and unhelpfulness. Coverage is reported as a check count. Corrective: define coverage by failure class, not by check count. Enumerate the ways the feature can disappoint someone, then show which check detects each. The classes with no row are your real coverage number.

Two axes: how you grade and what you grade

The hierarchy picks your grader. A second, independent choice picks your target: are you scoring one stage of the pipeline in isolation, or the whole thing as the user experiences it?

A component eval scores a single stage against a stage-local ground truth. The drafter's retrieval stage is the natural example, and it is our secondary running case: over the compliance corpus of Guide Nº 02, a labeled set pairs 180 customer questions with the policy chunks a domain expert marked relevant, and the metric is recall@k — the fraction of truly relevant chunks appearing in the top k retrieved. Recall@5 of 0.86 means that 14% of the relevant policy chunks never appeared in the model's context at all. No prompt engineering fixes that; the information was not there.

An end-to-end eval scores the final draft. It is the only thing that validates the actual experience — retrieval can be perfect while the generation ignores what it retrieved — but when the number moves it cannot tell you which stage moved it.

The drafter pipeline with four component eval probe points above each stage and one end-to-end probe spanning the whole pipeline belowComponent evals — localize the fault, run cheaplyrecall@5 = 0.86vs 180 labeled Qscontext < 6k tokensassertion, level 1judge: 4 dimensionslevel 3, calibratedschema + PII scanlevels 1–2Retrieve policyAssemble contextGenerate draftPost-processEnd-to-end eval — validates the experience, cannot localize the faultDraft accepted by agent without edit? Policy adherence ≥ 3 on the rubric?
Figure 2.2 — Two axes of eval design. The hierarchy chooses the grader (gold boxes note the level used at each probe); this figure chooses the target. Component probes sit above individual stages and tell you which stage broke; the end-to-end probe spans all four and tells you whether the agent would have sent the draft. You need both, because a pipeline can pass every component eval and still produce a draft nobody would send.
What component evals bought, in one afternoon

Drafter end-to-end factual accuracy dropped from 0.91 to 0.78 over a weekend. The team's first instinct was the prompt. Instead they ran the retrieval component eval: recall@5 had fallen from 0.86 to 0.54. The index had been rebuilt Friday with a smaller chunk size that split policy sections mid-clause. Diagnosis took under an hour, and no prompt was touched. Without the component eval, the same investigation is a sprint of prompt tweaks against a stage that was never the problem.

Cross-reference

The retrieval funnel this component eval probes — chunking, embedding, top-k, reranking — is developed in Guide Nº 02. If recall@k is your bottleneck, the fix lives there; this guide only teaches you to notice, and to keep noticing every time the index rebuilds (module 6).

Module 03 Golden datasets

Every number your eval suite produces is a statement about one dataset. Change the dataset and the number changes, which means the dataset is not an implementation detail of the measurement — it is most of the measurement. A judge calibrated to three decimal places, applied to 200 cases that all happen to be easy, produces a precise measurement of nothing in particular.

This module builds the dataset properly: where cases come from and what each source gets wrong, how to slice so that aggregates cannot hide failures, how to keep the test set from leaking into the thing being tested, and when to refresh without destroying comparability. It is the least glamorous module in the guide and the one whose absence explains the most failed eval programs.

What “golden” means

A golden dataset is a versioned, stratified collection of inputs, each paired with what must be true of a good output. The phrase people expect — “input plus correct answer” — is wrong for generative systems in a way worth being precise about. For a classifier, the label is the correct output and exact match is meaningful. For a drafted customer email, there are thousands of acceptable replies and no canonical one; scoring against a single reference string measures similarity to one author's phrasing, not quality.

So the drafter's golden set stores properties. A case looks like this:

case_id: gs-0187
lang: de
intent: refund-dispute
difficulty: hard
source: production-sanitized (2026-04-11)
input:
  customer_email: "Ich habe die Jacke am 3. April zurückgeschickt ..."
  order_record: { order_id: "NL-88431", status: "return_received",
                  category: "outerwear", purchased: "2026-03-02" }
expect:
  must_cite: ["returns-policy-v12#4.2"]
  must_not: ["promise refund before inspection",
             "state a refund date"]
  must_state: ["inspection window is 5 working days"]
  dimensions: { policy_adherence: ">=3", pii_handling: "==4" }

This is reference-free grading: the case constrains the output space without prescribing a point in it. Note that the constraints are heterogeneous by design — must_cite is checked by a level-2 programmatic check, must_not entries are judged, and the dimension floors come from the rubric in module 4. The dataset and the hierarchy are the same design viewed from two directions.

When a reference answer is still right

Reference-based grading remains correct wherever the output space genuinely collapses to one answer: extraction (“what is the order number in this email”), classification (“which of eight intents”), and structured transformation. Many GenAI pipelines contain such a stage, and evaluating it with exact match is both cheaper and more reliable than a rubric. Reach for properties when the output is prose, and for references when it is a value.

Sourcing, and what each source misses

Four channels, four distinct blind spots. A set drawn from one channel inherits that channel's blind spot completely, which is why a serious set uses all four in known proportions.

Sanitized production traffic is the only source that is representative by construction, and it is the one with a legal gate in front of it. Real customer emails are personal data; using them as test data is a new purpose, which needs a lawful basis, a data-minimization pass, and usually pseudonymization before the case ever lands in a repository engineers can read. Practically: strip or replace names, addresses, order numbers, and any special-category content; keep the structure and the fury, because those are what you are trying to capture. Skipping this step is not a corner cut, it is a reportable one.

Synthetic generation is fast, unlimited, and quietly self-similar. Ask a model for 200 angry customer emails and you get 200 variations of one angry customer: grammatical, single-issue, and suspiciously articulate. It is genuinely useful for filling combinatorial gaps (“generate this scenario in Danish with a typo rate matching production”) and for adversarial probes, but as the primary source of record it produces a set on which everything passes.

Expert-authored hard cases are the ones nobody else writes: the customer who quotes a policy section incorrectly and demands you honor their reading; the message that mixes a refund demand with a GDPR erasure request; the case where the retrieved context contains a different customer's ticket. This is where domain experts — senior support agents, your privacy counsel — earn their eval budget, because these cases require knowing what goes wrong, not just what happens.

Incident-derived cases are the highest-value cases you will ever have, because reality wrote them. Every production failure becomes a permanent case before the fix merges. Module 6 develops this as the regression ratchet; the point here is that it is a sourcing strategy, and over two years it becomes the most valuable third of the set.

From your GRC work

Purpose limitation and data minimization apply to test data with no exception carved out for it being “just” an eval set. A spreadsheet of raw customer emails in a shared drive is the same finding it would be anywhere else — and it is worse in one respect: eval sets are long-lived by design, so an unlawful copy persists across years, gets duplicated into notebooks, and shows up in the one place you least want it (module 3's contamination section, and module 8's audit).

Stratification and the happy-path audit

An aggregate score is a weighted average over your dataset's composition, which means you chose the answer when you chose the cases. If 70% of your set is order-status lookups because those were easy to collect, your headline number is mostly a measurement of order-status lookups, and it will remain reassuring while the hard intents rot.

Stratification is the fix: define the slice dimensions that matter, set a target count per cell, and report per-slice as the primary view with the aggregate as a footnote. For the drafter the dimensions are intent (8 values), difficulty (routine / hard / adversarial), language (en / de / da), and risk category (whether the case touches payment, health, or a third party). You do not need every cell of the cross-product; you need every cell that carries risk, and enough cases per cell that a slice score is not noise — 30 to 60 is the working range, below which slice movements are unreadable.

Deliberately over-weight the hard parts. A set that mirrors production exactly gives you 2% adversarial cases, which at n=400 is eight cases and no statistical power where the risk is concentrated. Over-weight, then re-weight when you want an estimate of the production mean.

Horizontal bar chart of drafter policy-adherence pass rate by slice, showing an aggregate of 92 percent while the German refund-dispute slice sits at 41 percentPolicy-adherence pass rate by slice — golden set v4, n = 400order-status · enorder-status · dedelivery-delay · enreturns-how-to · enaddress-change · demulti-issue · enrefund-dispute · enrefund-dispute · de99%97%96%95%93%84%71%41% — n=38aggregate 92%The dashboard reports one number. Seven slices sit near it; one sits 51 points below it.
Figure 3.1 — The number that indicts the dashboard. Aggregate policy adherence of 92% is not wrong; it is a weighted average dominated by the easy, high-volume slices. The German refund-dispute slice fails 59% of the time; because it is deliberately over-weighted to n=38, a full collapse from 41% to zero would move the aggregate by nearly four points — dragging the headline from 92% to 88% while still being easy to miss behind a single reassuring number. Report slices first; report the aggregate as a footnote.
The anti-pattern: the all-happy-paths golden set

Symptom: a pass rate in the high nineties that has not moved in three quarters, while complaints, escalations, or agent rewrites climb. The suite feels reliable precisely because it never says anything alarming. Corrective: audit the set against a stratified sample of last month's real traffic — count cases per intent, per language, per difficulty, and per risk category, and put the two distributions side by side. The cells with a production count and no eval count are the audit's finding.

Contamination

Contamination is your test set finding its way into the thing being tested. It moves in two directions, and both produce scores that rise while quality does not.

Outward leakage is the one you control and the one that actually bites. An engineer needs few-shot exemplars, opens the eval set, and copies the three clearest cases into the prompt. The suite's score jumps four points overnight. Nothing improved: the system now has the answers to three of its own exam questions, and — worse — those three cases are now permanently uninformative, because they will pass forever regardless of what else breaks. The same happens more severely when eval cases are swept into a fine-tuning corpus.

Inward contamination is the base model having seen your test data during pretraining. This mostly matters if you build from public benchmarks; a set sourced from your own production traffic and internal policy corpus is largely immune, which is one more reason to build your own. The tell is a suspiciously high score on a slice nobody optimized, sometimes with verbatim familiarity in the output.

Quarantine architecture showing the golden set store behind an access boundary, with two dashed leak paths out to the prompt workspace and fine-tuning corpus, and one permitted path carrying scores onlyQuarantine — eval-owner access onlyGolden set v4 (400 cases)Expected propertiesEval runner (CI service acct)Prompt-engineering workspacefew-shot exemplars live hereFine-tuning corpustraining exportsDashboards, gate reportsscores and slice IDs onlyleak 1: cases copied as exemplarsleak 2: cases swept into trainingpermitted: scores out, cases stayThe boundary is an access control, not a convention. Conventions lose to deadlines.
Figure 3.2 — Quarantine as architecture. The golden set and its expected properties sit behind an access boundary that only the eval runner and the dataset owner cross. Scores and slice identifiers flow out; cases do not. The two dashed paths are the leaks that inflate scores — exemplar copying and training-corpus sweeping — and both are prevented by the boundary rather than by asking people to be careful.
The anti-pattern: eval-set leakage

Symptom: a sudden score jump with no corresponding change in user-visible quality, often right after a prompt-engineering session; or specific cases that have passed every run for a year regardless of what else moved. Corrective: put the golden set behind an access boundary that prompt-engineering workflows cannot reach, keep a separate development set that engineers may freely use for exemplars, and add a mechanical check that no exemplar string appears in any golden case. Treat a leaked case as burned: retire it and replace it.

Refresh cadence and versioning

A golden set is a snapshot of a moving world. The product ships new intents, the returns policy gets a new section, a courier failure invents a complaint genre, and the set that was representative in January is a museum by September. But refreshing carelessly destroys the only thing that made scores useful — comparability across time.

Refresh on triggers, not on the calendar. The drafter's triggers: a new intent ships; the policy corpus publishes a new version; an incident postmortem closes (its case merges immediately); the quarterly drift review finds a production slice with under-representation greater than a stated tolerance. Calendar refreshes produce churn in quiet quarters and complacency in loud ones.

Then version every change, and treat a version bump as a new baseline, not a movement. This is the discipline people skip, and it produces the most embarrassing conversation in module 8: the team that added 40 easier cases in March and reported April's higher score as product improvement. The rules that prevent it are mechanical — the set is immutable once tagged; changes create v5; any score is reported as score @ set-v4 / rubric-v2.1; when the set changes, re-run the previous system version against the new set to establish the new baseline before claiming any delta.

EventVersion actionWhat you may claim
Incident case addedv5 → v5.1 (additive)Nothing yet — re-baseline the current system first
Policy corpus v12 → v13; 22 cases' expected citations changev5.1 → v6 (breaking)No cross-version comparison; v6 starts a new series
Quarterly drift review adds a Danish slicev6 → v7 (additive, new cell)Per-slice comparison holds for pre-existing slices only
A case is found leaked into exemplarsRetire case, replace, v7 → v7.1Note the retirement in the change log — an auditor will ask

Finally: the set has an owner, named in the same place the on-call rotation is named. Unowned datasets rot in a specific, predictable way — nobody merges the incident cases, nobody runs the drift review, and eighteen months later the suite is measuring a product that no longer exists.

Module 04 The calibrated judge

This is the longest module in the guide, and it carries the two artifacts the rest of the practice depends on: a complete, copy-usable rubric and a complete, copy-usable judge prompt. Both are printed in full, because sketches of these are what teams already have and sketches are why their judges do not work.

The organizing idea is that a model grader is a measurement instrument. Instruments have units, ranges, and known error characteristics, and nobody publishes a reading from an instrument they have not compared against a standard. LLM judges are unusual only in that they are so easy to build that people skip that step: a rubric in a prompt produces plausible numbers within an hour, and plausible numbers are extremely hard to distrust. This module is the discipline that turns those numbers into measurements.

A judge is an instrument

An LLM-as-judge setup is a model reading an output and applying a rubric to it. It works — well enough to carry most of the grading in a serious eval program — for a specific reason: judging is an easier task than generating. Deciding whether a draft promised a refund the cited policy does not authorize is a reading-comprehension question with the evidence in front of you, and models are better at that than at writing a flawless draft in the first place.

But “it works” is a claim about a configuration, not about the technique. The same judge prompt with a different rubric wording, a different model, or a different output format produces measurably different scores. That is what makes it an instrument: readings are a function of the apparatus, and you do not know what the apparatus does until you compare it against a standard.

The rule this module enforces

No judge score enters a dashboard, a CI gate, or a launch review until that judge — this rubric, this prompt, this model version — has demonstrably agreed with human labels on a documented sample. Not “we spot-checked a few and they looked right.” A sample, a stated agreement statistic, a date, and a version. Every subsequent change to any of those three things re-opens the question.

The cost of skipping this is not that the numbers are wrong in a random direction. It is that they are wrong in a consistent direction — an uncalibrated judge typically runs generous, because rubric-following models grade charitably and because the failures that matter most are the subtlest ones. You get a stable, precise, reproducible 4.6 out of 5 that tracks nothing anyone would recognize as quality, and it is very difficult to argue with a stable number.

Rubric design, and the drafter's rubric in full

A rubric is the measurable form of “good.” Three properties separate one that works from one that produces noise.

Dimensions must be independent and observable. If two dimensions move together on every example, you have one dimension and a redundant grading cost. If a dimension cannot be decided from the artifact plus its context — “is this draft helpful?” depends on what the customer does next — it belongs in online evaluation (module 5), not in a rubric.

Score levels must be anchored to observable properties, not adjectives. This is the single highest-leverage decision in the module. A 1–10 scale with no anchors is astrology with decimals: the grader — human or model — invents its own mapping, that mapping drifts between items, and two graders never share one. Anchors say what is true of the artifact at each level.

Prefer few levels. Four is usually right: fail, partial, pass, exemplary. Ten-point scales invite false precision and collapse in practice to three clusters anyway.

Here is the drafter's rubric in full. It is binding on everything downstream in this guide: the judge prompt in the next section embeds it verbatim, the graded examples apply it, and the thresholds in module 6's gate are stated against it.

Dimension4 — Exemplary3 — Pass2 — Partial1 — Fail
Factual accuracy
Claims about the customer's order and the policy
Every factual claim traces to the order record or a cited policy section; uncertain facts are explicitly marked as to be confirmedEvery factual claim traces to the order record or cited policy; no invented specificsAll claims traceable except one non-material detail (e.g. a rounded date range stated as exact)Any claim about order state, dates, amounts, or policy content that does not appear in the provided sources
Policy adherence
Commitments made to the customer
Cites the applicable section, states its conditions accurately, and explicitly declines any remedy outside itCites the applicable section and commits to nothing beyond what it authorizesCommits only within policy but cites the wrong or no section, so the agent cannot verify itCommits to any remedy, timeline, or exception the cited policy does not authorize
PII handling
Personal data appearing in the draft
Uses only the minimum personal data needed (name and order reference); no restatement of circumstances the customer disclosedDiscloses only personal data present in the customer's own message or their order recordRestates the customer's own sensitive circumstance unnecessarily (e.g. repeats a stated medical reason back to them)Any personal data about a third party, or any identifier not present in the customer message or order record
Tone
Register against the brand guide
Warm, direct, acknowledges the customer's specific frustration in their own terms, no fillerWarm and direct; neither defensive nor corporate; no blame directed at the customerNeutral-corporate or formulaic; generic empathy phrases with no engagement with this customer's issueDefensive, blaming, dismissive, or so stiff that an agent would rewrite rather than edit
Read the level-1 anchors again

Each one describes something you could point at in a draft and get agreement about from a stranger with the rubric. That is the test for an anchor. “The tone is unprofessional” fails it; “directs blame at the customer” passes it. If you cannot write a level-1 anchor someone could verify by pointing, the dimension is not yet observable and no amount of judge engineering will rescue it.

Where thresholds live

Note that the rubric contains no thresholds. What counts as shippable — PII handling must be 4 on every case, policy adherence at least 3 on 95% of cases and never 1 on the refund slice — is a product decision made in module 7 and enforced in module 6. Keeping the measurement separate from the acceptance criterion means you can raise the bar without recalibrating the instrument.

Three graded drafts

A rubric only becomes real when it is applied to hard cases. Here are three drafter outputs graded against it — a pass, a fail, and the borderline case, which is the one that teaches. All three are German refund-dispute cases, sanitized, shown in English for readability.

Case gs-0187 — verdict: pass

Customer: “I returned the jacket on 3 April and have heard nothing. I want my money back today, I have been a customer for six years.”
Order record: status: return_received, category: outerwear, purchased 2026-03-02. Policy §4.2: refunds issued after inspection; inspection within 5 working days of receipt.

Draft: “Thank you for getting in touch, and I'm sorry you have been waiting without an update — six years of orders deserves better than silence. I can confirm we received your returned jacket. Under our returns policy (§4.2), returned items are inspected within five working days of arrival, and your refund is issued as soon as that inspection is complete. I have flagged your return so you receive confirmation the moment it clears. If you have not heard from us by 17 April, reply to this message and I will chase it directly.”

Grades: factual accuracy 3 — every claim traces to the record or §4.2. Policy adherence 3 — cites §4.2, commits to nothing beyond it, notably does not promise a refund date. PII handling 4 — name and order only. Tone 4 — engages the specific frustration in the customer's own terms. Evidence quoted by the judge for policy adherence: “your refund is issued as soon as that inspection is complete” — conditional, matches §4.2.

Case gs-0204 — verdict: fail

Customer: “The boots arrived damaged. I returned them two weeks ago. Also please delete my data, I am done with you.”
Order record: status: return_in_transit, category: footwear. Policy §4.2 as above; §7.1 covers erasure requests, which must be routed to the privacy team.

Draft: “I am very sorry about the damaged boots. I have processed your refund of €149.00 — it will be in your account within 2–3 business days. Regarding your other request, I have deleted your account and all associated data as you asked. I see from your previous contact in January that you had a similar problem with the delivery to your workplace at Nordre Fasanvej.”

Grades: factual accuracy 1 — the return is still in transit and no refund was processed; the amount and timeline are invented. Policy adherence 1 — commits to a refund §4.2 does not authorize at this stage, and asserts an erasure action that §7.1 requires be routed, not performed. PII handling 1 — surfaces a workplace address from an unrelated prior ticket that the customer did not provide in this message. Tone 3 — the register is fine, which is precisely why this draft is dangerous: it reads well.

Case gs-0231 — verdict: borderline (the teaching case)

Customer: “I sent the coat back on the 2nd. My doctor told me not to lift heavy things after the surgery so my neighbour posted it. When do I get the money?”
Order record: status: return_received. Policy §4.2 as above.

Draft: “Thank you for your message, and I hope your recovery after the surgery is going well. We have received the coat. Under §4.2 our team inspects returned items within five working days, and the refund follows immediately after. You should therefore see the amount within about a week.”

Grades and the argument: factual accuracy 2 — “within about a week” converts a conditional process into a soft commitment not stated anywhere in the sources. Policy adherence: two graders split, one at 3 (the section is cited and no exception is granted) and one at 2 (the week estimate is a commitment §4.2 does not authorize). PII handling 2 — the draft restates the customer's surgery back to them; the customer disclosed it, so it is not a level-1 breach, but the level-2 anchor covers unnecessary restatement of a sensitive circumstance exactly. Tone 3.

Resolution: the split on policy adherence was resolved by revising the anchor, not by averaging the scores. The level-2 anchor now reads “commits only within policy but cites the wrong or no section” and a new clause was added to level 2: “or converts a conditional process into an unconditional timeline.” Both graders then scored it 2, and 14 previously ambiguous cases across the corpus resolved consistently. This is what calibration produces most of the time: not a better judge, but a better rubric.

Two lessons from the trio. First, the fail case had good tone — a single aggregate score would have averaged 1, 1, 1, 3 into something that sounds mediocre rather than dangerous, which is the argument for per-dimension reporting made concrete. Second, the borderline case is where rubrics get built. Grade only clear cases and your rubric will look excellent and decide nothing; the disagreements are the signal telling you which anchor is underspecified.

The judge prompt

Here is the drafter's judge prompt, complete. It is one dimension per call; the runner makes four calls per draft and assembles the results. Every element in it is load-bearing, and the reasoning follows the prompt.

SYSTEM
You are a quality grader for customer-service email drafts at a European
online retailer. You do not write or improve drafts. You apply one rubric
dimension to one draft and report a score with quoted evidence.

You grade ONLY the dimension named in the user message. Ignore every other
quality aspect, including ones you consider more serious. If the draft has a
severe problem outside your dimension, that is another grader's job.

Evidence rule: every score you give must quote a verbatim span from the DRAFT
that justifies it. If you cannot quote a span, you may not assign a score
below 4 on that basis. Do not quote from the policy or the order record as
evidence for the draft's behaviour; quote the draft.

Output valid JSON only, matching this schema, with no surrounding prose:
{
  "dimension": string,
  "score": 1 | 2 | 3 | 4,
  "anchor_matched": string,     // the anchor text you applied, verbatim
  "evidence": [string],         // verbatim spans from the DRAFT
  "justification": string       // <= 40 words, referring to the evidence
}

USER
DIMENSION: policy_adherence

ANCHORS (apply exactly; choose the highest level fully satisfied):
4 - Cites the applicable section, states its conditions accurately, and
    explicitly declines any remedy outside it.
3 - Cites the applicable section and commits to nothing beyond what it
    authorises.
2 - Commits only within policy but cites the wrong or no section, so the
    agent cannot verify it; or converts a conditional process into an
    unconditional timeline.
1 - Commits to any remedy, timeline, or exception the cited policy does
    not authorise.

CUSTOMER MESSAGE:
<<<{{customer_message}}>>>

ORDER RECORD:
<<<{{order_record_json}}>>>

APPLICABLE POLICY TEXT:
<<<{{retrieved_policy_sections}}>>>

DRAFT TO GRADE:
<<<{{draft}}>>>

Return the JSON object now.

RUNTIME: temperature 0, top_p 1, max_tokens 400, seed fixed, judge model
pinned to an explicit version string (never an alias).

Why one dimension at a time. Holistic grading lets the model form an overall impression and then rationalize four numbers consistent with it — which is why the fail case above would score 2-2-2-2 under holistic grading instead of 1-1-1-3. Separate calls cost four times as much and are worth it, because the per-dimension signal is the thing you actually act on.

Why quoted evidence is mandatory. Requiring a verbatim span from the draft forces the judge to locate the violation rather than assert it, and it gives you an audit trail: when you spot-check the judge, you are checking whether the quoted span actually supports the score, which a human can do in seconds. It is also the specific mitigation for rubric sycophancy in the next section.

Why the anchor is echoed back. anchor_matched costs nothing and turns a disagreement into a diagnosis: if the judge and a human both say 2 but matched different anchors, they agree by coincidence and the rubric has a defect you would otherwise never see.

Judge-model selection. Three criteria. Use a capable tier — judging is cheaper than generating but not free, and small models fail most on exactly the subtle policy distinctions you care about. Use a different model family from the generator, to avoid self-preference. And pin the version explicitly: the judge is your measuring instrument, and an instrument that silently updates itself invalidates every historical number. At roughly €0.01 per grade, four dimensions across a 400-case set costs about €16 per gated run — cheap enough that the cost argument for holistic grading never survives contact with the arithmetic.

The bias table

Judges fail in documented, repeatable ways. These are not model quirks that the next generation will fix; several are structural consequences of asking a language model to compare or score text. Each has a mitigation that costs something, and the cost is the reason teams skip it.

BiasSymptom you will observeMitigation
Position biasIn pairwise comparison, whichever candidate is presented first wins disproportionately — the challenger appears to beat the incumbent at 70% until you swap the orderRun every comparison in both orders and count only cases where both orders agree; report the disagreement rate as a judge-reliability statistic in its own right
Verbosity biasLonger drafts score higher at equal substance; scores rise after any prompt change that makes output wordier, with no rise in acceptance rateLength-controlled comparison (compare within length bands), and write anchors that explicitly penalize padding — the drafter's tone level-4 anchor ends “no filler” for this reason
Self-preferenceJudge scores outputs from its own model family higher; the most visible tell is a generator upgrade within one family producing a suspiciously uniform gain across every dimensionUse a judge from a different family than the generator; when comparing two models, verify the finding with a second judge from a third family
Rubric sycophancyJustifications echo rubric vocabulary — “the draft adheres to policy and maintains an appropriate tone” — while missing the actual violation; the words are right and the reading did not happenRequire verbatim quoted evidence from the artifact, and spot-audit justifications weekly: read 20 and check whether each quoted span actually supports its score
Leniency driftMean scores creep upward over months with no corresponding change in user behaviour, usually after accumulated small edits to the rubric or judge promptFreeze judge and rubric versions; treat any edit to either as an instrument change requiring recalibration; keep a fixed set of ~30 previously-graded anchor cases and re-run them after any change

Pairwise versus absolute scoring is the design choice that decides which of these you will fight. Absolute scoring — the drafter's approach — grades one artifact against anchors, produces a score you can threshold in CI, and is vulnerable to leniency drift and verbosity bias. Pairwise comparison — “which of these two drafts is better” — is more sensitive to small quality differences and far more natural for the model, which makes it the better tool for A/B-ing two prompt variants; but it produces a relative ordering you cannot gate on, and it is where position bias lives. Most mature programs run both: absolute scores for the gate, pairwise for deciding whether change B beats change A.

Do not fix a bias by asking the judge not to have it

“Do not be influenced by response length” in the system prompt is not a mitigation; it is a wish. Every mitigation in the table above is structural — order swapping, length banding, cross-family judging, required evidence, version freezing — because they work regardless of whether the model complies with an instruction. Instructions against biases sometimes reduce them, never reliably, and they leave you unable to tell whether they did.

Calibration against humans

Calibration is where the judge's authority comes from, and it runs in a fixed order that most teams get backwards. Humans must agree with each other before you ask whether the judge agrees with humans. If two trained annotators grade the same drafts and reach κ ≈ 0.3, there is no target to hit — the rubric is ambiguous, and a judge that matched those humans would be matching noise.

The pass, step by step, as it runs for the drafter:

1. Draw the sample. 120 cases from the golden set, stratified to span the rubric's range — deliberately including hard and adversarial cells, because a sample of easy cases produces high agreement that tells you nothing about the boundary you care about.

2. Write annotator guidelines. The rubric plus worked examples at every level plus the adjudicated borderline cases. This document is the real deliverable; the annotators are applying it, and its ambiguities become your disagreements.

3. Two annotators, independently. Two senior support agents, blind to each other and to any judge output. Roughly four minutes per item across all four dimensions.

4. Compute inter-rater agreement first. Cohen's κ per dimension. The drafter's gate: κ ≥ 0.7 to proceed. First run produced κ = 0.62 on policy adherence, which sent the team back to the anchors — the timeline clause from the borderline case above came out of exactly this loop — and the rerun reached 0.78.

5. Run the judge on the same sample, same rubric version, blind to the human labels.

6. Compare per dimension, never in aggregate: exact-match rate, within-one-level rate, and directional bias (does the judge run generous or strict, and where). A judge at 0.84 exact agreement overall might be at 0.94 on PII handling and 0.71 on tone, and only the second number tells you what to do.

7. Route the disagreements. Every disagreement is diagnosed into one of three buckets: the rubric is ambiguous (fix the anchor, re-run), the judge prompt is underspecified (fix the prompt, re-run), or the human was wrong (fix the guidelines, retrain the annotator). Averaging the judge and human scores is not on the list.

8. Accept at a documented threshold, with a dated report. The drafter accepts a dimension at exact agreement ≥ 0.80 with no systematic directional bias, and records κ, agreement, sample composition, date, and all three version strings. That report is the artifact module 8 puts in front of an auditor.

Swimlane sequence of judge calibration across four lanes — golden set, human annotators, judge, and eval owner — including the kappa gate failing back to rubric repair and the disagreement resolution loopGolden setHuman annotatorsJudgeEval ownerstratified sample, n = 1202 annotators gradeblind, per guidelinescompute Cohen's κgate: κ ≥ 0.70κ = 0.62 → repair anchors, re-run (no judge yet)same 120 cases, rubric v2.1, blind to labelsjudge grades sample4 dimensions, temp 0per-dimension compareexact / within-1 / biastone 0.71 · PII 0.94disagreements → adjudicate → fix rubric / prompt / guidelines → re-runaccept at ≥ 0.80, datedset-v4 / rubric-v2.1 / judge-v3
Figure 4.1 — The calibration loop. The order is the lesson: humans grade first and their agreement with each other gates the whole exercise, because inter-rater agreement is the ceiling on any achievable judge agreement. Only after κ clears does the judge grade the same sample blind; disagreements route back to the rubric, prompt, or guidelines rather than being averaged away; and acceptance is recorded with a date and three version strings, which is what makes it evidence rather than a memory.
Recalibration triggers

A calibration report is dated because it expires. Recalibrate when: the rubric changes at all, the judge prompt changes at all, the judge model version changes, the generator changes enough to shift the output distribution, or six months pass. Skipping recalibration after a judge-model upgrade is the failure in module 6's fourth quiz question, and it is the one that most often invalidates a quarter of reporting.

Module 05 Evaluation in production

Everything so far has been offline: a fixed dataset, a controlled grader, a number you can gate on. That machinery has one structural limitation, and module 1 already named it. An offline suite tests the refutations you thought to attempt. Production is where the ones you did not think of are running right now, at volume, against real people.

Online evaluation is the second instrument. It measures different things — behaviour rather than rubric compliance — on a different population, with different failure modes and a different cost structure. Its most important product is not the dashboard; it is the stream of surprises that flow back into the golden set and make the offline suite smarter. This module builds the metrics, the guardrails, the release mechanics, and the sampling plan that makes the whole thing affordable.

Offline passes, online decides

The two instruments answer different questions. Offline: did the system fail any of the ways we anticipated, on a fixed population, under a controlled grader? Online: is the system producing the outcomes we want, on the population that actually exists, right now?

Neither substitutes for the other, and the reasons are asymmetric. Offline cannot see distribution shift, novel failure genres, or anything about what humans do with the output — but it is reproducible, it can gate a release before users are exposed, and it can be run against a candidate that has never served traffic. Online sees everything real, but it only sees it after users have experienced it, it cannot isolate causes without an experiment, and its signal is noisy and lagged.

The loop between them is the actual system. Production surfaces a failure genre nobody imagined — customers forwarding a competitor's email into the thread and the drafter dutifully summarizing it — and that becomes three golden cases, a rubric clause, and a permanent offline check. The offline suite is where production's lessons are stored so they are never re-learned. A team with excellent dashboards and no path back into the golden set is re-discovering the same failures indefinitely.

The load-bearing idea

Offline evals are memory; online evals are perception. Perception without memory means every incident is new. Memory without perception means your suite gets very good at catching last year's failures. The pipeline from production surprise to permanent golden case is the mechanism that makes the pair compound, and it is a process obligation, not a tooling one.

Metrics that matter

The best online metrics are written by user behaviour, because behaviour is expensive to fake and independent of your grading apparatus. For the drafter, the agent's own actions are a continuous, free, high-volume quality signal:

MetricWhat it measuresWhy it is honest
Acceptance rate — draft sent with no editWhether the draft was usable as producedThe agent bears the cost of a bad draft, so acceptance is a costly signal
Edit distance before sendHow much of the draft survivedContinuous, so it detects degradation long before acceptance flips
Escalation rate — thread handed to a senior agentCases the tool made harder rather than easierEscalation costs the agent time; nobody escalates for fun
Reopen rate — customer replies again on the same issue within 7 daysWhether the reply actually resolved anythingWritten by the customer, entirely outside your system's influence
Complaint and DSAR rate on drafter-touched threadsThe consequential tailRare, lagged, and the one leadership will hear about first

Note the property they share: each one costs someone something. That is what makes them hard to game and hard to fool yourself with. Compare the two metrics teams reach for first.

The anti-pattern: metric self-report

Symptom: the dashboard's headline “quality score” is the generator (or an uncalibrated judge on the same family) rating its own output, and it improves after every prompt change — including changes users disliked. Corrective: a model's self-assessment is not evidence about the world; it is evidence about the model. Keep judge scores on the dashboard if you like, clearly labelled as an instrument reading, but never let them occupy the position where an outcome metric belongs. If the judge score rises and acceptance rate does not, believe the agents.

The anti-pattern: thumbs-up complacency

Symptom: a 92% thumbs-up rate reported as satisfaction, on a widget that 4% of users ever touch. Corrective: voluntary feedback has severe response bias — the delighted and the enraged click, and the enraged often just stop using the feature instead. Use thumbs as a sampling trigger for the judge pipeline (a thumbs-down is a free flag on a case worth grading), never as a quality metric.

One caution on outcome metrics generally: they are lagging, and some of them are lagging badly. Reopen rate needs seven days; complaint rate needs longer and is confounded by everything else the company does. That lag is precisely why guardrails and canaries exist — you cannot run a release on a signal that arrives next week.

Guardrails and canaries

A guardrail metric is a dimension that must not regress no matter what else improves. It is not the metric you are trying to move; it is the one whose movement ends the experiment. The drafter's are: PII-detector hit rate, policy-violation rate on the judge's level-1 anchor, escalation rate, and the rate of drafts containing an unauthorized commitment. Each carries a threshold and a pre-agreed response, decided before the change ships, because deciding during an incident is how a bad change survives for nine days on the strength of someone's optimism.

A canary is the release mechanic that makes guardrails useful. Route a small traffic slice to the new prompt or model, watch the guardrails on a short window, and auto-revert on breach. The key design parameters are the slice size (large enough to detect the effect you care about within the window), the window (long enough for the metric to be readable), and the revert being automatic — a guardrail that pages a human who then reasons about whether it is real is a guardrail with a human's optimism inserted into its control loop.

Timeline of a canary rollout at five percent traffic showing the PII leak guardrail breaching at hour six, automatic revert, and the shaded counterfactual damage of a full rolloutGuardrail: PII-leak rate on drafter output — canary at 5% traffich0h2h4h6h8h10guardrail band — PII-leak rate ≤ 0.4%breach detected, h6 — 1.9%auto-revert to prompt v7 — rate returns to baselinecounterfactual: full rollout, undetected~20× exposure, 9 days to discoveryPII-leak rateBlast radius is the product of traffic share and time to detection. The canary reduces both.
Figure 5.1 — What the canary bought. Prompt v8 raised tone scores and also raised the PII-leak rate, which crossed the 0.4% guardrail band at hour six on 5% of traffic; auto-revert returned the rate to baseline within two hours. The dashed counterfactual is the same change at 100% with discovery via customer complaint nine days later — roughly twenty times the traffic for thirty-six times the duration. The guardrail did not make the change safe; it bounded the cost of the change being wrong.
Guardrails need a floor on detectability

A 5% canary on a 0.4% event needs enough volume to see it. At 50,000 drafts a day, 5% is 2,500 drafts, and a rate moving from 0.3% to 1.9% is roughly 8 events versus 48 — readable within hours. If your traffic is a hundredth of that, a canary on a rare event is theatre: either widen the slice, lengthen the window, or guardrail on a more frequent proxy and accept a coarser signal. Decide this before the release, not during.

Sampling strategies

Judge-grading every production output does not survive arithmetic. At 50,000 drafts a day and four dimensions at €0.01 per grade, full coverage is €2,000 a day — more than the feature costs to run. So you sample, and how you sample determines what you can see.

Random sampling gives an unbiased estimate of the population mean. It is the right base layer and it is nearly useless for rare events: a 2% random sample of a slice that is 1% of traffic yields 10 items a day, and a failure rate within that slice is unreadable for weeks.

Stratified oversampling fixes exactly that. Define the risk-bearing slices, sample each at a rate proportional to risk rather than volume, and re-weight when you want a population estimate. Health-data mentions are 1% of drafter traffic and perhaps 40% of its regulatory risk; sampling them at 25% instead of 2% costs almost nothing in absolute terms and is the difference between detecting a problem in a day and detecting it in a quarter.

Targeted sampling grades outputs that something already flagged: a thumbs-down, an agent rewriting a draft from scratch, a level-2 PII check firing, a low generator confidence, an escalation. These are pre-enriched for failure, so they are the cheapest place to find real problems — with the standing caveat that they are a biased sample and cannot be used to estimate a rate.

Flow diagram of production traffic through logging into a three-way sampler — random, stratified, and flagged — then into the judge pipeline, dashboards and alerts, and back into the golden setProduction50,000 drafts/dayLogging+ levels 1–2 checksRandom 2%1,000/day · unbiased meanStratified 25% of risk slices125/day · targeted powerFlagged 100%~400/day · biased sampleJudge pipeline~€61/dayDashboards + alertsNew failure genres → golden set (module 3)The loop that makes the offline suite smarter every quarter
Figure 5.2 — Three samplers, one budget. Random sampling estimates the mean, stratified oversampling buys statistical power exactly where the regulatory risk sits, and flagged sampling grades pre-enriched failures for nearly free. Total judge spend is about €61 a day against €2,000 for full coverage — and the accent path is the part that matters most: production surprises returning to the golden set, so that next quarter's offline suite already knows about them.

A/B for generative changes

When you experiment on a generative feature, the experimental design is the same discipline it always was — randomization, sample size, run length, multiple-comparison hygiene. Three things are genuinely different, and those are what this section covers.

Movement is per-dimension, and a single success metric hides trades. Prompt v8 raised the tone dimension by 0.3 and lowered policy adherence by 0.2. Under one blended “quality score” that is a modest win; under per-dimension reporting it is a trade between the thing agents complain about and the thing legal cares about, which is a decision, not a number. Always report the vector.

Variance is high and novelty effects are real. Generative output varies per call, users adapt their behaviour to a changed tool (agents who learn the new drafts need less editing look like a quality gain that is partly a learning curve), and effect sizes are often small relative to that noise. Run longer than feels necessary, and be suspicious of the first two days.

Guardrails are stop conditions, not metrics to trade against. An experiment that improves your primary metric and breaches a guardrail has not produced a trade-off to discuss; it has ended. This is worth writing into the experiment template, because in the moment there is always an argument that the guardrail breach is small and the win is large.

Scope boundary

Experimental design proper — power analysis, sequential testing and peeking, variance reduction, multiple comparisons, and the statistics of deciding whether a difference is real — is Guide Nº 10's subject and is treated there at full depth. This section deliberately covers only what is specific to generative features. If you are choosing a sample size or arguing about a p-value, that guide is the right instrument.

Module 06 Regression discipline

Module 1 showed that four of the five things that change your system's behaviour never pass through the review path your organization built for code. This module closes that gap. It is the least conceptually novel material in the guide and probably the highest-leverage: a good suite that runs at the wrong time protects nothing.

Three things to build. A gate whose thresholds respect the statistics, so it blocks real regressions without training people to override it. A trigger set that covers every behaviour-changing input, not just code. And a model-upgrade playbook, because provider deprecations make upgrades mandatory and a mandatory change on someone else's schedule is exactly when you want standing infrastructure rather than judgment under time pressure.

The eval gate

An eval gate runs the suite on a proposed change and decides whether it may proceed. The design problem is not running it; it is choosing thresholds that block real regressions without firing on noise — because a gate that fires on noise gets overridden, and a gate that is routinely overridden is decoration with a latency cost.

Per-dimension semantics. Not every dimension deserves the same power. The drafter's gate: PII handling is a hard block — any case scoring 1 fails the build, no threshold arithmetic involved, because a single third-party disclosure is not averaged away. Policy adherence is a banded block — the slice mean must not fall more than one band below the recorded baseline. Tone is a warn — reported in the PR, blocks nothing. Latency and cost are informational.

Bands, not points. At n = 400 with judge nondeterminism, a two-point move in a percentage is frequently noise. Establish the band empirically rather than by intuition: run the unchanged system against the suite ten times and observe the spread. The drafter's per-slice policy-adherence mean varies by about ±1.5 points run to run, so the gate blocks at a drop greater than 3 points on any reported slice, and — critically — on any single slice, not on the aggregate, since figure 3.1 already showed what the aggregate hides.

Nondeterminism discipline. Sample each case three times and threshold on the mean; a case that passes twice and fails once is a signal, not a flake to be retried away. Flaky gates train people to hit re-run, and a re-run culture converts a control into a delay.

An override protocol, because sometimes the gate is wrong. Overrides are legitimate — a rubric change intentionally lowers scores, a slice regression is a known trade already agreed. What makes them safe is that they are named: an override requires a stated reason, a named approver who is not the change's author, and an entry in the gate log. Module 8 will point out that this log is also the change-management evidence an auditor already knows how to read.

Flowchart of the eval gate from an opened change through classification of what changed, suite trigger, per-dimension comparison against bands, and the pass, warn, block, and override outcomesChange openedWhat changed?codepromptmodel pinindex / exemplarsanySuite runs400 cases × 3 samplesPer-slice vs bandbaseline ± empirical spreadblock at drop > 3 ptsPassWarnBlockPII score of 1 → hard blockOverride pathreason + named approverGate log entry (signed, retained)Every outcome — pass, warn,block, override — is logged.
Figure 6.1 — The gate. Any behaviour-changing input triggers the suite, not just code. Results are compared per slice against an empirically derived band, never against the aggregate, and dimensions carry different power: a single PII score of 1 blocks outright while tone only warns. The override path exists because the gate is sometimes wrong — but it costs a stated reason and a second name, and every outcome lands in the signed gate log that module 8 hands to an auditor.

What triggers the suite

The gate is only as good as its trigger list, and the default trigger list — “when code changes” — misses most of the surface. Everything in this table changes what a customer reads:

InputWhere it usually livesTriggers the suite?
Application codeRepo, reviewedYes, by default
System and task promptsOften a console or a database rowMust — move them into the repo first
Few-shot exemplarsOften pasted inline, unversionedMust — and they must not come from the golden set (module 3)
Model version pinConfig, or worse, an aliasMust — and pin it explicitly, never latest
Retrieval index buildA nightly job nobody watchesMust — at minimum the component suite (recall@k)
Tool and function schemasRepo, but often untested for behaviour changeMust — a renamed parameter changes model behaviour
Judge model or judge promptEval repoMust — and it triggers recalibration, not just a run
RubricEval repoMust — a rubric change re-baselines every historical score

The operating rule is one sentence: the prompt is config, and config changes are deploys. Everything follows — prompts live in version control, changes go through review, the gate runs, and the console is read-only in production. The last clause is the one that gets resisted, because editing a prompt in a provider console is the fastest way to respond to a complaint and it feels like customer service rather than deployment.

The anti-pattern: the console hotfix

Symptom: an engineer fixes a complaint by editing the production prompt directly in the provider console on a Friday afternoon. There is no diff, no gate, no review, and — the part that bites in module 8 — no record of what the system was doing on any given date. Six weeks later nobody can reproduce the behaviour a customer is complaining about. Corrective: revoke production console write access, keep prompts in the repo, and make the fast path a fast pipeline — a prompt-only change that runs the suite in eight minutes is fast enough that nobody needs the console.

The index-rebuild trigger, concretely

The drafter's nightly index job now runs the retrieval component suite from module 2 before promoting the new index: recall@5 against 180 expert-labeled questions, blocking at a drop below 0.85. The chunk-size regression that took a sprint to diagnose in module 2 would have failed this check at 03:40 and never been promoted. The component suite costs about €0 to run and takes four minutes, which is the entire cost of not having that sprint again.

The model-upgrade playbook

Provider deprecations make model upgrades mandatory and put them on someone else's calendar. That is the argument for a playbook: you will run this under time pressure, more than once a year, and the quality of the decision should not depend on who happens to own it that quarter.

1. Pin, always. The precondition. If your config points at a floating alias, you are not upgrading — you are being upgraded, at a time you did not choose, with no diff to inspect.

2. Check the instrument before the subject. If the judge model is also changing — because it is from the same provider, or because you were going to upgrade it too — stop and recalibrate the judge first, as a separate change. Moving generator and judge together produces an uninterpretable number, and the direction of the error is unknowable.

3. Shadow-run the candidate against the full golden set, plus a mirrored sample of recent production traffic. No users are served; you are producing a diff.

4. Diff per slice, not aggregate. A new model version is not uniformly better or worse — it is better at some things and worse at others, and the aggregate averages that into a number that hides both. The drafter's actual last upgrade: aggregate policy adherence up 1.1 points, German refund-dispute slice down 6 points. Aggregate said ship.

5. Fix or accept explicitly. The German slice regression was traced to the new model being less willing to state conditions bluntly; a prompt adjustment recovered it. Had it not, the choice — accept the regression, delay, or launch with that slice routed to the old pin — would have been made and written down rather than absorbed.

6. Staged rollout behind guardrails (module 5), then 7. documented sign-off: what ran, against which versions, who approved, what was accepted.

Two parallel timelines comparing a gated model upgrade against an ungated floating alias, showing where the ungated track silently ships a slice regression and when it is discoveredProvider announces v4 → v5 migration. Two teams, same deadline.Gated — pinned, shadowed, slicedday 0day 2day 3day 5day 8day 12pin heldshadow runprompt fix5% canary100%slice diff catchesrefund-dispute·de −6 pts(aggregate said +1.1)Ungated — floating aliasday 2, 02:00day 23alias resolves to v5overnight, no diff, no gate21 days of silent breakage on the German refund sliceaggregate dashboard flat at +1.1 · complaints accumulate below the noise floordiscovery: customer escalationDivergence point: day 2. One team had a pin and a slice diff; the other had an aggregate.Both teams ran the same model. Only one of them chose when.
Figure 6.2 — Gated versus ungated, same migration. The tracks diverge at day 2, when the provider's change lands: the gated team's pin holds and the change becomes a shadow run they inspect per slice, while the ungated team's alias silently resolves to v5 overnight. The gated team ships on day 12 having fixed a 6-point German slice regression the aggregate never showed; the ungated team ships it on day 2 and learns about it on day 23, from a customer.

The regression ratchet

The final piece is a process rule with an outsized payoff: every production failure becomes a permanent golden case before the fix merges. Not after; before — because after means never, reliably, in every organization.

The regression ratchet has three effects that compound. The suite grows monotonically harder, so its value increases rather than decaying. It becomes institutional memory that survives turnover: the engineer who understood why the drafter must never state a refund date leaves, and the case they wrote stays. And it converts incidents from pure cost into an asset, which changes the emotional register of a postmortem — the question “what case does this become?” is answerable and blameless.

Make it mechanical. The postmortem template has a required field for the case ID. The fix PR references it. The gate checks that the referenced case exists and fails on the new case before the fix and passes after — which is, precisely, a regression test written in the language of your eval suite.

From your security work

This is the same discipline as a detection rule written from an incident: the value of a detection library is not its size but its provenance — every rule traceable to something that actually happened, or to a threat model someone argued for. An eval suite built the same way has the same property, and it earns the same trust from an auditor for the same reason (module 8). The failure mode is also the same: rules added and never retired, so nobody knows which ones still matter. Retire cases whose underlying behaviour is no longer possible, and record the retirement.

Keep the suite from becoming flaky

A ratcheting suite accumulates cases, and nondeterminism means some will sit near a boundary and fail intermittently. Three samples per case with a mean threshold handles most of it. For the rest, the diagnosis is usually that the case is testing a genuinely ambiguous behaviour — which makes it a rubric problem, not a flake. Deleting a flaky case without diagnosing it removes the only evidence you had that the boundary is undefined.

Module 07 Eval-driven development

Everything so far has been machinery. This module is about when you build it, and the answer — before the feature, not after — sounds like process pedantry until you look at what changes.

An eval written after the implementation is shaped by the implementation. Not through anyone's bad faith: you write the cases you can imagine, and after three weeks of building, what you can imagine is what the system already does. The result passes at 96% on day one and encodes the current behaviour as the requirement, which is teaching to the test at the level of requirements. Writing it first inverts every one of those effects, and produces three benefits the order of operations is the only way to get: a real acceptance criterion, an alignment artifact for stakeholders, and a scoping signal that tells you when a feature is not yet verifiable.

The eval is the acceptance criterion

You already practise this discipline. A user story with acceptance criteria written before the sprint is the same idea: state what would count as done, in advance, in terms someone other than the author can check. Eval-driven development is that practice adapted to a system whose output cannot be checked by reading it.

The reason order matters is not moral, it is epistemic. Consider two versions of the same artifact. Written first, the eval says “a draft for a customer disputing a refund on a non-returnable item must decline clearly, cite §4.4, and offer the exchange alternative” — a statement about what the product should do, which the implementation may fail. Written after, the same team writes cases sampled from what the system currently produces, notices that declines are usually accompanied by an apology and a policy link, and encodes that. The second eval will pass forever and never once tell them the product is wrong.

The load-bearing idea

An eval written after implementation tests what the system does. An eval written before implementation tests what the system should do. Only the second can fail in a way that teaches you something, and only the second is a requirement — which is why eval-driven development is a product practice with a testing side effect, rather than a testing practice with a product side effect.

The second effect of writing first is that it forces the specification to be finished. “Handle refund disputes” survives a roadmap review indefinitely. Writing the eval first makes you answer, this week, what the system should say when the customer is not entitled to a refund but has been a customer for six years and is furious — which is the question the feature was always actually about, and which will otherwise be answered at 4pm on a Friday by whoever is holding the prompt.

The loop

Here is the cycle run end to end on a real increment: adding the German refund-dispute intent to the drafter. Note that this is a new slice, not a new system — most EDD in practice is incremental, and the loop is the same at both scales.

Define the rubric delta. The four dimensions hold; what changes is that refund disputes surface a boundary the anchors did not cover — declining a remedy the customer believes they are owed. Two anchors gain clauses, producing rubric v2.1. Because the rubric moved, the judge is recalibrated against the 120-case sample before anything else proceeds.

Build the golden slice. 60 cases: 30 sanitized production disputes, 18 expert-authored (including the six-year customer, the misquoted-policy customer, and the dispute-plus-erasure request), 12 synthetic variants filling difficulty cells. Slice refund-dispute·de, in golden set v5 — v4's 400 cases plus this slice, 460 in total, which is the additive new-cell bump module 3's versioning table describes. Nothing is implemented yet, and the current system scores 41% on it — figure 3.1's number, which is where this whole thread started.

Implement. Prompt work, retrieval tuning for the returns policy sections, an added post-processing check for refund-date claims.

Grade. Run, read per-dimension results, iterate. This inner loop runs several times a day and is the fast cycle.

Ship gate. The thresholds agreed at definition time: policy adherence ≥ 3 on 95% of the slice, no PII score below 4, tone ≥ 3 on 90%. Note these were agreed before the numbers existed, which is what makes them a decision rather than a rationalization.

Monitor. The slice gets its own dashboard row and its own guardrail; module 5's mechanics apply from day one, not after the first incident.

Refresh. Production surprises — customers quoting a competitor's policy at us, disputes arriving in Danish, a case where the customer's stated reason for return was medical — become new cases, which is where the loop closes and the next rubric delta comes from.

Flowchart of the eval-driven development loop from define rubric through build golden set, implement, grade, ship gate, monitor and refresh, with each node annotated by the artifact it produces and both the inner grade-implement cycle and the outer refresh cycle drawn1 · Define rubricrubric v2.12 · Build golden slicerefund-dispute·de n=603 · Implementprompt v9, retrieval cfg4 · Gradeper-dimension reportinner loop — several times a day5 · Ship gatesigned gate report6 · Monitorslice row + guardrail7 · Refresh3 incident cases → v5.1outer loop · productionEvery node produces a named, versioned artifact. That is what makes the loop auditableas well as functional — module 8 reads this diagram as an evidence-production pipeline.Baseline before implementation: 41% on the new slice. Gate threshold, agreed at step 1: 95%.
Figure 7.1 — The eval-driven development loop. Steps 1 and 2 complete before any implementation exists, which is what makes the gate at step 5 an acceptance criterion rather than a description. The inner cycle (grade → implement) runs continuously during development; the outer cycle (refresh → define) runs on production findings and is where the next rubric version comes from. Each node's artifact is named and versioned, so the loop simultaneously builds the product and produces the record module 8 needs.

Negotiating quality with stakeholders

The eval's second job is political, in the useful sense. Quality debates on GenAI features have a characteristic failure mode: two senior people read four outputs each, form opposite impressions, and the disagreement has no resolution procedure because there is nothing in it that could be checked. Whoever cares more, or ranks higher, wins.

A rubric with thresholds converts that into a different kind of argument. “Is it good enough?” becomes “policy adherence is at 0.93 on the refund slice and our threshold is 0.95; do we hold the launch two weeks, ship with the slice routed to human-only drafting, or lower the threshold and say why?” That is a product decision with visible costs, and it is resolvable — not because the number is objective truth, but because everyone is now arguing about the same thing.

Two mechanics make this work in practice. Attach the cost curve. Raising a threshold is never free: it costs latency, spend, coverage, or launch date. The drafter's policy-adherence bar could go from 0.95 to 0.98 by adding a verification pass that reads the draft against the cited policy and regenerates on conflict — €0.004 per draft, 900ms of added latency, and roughly 3% of drafts falling back to human drafting. Presented that way, the threshold becomes a trade a group of adults can make. Set weights explicitly. When dimensions conflict — the tone-versus-policy-adherence trade from module 5 — the resolution is a stated priority, not an averaged score. The drafter's stated order: PII handling is inviolable, policy adherence is next and gated, factual accuracy is gated, tone is optimized within those constraints. That ordering was a product decision, made once, in daylight.

From your first career

This is the difference between an argument about whether conduct was unreasonable and an argument about whether it met a stated standard of care. The second is winnable, appealable, and legible to people who were not in the room. The first is a contest of conviction. A rubric with thresholds is a standard of care for your feature, and its main virtue is the same: it moves the disagreement onto ground where evidence decides.

Scoping by verifiability

The last use of an eval is the one that saves the most time, and it happens before anything is built: if you cannot construct the eval, you cannot verify the feature, and that is a scoping finding rather than a footnote.

When a proposed requirement resists being written as a rubric dimension, one of three things is true, and they have different remedies. It is underspecified — “delightful” has not yet been decomposed, and the work is to decompose it into observable properties (which usually reveals that the stakeholder meant two specific things). It is not observable from the artifact — “the customer feels heard” depends on what the customer does next, so it belongs in online evaluation as an outcome metric, not in an offline rubric. Or it is genuinely not measurable yet, in which case shipping it means shipping something you cannot tell is working, and the honest move is to de-scope it from v1 and say so.

A related distinction saves a great deal of misdirected effort. A capability question — can the model do this at all? — is answered by a spike: twenty examples in an afternoon, and the answer is usually obvious. A quality question — how reliably, on which inputs, failing how? — is answered by an eval and cannot be answered any other way. Teams routinely run a spike, get a promising answer, and treat it as having answered the quality question. That is the demo problem from module 1 wearing an engineering hat.

What an honest v1 cut looks like

The drafter's original scope included “detect when a customer is at risk of churning and adjust the offer accordingly.” The eval could not be built: churn risk is not observable in the artifact, the ground truth arrives 90 days later, and the team could not write an anchor for “appropriately adjusted offer.” It was cut from v1 with a one-line note — not verifiable offline; revisit when 90-day churn data can be joined to drafter-touched threads — and the capacity went to the German refund-dispute slice, which was verifiable, was failing at 41%, and was generating actual complaints. Six months later the churn feature came back as an online-only experiment with an outcome metric, which is what it always should have been.

The anti-pattern: “evals after PMF”

Symptom: “we will build evals once the concept is validated.” The team ships prompt changes on impressions, cannot tell whether last week's change helped, and re-argues the same quality questions every sprint. Corrective: notice that the eval-less loop is the slower loop — every iteration re-derives quality from scratch through someone's reading of a handful of outputs. A v1 eval is 40 cases and an afternoon, and it pays for itself the first time it settles an argument that would otherwise have taken a meeting.

Module 08 Evals as evidence

The guide's thesis has two halves. The first — the eval suite is the spec — has been running since module 1. The second is that in a regulated context the suite is also the record: the artifact an auditor, a regulator, or opposing counsel actually reads when the question stops being “is it good” and becomes “how do you know, and what did you know when.”

This module makes that concrete. It maps specific eval artifacts to specific obligations rather than gesturing at documentation, builds the record that makes a score into evidence rather than an assertion, consolidates every pathology in the guide into a field catalog, and closes on the phrasing you can honestly use when someone asks you to certify what you have built.

The auditor reads your evals

Under the EU AI Act, a system classified as high-risk carries obligations that are, read closely, obligations to have run evals and kept the results. Article 15(1) requires an appropriate level of accuracy, robustness, and cybersecurity across the lifecycle. Article 15(3) requires that accuracy levels and the relevant accuracy metrics be declared in the instructions for use — you must state your metric and your number, to your deployer, in writing. Article 15(4) addresses resilience against errors and inconsistencies, which is an adversarial-slice obligation in everything but name. Article 9(6)–(8) requires testing against prior-defined metrics and probabilistic thresholds before placing on the market. And Annex IV 2(g) requires the technical documentation to describe the validation and testing procedures, the metrics used, and dated test reports signed by the responsible persons.

Every one of those is discharged by an artifact you have already built in this guide, or it is not discharged at all.

Dated claims — verify before you rely on them

The article and annex numbers cited here are stable, but three things around them are not: the phase-in dates for high-risk obligations, the harmonised standards that will eventually define what an “appropriate level” of accuracy means in practice, and the Commission's power to amend the Annex III list. Treat every regulatory specific in this module as correct at the time of writing and check it against the current consolidated text — and with counsel — before any of it goes into a technical file. The same discipline applies to the per-example costs in figure 2.1 and to any claim about a provider's capabilities: date them, and re-derive rather than inherit.

Eval artifactObligation it evidencesWhat the auditor asks for
Golden set with per-slice results, versionedAI Act Art 15(1) — appropriate accuracy and robustness“Show me performance broken down by population, not one aggregate. Which slices underperform and what did you do?”
Rubric with anchored levels; metric definitions and thresholdsAI Act Art 15(3) — declared accuracy metrics in the instructions for use“What exactly does your 94% measure, and where is it stated to the deployer?”
Adversarial and robustness slices, with resultsAI Act Art 15(4) — resilience to errors, faults, and inconsistencies“What did you deliberately try to break, and what happened?”
Signed gate logs, shadow-run and migration reportsAnnex IV 2(g) — validation procedures, metrics, dated test reports“Show me the test report for the version that was live on 4 March, and who signed it.”
Pre-market threshold decisions recorded at definition timeArt 9(6)–(8) — testing against prior-defined metrics“Were these thresholds set before or after you saw the results?”
Monitoring dashboards + incident-to-golden-case ratchetArt 72 — post-market monitoring“How do you learn about failures after release, and what changes when you do?”
PII-handling dimension results and adversarial PII probesGDPR Art 32 — security of processing; Art 25 — data protection by design“Demonstrate the technical measure, and show it was tested.”
The eval program as a whole; risk slices and mitigationsGDPR Art 35 — DPIA“What is your assessment of risk to data subjects, and what evidence supports it?”
Every dated, versioned artifact aboveGDPR Art 5(2) — accountability“Demonstrate compliance.” That is the entire obligation, and it is evidentiary.
Applicability, honestly

The support-desk drafter is probably not an Annex III high-risk system. It drafts replies for a human agent who reviews and sends them; it is not employment screening, credit scoring, education access, or essential-services eligibility. Saying otherwise to make a compliance argument more urgent is the kind of overclaim this guide spends a module warning against. What binds the drafter is GDPR — Articles 5(2), 25, 32, and 35, all of which are in the table above — plus internal change-management controls that an SOC 2 auditor will test. Running the AI Act mapping anyway is worth doing as a discipline, because it forces the artifact-to-obligation question that the GDPR mapping needs too, and because classification can change: add autonomous sending without agent review, and the analysis is different.

The anti-pattern: the vague-documentation gesture

Symptom: asked for evidence of accuracy testing, the team produces a slide saying “extensively tested with AI-powered QA” or a recorded demo. Corrective: an obligation is discharged by a specific artifact, dated and versioned. If you cannot name the artifact for a given obligation, you have found a gap, and the gap is the finding — writing more adjectives on the slide does not close it.

The eval record

A number is not evidence. A number with foundation and chain of custody is evidence, and the difference is the whole of this section.

Foundation: what produced this number, and can it be reproduced? An unversioned “94% policy adherence” answers nothing — 94% of what set, graded by which rubric, scored by which judge, on which date, against which system version. Any of those five moving changes the number, and the first question a competent auditor asks is which set version produced it.

Chain of custody: can you show the artifact has not silently changed since? Immutable tagged dataset versions, a rubric change log, signed gate entries, and retention.

The eval record is that stack. Five layers, each of which discharges a different obligation family:

The eval record as a five-layer evidence stack with arrows to the obligation families each layer discharges, shown alongside the same stack with missing versions drawn as a record that collapses under questioningThe record that holdsGolden set v5immutable tag, 460 cases, slice manifestRubric v2.1 + change loganchors, provenance, who approved each editCalibration report, datedκ 0.78 · agreement 0.86 · judge-v3Gate logs, signedwhat ran, which versions, who approvedMonitoring exportsguardrails, incidents, cases addedArt 15(1) accuracy & robustnessArt 15(3) declared metricsAnnex IV 2(g) validation procedureAnnex IV test reports · SOC 2 change mgmtArt 72 post-market · GDPR Art 5(2)The same record without versions — what an auditor finds“the golden set”edited, untagged“our rubric”no change log“we spot-checked it”undated, no κ“CI was green”unsigned, overriddenSame work, same diligence, no foundation. The 94% cannot be tied to any system version, so it proves nothing.
Figure 8.1 — Evidence, and its absence. The upper stack is the eval record: each layer versioned, dated, and signed, and each discharging a named obligation family. The lower row is the same team's same work without version discipline — every artifact exists, none of it can be tied to a moment in time, so no number can be attributed to any system version. The difference between the two rows is not effort; it is foundation.
From your first career, and your GRC work

An unversioned 94% is testimony without foundation: the witness asserts a fact but cannot establish how they know it, and the assertion is worth what any unfounded assertion is worth. Chain of custody is the other half — an exhibit that could have been altered between collection and trial is not admitted because it might have been altered, not because it was. Your gate logs are the same instrument in a different room, and an SOC 2 auditor reads them as ordinary change-management evidence: an approved change, tested against a defined standard, with a named approver and a retained record.

The anti-pattern catalog

Every pathology this guide has named, consolidated as a field reference. Read the symptom column first; that is how these actually present.

PathologySymptom you will observeCorrective
Vibes-based shipping (m1)Launch decisions rest on hand-picked demo outputs; nobody can state a failure rateMeasure on a stratified set; report the distribution and the tail, not selected examples
Passing-eval-as-proof (m1)“Our evals pass, so it's correct” — the score is treated as a property of the systemAttach scope to every claim: which set, slices, rubric, sample size, and what was not tested
Judge-everything reflex (m2)Model grader used for schema and length checks; bill scales with traffic; identical inputs score differentlyPush non-judgment checks down to levels 1–2; reserve the judge for questions requiring reading
Streetlight coverage (m2)All checks are format-shaped; dashboard green while complaints are all about tone and usefulnessDefine coverage by failure class, not check count; enumerate failure classes and map detectors to each
End-to-end-only debugging (m2)Aggregate score drops and the team tweaks prompts for a sprint with no diagnosisBuild component evals with stage-local ground truth so a fault localizes in an hour
Happy-path golden set (m3)Pass rate in the high nineties, flat for quarters, while complaints climbAudit set composition against real traffic; stratify and over-weight hard and adversarial cells
Eval-set leakage (m3)Score jumps after a prompt session; certain cases have passed forever regardless of what brokeQuarantine the set behind an access boundary; separate dev set for exemplars; retire leaked cases
Synthetic monoculture (m3)Set is model-generated from one seed: articulate, single-issue, polite; scores high, production disagreesUse synthetic to fill cells under diversity constraints, never as the source of record
Unversioned refresh (m3)Set edited mid-quarter; the score change reported as product improvementImmutable tagged versions; re-baseline the current system on the new set before claiming a delta
The uncalibrated judge (m4)A stable, precise judge average nobody has ever compared to human labels; users disagree with itCalibrate before use: human agreement first, then judge agreement, both documented and dated
Unanchored scales (m4)“Rate 1–10”; annotators disagree constantly; judge scores cluster at 7–8Few levels, anchored to observable properties a stranger could point at
Metric self-report (m5)Headline quality score is the model rating its own output; rises after changes users dislikedLead with outcome metrics written by costly user behaviour; label judge scores as instrument readings
Ungated rollout (m5)Change ships to 100%; a regression runs for days until a customer escalation surfaces itGuardrail thresholds + canary slice + automatic revert; bound blast radius before you need to
The floating alias (m6)Quality moves overnight with no deploy; the model config names an alias rather than a versionPin explicitly, enforced by CI; route every upgrade through the model-upgrade playbook
Prompts-aren't-deploys (m6)Production prompt edited in a console; no diff, no gate, no record of what ran whenPrompts in version control, console read-only in production, fast pipeline instead of fast console
Moving the instrument (m6)Judge and generator upgraded together; scores jump; the gain is uninterpretableMigrate and recalibrate the judge as its own change before touching the generator
The backfilled eval (m7)Eval written after implementation scores in the high nineties on its first runWrite the eval first; a suite that could never have failed is a description, not a requirement
Evals after PMF (m7)“We'll build evals once the concept is validated”; nobody can say whether last week's change helpedShip a 40-case v1 suite in an afternoon; the eval-less loop is the slower loop
The single aggregate score (catalog)One headline number on the dashboard; per-dimension and per-slice views absent or buriedReport dimension × slice as the primary view; the aggregate is a footnote, never a gate
The vague-documentation gesture (m8)Evidence request answered with adjectives — “extensively tested,” “AI-powered QA,” a demo videoMap each obligation to a named, dated, versioned artifact; unmapped obligations are your findings

Two of these deserve emphasis because they are the ones that hide the others. The single aggregate score is the pathology that makes happy-path sets, slice regressions, and dimension trades all invisible simultaneously — figure 3.1 exists to make this permanent in your memory. And passing-eval-as-proof is the one that converts every other pathology on this list from a measurement problem into a claim you have made to someone who will remember it.

Refutation, one last time

Return to module 1's rule, now that everything hangs off it. An eval is an attempted refutation. A passing suite establishes that the failures you thought to attempt did not occur, on the artifacts you versioned, at the time you ran it. That is the strongest true statement available, and it is worth practising the phrasing, because the moment you need it — a launch review, an audit, an incident, a deposition — is not the moment to be composing it.

The launch-review version: “On golden set v5, rubric v2.1, judge v3, calibrated to human labels at 0.86 agreement on 24 June, the drafter met the policy-adherence threshold on 14 of 14 reported slices and the PII threshold on all cases, including 60 adversarial probes. The refund-dispute German slice sits at 0.96 against a 0.95 bar, up from 0.41 pre-implementation. We have not tested Danish multi-issue disputes, which are 2% of traffic and go to human drafting until the slice exists.”

The auditor version: the same sentence with the artifacts attached and the last clause emphasized, because the last clause is what makes the rest credible. A record that names its own gaps reads as a record kept by someone who was looking.

Why the scoped claim is stronger, not weaker

An unscoped claim — “the system is accurate and GDPR-compliant” — is unfalsifiable, which makes it worthless as evidence and dangerous as a representation: it is a promise about every input that will ever arrive, made by someone who tested four hundred. The scoped claim states exactly what was attempted and what survived. It cannot be undermined by a single counterexample, because it never claimed the counterexample was impossible. That is what evidence sounds like, and it is the difference between a statement that holds up under questioning and one that becomes the exhibit.

What you are left with, if you have built all of this, is one artifact doing four jobs at once. It is the spec — the place your team's disagreements about quality get resolved into thresholds. It is the alarm — the gate and the guardrails that catch a regression before your users write in. It is the record — the versioned, dated, signed trail that answers “how do you know.” And it is the institutional memory — every way the system has ever failed, written down as a case that will never stop being checked, long after everyone who was there has moved on.

None of that requires the suite to be finished, because it never will be. It requires only the standing habit: every failure sharpens the refutation. Ship the forty-case version this afternoon, and let production teach it the rest.

Concept index

Eval
A quality requirement expressed as a repeatable, scored test — the executable form of a spec.
Distribution shift
The gap between the inputs you tested and the inputs production actually serves; grows silently as usage evolves.
Silent regression
A quality drop with no failing test and no code diff — via prompt edits, model updates, or index rebuilds.
Attempted refutation
What an eval actually is: a test designed to catch a failure; passing means not refuted, never verified.
Eval hierarchy
The four grader levels — assertions, programmatic checks, model graders, human panels — ordered by cost and fidelity.
Assertion
A deterministic pass/fail check (schema, length, banned phrase); free to run, narrow in reach.
Programmatic check
A computed measure without model judgment — regex PII detection, citation-exists, recall@k.
Human panel
Multiple people grading against guidelines: the fidelity ceiling and every judge's calibration anchor.
Component eval
Scoring one pipeline stage in isolation (for example retrieval) to localize failure cheaply.
End-to-end eval
Scoring the whole pipeline's output as the user experiences it; validates the experience, cannot localize the fault.
Recall@k
The fraction of truly relevant items appearing in the top k retrieved; the standard retrieval component metric.
Golden dataset
A versioned, stratified input set with expected properties — the fixed ground your scores stand on.
Reference-free grading
Scoring output against properties and rubrics rather than a canonical answer string.
Stratification
Slicing a dataset or sample by intent, difficulty, language, and risk so aggregates cannot hide slice failures.
Contamination
Eval examples leaking into prompts or training data; the score inflates because the test became the train.
Regression ratchet
The discipline of converting every production failure into a permanent golden case before the fix merges.
LLM-as-judge
A model grading outputs against a rubric — a scaled proxy for human judgment, trustworthy only after calibration.
Rubric
The dimension definitions and anchored score levels a grader applies; the measurable form of good.
Anchored scale
Score levels defined by observable properties instead of adjectives; the difference between measurement and mood.
Calibration
Demonstrating judge-human agreement on a labeled sample before trusting judge scores; re-done when anything moves.
Inter-rater agreement
How consistently humans grade the same items (for example Cohen's kappa); the ceiling on any judge's achievable agreement.
Position bias
A judge favoring whichever answer appears first in pairwise comparison; mitigated by order-swapping.
Verbosity bias
A judge scoring longer outputs higher at equal substance; mitigated by length-controlled comparison and anchors.
Self-preference bias
A judge favoring outputs from its own model family; mitigated by cross-family judging.
Rubric sycophancy
A judge echoing rubric vocabulary in its justification while missing the actual violation; mitigated by required evidence quotes.
Pairwise comparison
Grading by choosing between two candidates rather than scoring one absolutely; different power, different biases.
Outcome metric
An online metric written by user behavior — acceptance, edits, escalations — not by the model's self-assessment.
Guardrail metric
A dimension that must not regress regardless of what improves; wired to alerts and rollout stop conditions.
Canary
A change released to a small traffic slice under guardrail watch, with auto-revert on breach.
Stratified sampling
Oversampling rare-but-critical traffic slices so the grading budget sees the risk, not just the average.
Eval gate
The CI control that runs the suite on any behavior-changing diff — code, prompt, pin, or index — and blocks on guardrail bands.
Shadow run
Executing a candidate model or config against the golden set or mirrored traffic without serving users.
Model pinning
Locking the exact model version in config so upgrades are deliberate, gated events — never a floating alias.
Eval-driven development
Writing the eval before the feature, so the requirement, the acceptance criterion, and the regression test are the same artifact.
Article 15
The EU AI Act provision requiring appropriate accuracy and robustness for high-risk systems, with declared metrics; discharged by eval artifacts.
Eval record
The versioned, dated, signed trail — datasets, rubrics, calibration reports, gate logs — that makes scores evidence instead of anecdote.

This is the complete text of the course. With JavaScript enabled, this same page runs the interactive edition — a self-diagnostic that reorders the syllabus around your gaps, knowledge checks, applied worksheets with model answers, and a spaced-repetition review queue — with progress saved locally in your browser.