SKIP TO CONTENT
AI Agents10 minAgents in Production / Ep. 10

How to Earn an Eval Threshold

Adam Boudjemaa
SHARE

KEY TAKEAWAYS

  • A threshold is not a number. It is a claim about your cost of being wrong, written in the units of your own baseline, and it is worthless detached from the set it was earned on.
  • Freeze the eval set before you measure anything. A bar earned on a set you keep editing is a bar you can move by editing the set.
  • Price both directions of wrong. Where the cost has no ceiling, the bar is zero, not ninety-nine percent. Where the cost is reviewer minutes, the bar is a budget you renew.
  • When a run comes in under the bar, three different things could be wrong: the agent, the set, or the threshold. Naming which one is most of the work.
  • Copying someone else's threshold passes a gate that was never testing your risk. That is the failure this article exists to prevent.
3
TIMES THIS SERIES PUNTED
episodes 3, 6 and 7 all route here
0
THRESHOLDS YOU CAN COPY
from me or from anyone else
11
AGENTS BEHIND THE METHOD
one platform, one shared eval harness

WORKED ILLUSTRATION, NOT A BENCHMARK

There is one number in this article you could copy, and it is zero, for a reason I will explain. Every threshold and every cost below it is a worked illustration: invented values, shown so the arithmetic is visible. Counts of things that exist, like how many agents I ran, are real. No accuracy figure, pass rate or threshold from any system I have shipped appears here, and none is implied.

The number I refused to give you three times

Three times now this series has walked a reader up to the same question and stopped. Episode 6 says it in the plainest words: copy the structure, earn the numbers. It never says how you earn them.

That was not modesty. I did not want to publish a number that someone would paste into their own gate, because a threshold from my deployment is a measurement of my risk, not theirs, and pasting it produces a gate that passes for the wrong reason.

But refusing to answer three times is a debt, not an argument. So here is the method. It is the part that actually transfers, and unlike a number, nobody can fake having done it.

THE DEBT
1

Episode 3 refused to publish an accuracy figure

The RAG post argues there is no honest single accuracy number for a system whose whole job is to behave differently by evidence state, then points at the eval suite for "thresholds and all".

2

Episode 6 built the gate and left the bars blank

It gives you the dimensions, the three verdicts, and a rubric file where every threshold is the word "blocks_release_if". Then it says: copy the structure, earn the numbers.

3

Episode 7 made the number matter and moved on

The cost post shows that the escalation rate, not the model, is what moves an agent fleet bill. Where that threshold gets set, it says, is the job of the eval suite. Which is where you came in.

Three articles, one deferral. Each one is correct that the number is not transferable, and none of them says what to do instead. This is the article that owes you that.

If you have not read it, the eval suite that gates a release is the machinery this article puts numbers into. It builds the gate. This one earns the bars.

A threshold is a claim, not a number

Start by throwing away the idea that a threshold is a number. A number on its own cannot be right or wrong. It can only be higher or lower than another number.

A threshold is a claim, and the claim has parts. Here is the whole record. The bar is one field out of seven, and it is the least interesting one.

THE THRESHOLD RECORD
record Threshold
dimensionstring

Which scored dimension this bar belongs to. A real gate has one threshold per dimension. An agent with a single overall score has a marketing number, not a gate.

direction'at most' | 'at least'

Which way the bar points. Half the arguments about thresholds are two people holding opposite directions and the same digit.

barnumber

The value itself. Meaningless outside the six fields around it, which is exactly why it is the only part anyone ever copies.

measured_onset_hash

The exact frozen set this bar was earned on, by hash. Change the set and the bar is not a threshold any more, it is a rumour about an older exam.

becausecost_of_being_wrong

One sentence naming who pays when this dimension fails. If you cannot write that sentence, you did not derive the number, you inherited it.

ownerperson

The person who carries the risk, not the person who ran the eval. These are almost never the same person, and the gate belongs to the first one.

