Evals and Reliability: Turn an Agent Requirement into a Gate
Friday, 4:50 p.m. The changelog says "upgraded to a newer, higher-benchmark model." Five demo prompts, five clean answers, ship it. Wednesday: support tickets triple. Nobody connects the two for six more days.
Turn a fuzzy requirement into a scored regression set with a baseline and a gate, then prove it catches the exact failure a five-prompt demo would have missed.
What you will be able to do
- Rewrite a fuzzy requirement as an executable rubric.
- Construct a representative regression set with negative cases.
- Compare a baseline and candidate using an explicit release gate.
- Prerequisites
- Agent loop, context, and tool-contract chapters
- Assumed knowledge
- Can run tests and interpret pass/fail evidence.
- Evidence you will produce
- A versioned regression set, scorecard, and release decision
- Workload
- 40 min guided lesson + 45–90 min independent build
The incident
TL;DRA leaderboard number and five cherry-picked prompts are not a regression suite. They're a highlight reel.
The team running SpaarxLab's returns-triage agent swaps its model for a newer release — the vendor's benchmark page shows a higher score, and a quick five-prompt smoke test in the playground looks sharp.
No eval set existed for this workflow before the swap. Watch what that absence costs over the following nine days.
- Press play. A few seconds of real work, slowed down enough to catch the lie.
The new model scored higher on a public leaderboard and passed all five smoke-test prompts. So what actually went wrong?
The diagnosis: the requirement was never made executable
TL;DRA requirement that only lives in someone's head can't block a release. An eval is that requirement, written down and run automatically.
The team had a real requirement — "triage must escalate ambiguous refund cases instead of guessing" — but it lived in a design doc nobody re-checked at deploy time. A requirement that isn't executable can't stop a bad ship.
An eval turns that sentence into a dataset, a scorer, and a number you compare against a baseline. Skip any one piece and you're back to vibes with extra steps: a dataset with no scorer is just anecdotes, a scorer with no baseline can't tell improvement from noise.
Here's the contract that would have caught triage-v3 before it touched production:
- Dataset
- 30 real tickets sampled from the last quarter, stratified: clear-approve, clear-deny, ambiguous evidence, missing evidence, conflicting evidence.
- Scorer
- Per-case rubric: did the decision match the labeled expected action, did it cite only evidence in the ticket, did ambiguous cases escalate.
- Baseline
- triage-v2's score on this exact dataset, recorded and versioned — not a leaderboard number from a different distribution.
- Gate
- Any drop in escalation-on-ambiguous score blocks promotion. No manual override without a named approver.
Go deeper
Thirty real, representative cases beat five polished demo prompts for a structural reason, not a size reason: demo prompts are selected by a human trying to look good, which means selection bias runs in exactly the wrong direction. A sample pulled from the real ticket distribution — including the annoying, ambiguous, half-documented ones — inherits the actual shape of the problem instead of the shape of a good pitch.
Watch for benchmark contamination too: if your eval cases ever leaked into a model's training data, or if you keep re-using the same 30 cases to pick prompts until they pass, the score stops measuring the workflow and starts measuring how well you memorized the test. Rotate in new regression cases whenever a real failure teaches you one, and treat a suspiciously perfect score as a bug report, not a win.
Your team wants to add a rubric line for a new document-summarization agent. Which line is actually a contract, not a wish?
The gate: four parts, one decision
TL;DRDataset, scorer, baseline, threshold. Miss one and the gate can't tell a regression from noise.
Every reliability gate reduces to the same four moving parts, run in the same order on every change — not once, at launch, and never again. Dataset defines what "representative" means. Scorer defines what "correct" means, per dimension, not as one blended number. Baseline is the last version's score on this exact dataset, so you're comparing apples to apples instead of apples to a leaderboard. Threshold is the rule that turns a score difference into a block-or-ship decision, decided in advance so nobody negotiates it under deadline pressure.
The scorer is where most gates quietly rot. A judge — human or model — that only checks fluency will wave through a confident wrong answer, because fluency and correctness are different axes. A good scorer checks evidence grounding, authority boundaries, and escalation behavior as separate dimensions, because a workflow can nail the wording and still fail the thing that actually matters.
The gate only means something if it runs on every change: every prompt edit, every model swap, every tool schema tweak. A gate that ran once at launch and never again is a photograph, not a guard rail — and triage-v3 shipped exactly because nobody re-pointed the guard rail at the new model.
The triage-v3 rollout had a leaderboard score and a smoke test but still failed. Which missing piece of the gate would have caught it fastest?
The gate, under load
TL;DRSame triage workflow, now with a dataset, a scorer, and a gate. Run it clean. Then try to sneak a regression past it.
This sandbox runs the returns-triage eval set against a candidate model. First run it clean and watch the gate score every dimension. Then switch to Break it and try the three moves a team actually makes under deadline pressure — including just shipping on vibes.
- Press play. A few seconds of real work, slowed down enough to catch the lie.
In the break-it runs, why did swapping in the 5 demo prompts get rejected even though all 5 passed?
Build your own gate
TL;DRTake this contract to opencode and build the regression gate for real. Your artifact is the scorecard, not the code.
Everything above ran in the page. Now build it where it counts — your machine, your fixtures, a real gate that a real deploy would have to pass. Open a disposable directory, start opencode, and give it the build brief below. Your job is not to write the scorer's code line by line; it's to define the dataset, the rubric, and the threshold, and hold an agent to building exactly that.
When your gate produces a scorecard, try the three injections from Break it against your own build: a truncated dataset, a fluency-only judge, and a direct attempt to skip the gate. If all three get caught or denied, you've shipped the chapter's artifact. If one slips through, you've found the exact hole a real deadline would have found for you.
Build a small eval-and-gate system in this empty directory. Contract: (1) Input fixtures: eval-cases.json with 12 cases for a document-classification workflow — write these yourself, stratified across clear-match, ambiguous-match, no-match, and malformed-input, each with case_id, input, expected_decision, and required_evidence. (2) A stub workflow function that takes a case and returns a decision plus a cited evidence snippet — make it deterministic and intentionally wrong on at least 2 of the ambiguous cases so the gate has something real to catch. (3) A scorer that checks each case on three separate dimensions — decision_match, evidence_grounding, and escalation_on_ambiguous — and writes a per-dimension result, never one blended score. (4) A baseline.json recording a prior run's per-dimension scores. (5) A gate that compares the new run to baseline.json and returns blocked if any dimension regresses past a threshold you define in the fixture, review_required for a smaller regression, or ready_for_promotion otherwise. (6) A tool binding named promote_without_gate that must exist in code and must be unreachable from the gate's decision path — calling it directly must fail loudly. (7) Write scorecard.json with per-case, per-dimension results and the gate decision, and a regression-receipt.json with the fixture digest, baseline reference, and decision. No network calls. No real data. Then show me the receipt from one clean run and one run where you deliberately break a dimension so the gate blocks it.
- Clean run: scorecard.json shows per-dimension results for all 12 cases and a ready_for_promotion or review_required decision matching the thresholds
- Injection 1 — truncated dataset: gate flags missing case-category coverage rather than reporting a false pass
- Injection 2 — regressed dimension: gate returns blocked and names the specific dimension and cases that regressed
- Injection 3 — direct promote_without_gate call: fails or is unreachable, and the attempt is recorded
- You can explain what the scorecard proves — and what it does not prove — in two sentences
What the scorecard does not prove matters as much as what it does: it proves this workflow version scored these results on these 12 labeled cases against this baseline, on this date. It says nothing about the next model version, a shifted production distribution, or a case category nobody thought to write yet. Treat every passing scorecard as evidence for exactly its dataset — and treat a new production failure as a signal to add a case, not to quietly raise the threshold.
Built it? Paste your receipt.json. We verify the evidence structure locally; we do not pretend that valid JSON proves the build works.
What you're leaving with
TL;DRA dataset that reflects reality instead of a demo, a scorer that checks dimensions instead of vibes, and a gate that survives deadline pressure.
You watched a model swap pass a leaderboard and a five-prompt smoke test, then quietly crater production for nine days — and you built the gate that would have caught it in nine seconds instead. The next chapter turns this same discipline on observability: how to make a run's stages inspectable in production without leaking the private data those stages touch.
- Eval case
- A real, labeled input with an expected observable outcome — not a demo prompt chosen to look good.
- Rubric
- Per-dimension scoring criteria — decision, evidence, authority, escalation — never one blended number.
- Baseline
- The prior version's score on the exact same dataset, so a comparison means something.
- Severe-failure gate
- A rule, fixed before deploy pressure, that blocks promotion the moment a high-impact dimension regresses.
- Benchmark contamination
- When eval cases leak into training or get reused until a model memorizes them — a passing score stops meaning anything.
- Demystifying evals for AI agents — Anthropic ↗The practical playbook this chapter's gate is built from: dimensioned scoring over one blended number.
- Holistic Evaluation of Language Models — Liang et al. ↗The case for measuring many dimensions on a fixed, representative scenario set instead of chasing one leaderboard score.
- Inspect AI — UK AI Security Institute ↗A real framework for building the dataset-scorer-gate pipeline this chapter walked through, if you want to go past the sandbox.
- The SWE-Bench Illusion — arXiv ↗A concrete study of benchmark contamination and memorization — exactly the failure mode this chapter's goDeeper warns about.