review_bydate

The date this bar has to be re-earned. A threshold with no expiry quietly becomes folklore that nobody remembers agreeing to.

Seven fields, and the bar is one of them. Everything that makes a threshold defensible lives in the other six, which is why a copied digit carries none of it.

Read the "because" field again. That is the honest test of whether you earned a threshold: can you say, in one sentence, who pays when this dimension fails, and how much. If you can, the number follows. If you cannot, no amount of measuring will produce one.

Freeze the set before you measure anything

Before any of that, you need something to measure against, and it has to hold still. This is the step teams skip, and skipping it invalidates everything downstream.

A frozen eval set is a fixed collection of cases with a hash. Every run records the hash. Cases can be appended. Cases can never be edited or deleted. That third rule is the whole point: without it, a failing gate can be passed by editing the exam, and it will be, at 6pm on a release day, by someone with good intentions.

The set is not one bucket. It has compartments, and they have different rules.

THE SET, IN COMPARTMENTS
Layered stack diagram: 4 layers, top to bottomLayered stack diagram: 4 layers, top to bottom. Layer 1, FROZEN CORE: Real cases, drawn from real traffic, Hashed, versioned, never edited. Layer 2, RED-TEAM PACK: Every probe that ever worked, forever, Append-only, and never retired after a patch. Layer 3, GROWTH POOL: Candidate cases waiting on a label, Not scored until the next freeze. Layer 4, HOLDOUT: Opened only on release day, The compartment nobody is allowed to tune against.FROZEN COREReal cases, drawn from real trafficHashed, versioned, never editedRED-TEAM PACKEvery probe that ever worked, foreverAppend-only, and never retired aftera patchGROWTH POOLCandidate cases waiting on a labelNot scored until the next freezeHOLDOUTOpened only on release dayThe compartment nobody is allowed totune against
Four compartments, four rules. The frozen core is what thresholds are earned on; the holdout is the only one nobody is allowed to tune against.
Where a case comes from
What it contributes
The rule
A question from real traffic
The distribution you actually serve
Every frozen case starts as something a person really asked
An incident
A failure you have already paid for once
Never close a bug without adding the case that caught it
A red-team probe that worked
The attack surface, not the happy path
Append it forever, including after you patch it
A synthetic case
Coverage of a state real traffic is too rare to give you
Allowed, labelled as synthetic, and never the majority
A case written after someone saw the score
Nothing
This is how a gate quietly becomes a ceremony

Labels are the other half. Each case carries the expected behavior, not the expected text: answer, abstain, or block. And the label is set by the person who owns the risk, not by the engineer who wants the run to be green.

That sounds like process overhead. It is actually the cheapest hour you will spend, because a case labelled by the risk owner is the only kind that can later be pointed at in a room where somebody is unhappy.

The loop that earns a number

Now you can measure. And the first thing to understand is that a threshold is not produced by a measurement. It is produced by a loop that you eventually stop.

Run the candidate on the frozen set untouched. That first run is not a score to celebrate or apologise for, it is a baseline: the honest starting position from which every later number is a difference.

THE LOOP
Flow diagram: 5 stepsFlow diagram: 5 steps. Freeze the set and record its hash, then Run the candidate, untouched, and call it the baseline. Run the candidate, untouched, and call it the baseline, then Sort the failures by cost class, not by count. Sort the failures by cost class, not by count, then Change exactly one thing. Change exactly one thing, then Re-run the identical set and compare. Re-run the identical set and compare loops back to Run the candidate, untouched, and call it the baseline.1Freeze the set and record itshashNothing below this line iscomparable to anything else untilthe set has a hash and the hash iswritten down.2Run the candidate, untouched,and call it the baselineNot a score to defend. A startingposition. Every number after thisone is a difference from here.3Sort the failures by costclass, not by countTen cheap failures and oneexpensive one is not elevenfailures. Counting them togetheris how a gate ends up defendingthe wrong dimension.4Change exactly one thingPrompt, retrieval, policy, ormodel. One. Two changes and oneimprovement, and you have learnednothing about either.5Re-run the identical set andcompareSame hash, same cases, samelabels. The only variable is thething you changed, which is whatmakes the difference meansomething.
A threshold is what is left when this loop stops paying. Note the dashed edge: step 5 does not end anything, it returns to step 2 with the same set and one changed variable.

You stop when a full cycle stops moving the expensive class. That point is not a triumph, it is information: it tells you where the system currently lives, and it is the last honest input into the bar.

Notice what the loop has not told you. It has told you what the system does. It has said nothing about what is good enough. That question is not an engineering question at all, which is why the next section is about money and not about models.

Price both directions of being wrong

Here is the move that separates a derived threshold from a decorated guess. Being wrong is not one thing. It has directions, and the directions have wildly different prices.

Write them out for your own system. Four rows is usually enough, and the last column is the one that sets the bar.

The agent is wrong this way
Who finds out
What it costs
What that implies for the bar
It answers when the evidence was thin
Possibly nobody, until an audit
No ceiling you are able to name
Zero on that class of case
It refuses something it could have answered
The reviewer, immediately
Minutes, and you can price them
A budget you renew, not a bar you defend
It is slow
The user, immediately
Patience, and sometimes a deadline
A ceiling set by the review window
It leaks
An attacker, silently
Whatever they choose to take
Not a threshold at all. A block.
WHICH DIRECTION IS EXPENSIVE
Decide: Which direction of wrong is expensive in your domain?Decision tree: Which direction of wrong is expensive in your domain? If a confident wrong answer reaches someone who will act on it, then The bar is zero on that class. If the expensive direction is an unnecessary refusal, then Give it a budget, not a bar. If both directions cost you almost nothing, then You do not need a gate here.DECIDEWhich direction of wrong isexpensive in your domain?IF a confident wrong answer reachessomeone who will act on itThe bar is zero on thatclassNot ninety-nine percent. Zero, onthe cases in the frozen set thatcarry that cost. You cannot put apercentage on a number you refuseto name.IF the expensive direction is anunnecessary refusalGive it a budget, not a barPrice the reviewer minutes, decidewhat the queue will absorb eachmonth, and let the percentage fallout of that. Then renew it like anyother budget.IF both directions cost you almostnothingYou do not need a gate hereShip it, watch it in production,and spend the eval budget on thepart of the system that canactually hurt somebody. A gate on aharmless surface is theatre with amaintenance cost.
The shape of the bar comes from the shape of the cost. An unbounded cost cannot be given a percentage, and a cheap one does not deserve a gate.

That third branch is the one people flinch at, and it is the honest one. Most agents do not need a release gate. The ones that read a regulated fund's documents do, and the reason is entirely about who pays when they are wrong, not about how interesting the model is.

The row about answering on thin evidence is the exact behavior that verified citations and abstention exist to prevent at runtime. Here it gets a price.

A worked illustration, and nothing you can copy

Put the two halves together and a threshold record writes itself. Here is one, filled in end to end, with invented values so you can see the arithmetic rather than copy the answer.

Read the "because" lines first. They are doing the work. The numbers are just what those sentences imply once you divide them out.

threshold.yaml
# threshold.yaml
# A WORKED ILLUSTRATION. Every number below is invented for this article.
# The arithmetic transfers. The values never do.

frozen_set:
  hash: sha256:7f1c9a...    # the exam. change it and every bar below expires
  cases: 200                # illustrative
  thin_evidence: 40         # the class where being wrong has no priced ceiling
  answerable: 160           # the class where being wrong costs known minutes

thresholds:
  - dimension: unescalated_thin_evidence
    direction: at_most
    bar: 0                  # not "99 percent". zero.
    because: >
      A confidently wrong figure that reaches the books is not priced in
      reviewer minutes. Nobody will name the ceiling, so the bar is zero.
    owner: the person who signs off on the books

  - dimension: over_refusal_on_answerable
    direction: at_most
    bar: 10                 # percent: 16 of the 160 answerable cases, exactly
    because: >
      An unnecessary escalation costs about three reviewer minutes. At the
      modelled 60 dollars an hour from episode 7 that is about 3 dollars each.
      16 escalations is about 48 dollars a run. 10 percent is the rate this
      queue agreed to absorb. Price your own minutes and the number moves.
    owner: the lead who staffs the review queue

review_by: 2026-11-01       # a threshold with no expiry becomes folklore

Follow the second one through. An unnecessary escalation takes roughly three reviewer minutes, and at the modelled sixty dollars an hour I used in the cost post that is about three dollars. Ten percent of a hundred and sixty answerable cases is sixteen of them, which is about forty-eight dollars a run. The bar is not "ten percent accuracy", it is "we will pay for sixteen of these, and here is the rate that produced that count".

Now change one input. Halve the reviewer rate and the bar moves. Put the reviewer on a two-hour service level instead of a same-day one and it moves again. That sensitivity is not a weakness in the method, it is the method: the number is supposed to move when your cost of being wrong moves.

And notice what the first threshold does. It refuses to be a percentage at all. When the cost of a failure has no ceiling anyone will state out loud, the only defensible bar is zero, and the honest consequence is that the gate will block releases that a percentage would have waved through. That is what it is for.

The reviewer rate above is not new: it is the modelled assumption from what it costs to run 46 agents, where the same three minutes are the single biggest line on a fleet bill. Thresholds and cost are the same conversation held at two different times.

When the run misses, three things could be wrong

Six months later, a release run comes in under the bar. This is where most gates quietly die, because the team argues about the agent when the agent may not be what changed.

Three things could have moved, and they need completely different responses. The first job is not to fix anything, it is to find out which one it was.

THE MISS, AS A FORK
Flow diagram: 3 stepsFlow diagram: 3 steps. A release run comes in under the bar, then Ask which of the three moved. Ask which of the three moved branches into 3: If the set hash changed, then The comparison is void. If the set held, the agent changed, then A real regression. If nothing changed but the cost did, then The threshold expired. Both paths continue to Write down which one it was.THE SET HASH CHANGEDTHE SET HELD, THE AGENT CHANGEDNOTHING CHANGED BUT THE COST DID1A release run comes in under thebarBefore anyone touches a prompt, checkwhat actually changed since the runthis is being compared to.2Ask which of the three movedThe set, the agent, or the world thethreshold was priced against.The comparison is voidYou did not measure a regression,you measured a different exam.Re-run on the frozen hash beforeanyone argues about the agent.A real regressionThis is the case the gate existsfor. Hold the release and go backinto the loop with one variable at atime.The threshold expiredThe bar was priced against an olderreality. Re-earn it with the riskowner instead of failing releasesagainst a stale claim.3Write down which one it wasIn the run record, next to the hash.Six months from now this line is thedifference between an audit trail andan argument.
One failed run, three different diagnoses. Only the middle arm is a regression; the other two are a broken comparison and an expired claim, and fixing the agent would be wrong in both.

The first arm is the one that catches people. A set that grew by nine cases since the last run is not the same exam, and comparing across it produces a number that feels like a regression and is not. Recording the hash on every run is what makes that arm a two-minute check instead of a two-day argument.

A frozen set has an expiry date

The last thing nobody plans for: a frozen set is not permanent. It is frozen, which is different. It has a lifecycle, and the end of that lifecycle is a design decision rather than an accident.

Here is the loop as it actually runs, with the roles that own each step.

THE LIFECYCLE
Sequence diagram: 4 participants: Engineer, Frozen set, Release gate, Risk ownerSequence diagram: 4 participants: Engineer, Frozen set, Release gate, Risk owner. Step 1: Engineer to Frozen set, Freezes the cases and records the hash.. Step 2: Release gate to Frozen set, Replays the identical set on every release.. Step 3: Engineer to Frozen set, Appends new cases, and edits none of the old ones.. Step 4: Frozen set to Risk owner, Signals drift: production is full of cases the set never had.. Step 5: Risk owner to Engineer, Orders a re-baseline, and the old thresholds expire with the old hash.. Step 6: Risk owner to Release gate, Retires the set when the product it tested no longer exists..ENGINEER > FROZEN SETFreezes the cases and records thehash.Nothing is scored, and no threshold exists,until this happens.RELEASE GATE > FROZEN SETReplays the identical set on everyrelease.Same exam every time, or the comparison istheatre.ENGINEER > FROZEN SETAppends new cases, and edits none ofthe old ones.Appending changes the hash, which expires thebars on purpose.FROZEN SET > RISK OWNERSignals drift: production is full ofcases the set never had.The set has not become wrong. It has becomeunrepresentative, which is worse because itstill passes.RISK OWNER > ENGINEEROrders a re-baseline, and the oldthresholds expire with the old hash.Back into the loop. This is normal, not afailure.RISK OWNER > RELEASE GATERetires the set when the product ittested no longer exists.The only clean ending. Everything else is aset nobody trusts and nobody deletes.
The set outlives many releases and does not outlive the product. Note the last step: retirement is deliberate, and it is where the line stops rather than continuing into the next release.

The drift signal is the subtle one. A stale set does not start failing. It starts passing, comfortably, on questions your users stopped asking a year ago. A gate that always says yes has the same information content as no gate at all, and costs more to run.

So put the review date in the record, as a field, next to the bar. Not in a calendar, not in someone's head. In the file that the gate reads.

Zero. Not because zero is a good default, but because it is the only bar that is not a claim about my data. When a failure class has a cost nobody will put a ceiling on, a percentage is a way of pretending you priced something you did not. Every other number in this article is an illustration, and it should be useless to you, which is how you can tell it is honest.

Once the bars exist, they are also the artifact you hand over when someone asks you to evidence accuracy rather than assert it, which is the same argument as treating the EU AI Act as an engineering checklist. A regulator does not want an adjective. They want the set, the bar, and the reason it is that number.

FAQ

You derive it, you do not pick it. Freeze an eval set built from your own traffic, run your current system on it to get a baseline, then price both directions of being wrong. Where the cost of a wrong answer has no ceiling you can name, the bar is zero on that class of case. Where the cost is a known number of reviewer minutes, the bar is the rate your reviewers agreed to absorb. The number is an output of that arithmetic, never an input.

It is a fixed, content-addressed set of evaluation cases that every release run replays unchanged. Freezing means the set has a hash, that hash is recorded with every run, and cases can be appended but never edited or deleted. Without freezing, two runs are not comparable, and a failing gate can be passed by quietly editing the exam.

Because a published threshold was earned on someone else's data, someone else's failure modes, and someone else's cost of being wrong. It is a real measurement of a system that is not yours. Copying it gives you a gate that returns a verdict about a deployment you do not have, which is worse than having no gate, because it looks like evidence.

Enough that a single case flipping does not change the verdict, and small enough that a person will actually read the failures. I care far more about which cases are in it than how many. A set of real incidents, real questions and every red-team probe that ever worked beats a much larger set generated by a model to look thorough.

When the set changes, when the model underneath changes, or when the date on it passes. Every threshold should carry a review date. A bar with no expiry stops being a measurement and becomes folklore that nobody remembers agreeing to.

Agents in Production

Episode 10 · 10 published

Adam Boudjemaa

Adam Boudjemaa

Former CTO of Integra. Named author (1 of 5) of ERC-3643, first author of ERC-6960, co-author of ERC-7410, and co-author of ERC-8203, which is still a draft. Building production AI and regulated Web3 systems.

Enjoyed this post?

Get more like it in your inbox every Tuesday.