Evaluating in Production, Without Pretending
Your coding agent closes a ticket overnight. The suite is green, the diff is short, the reviewer approves it before the coffee is cold. By every number on your dashboard that was a good run. Then you open the recorded run, out of habit, and count ten calls that did nothing — the same file read four times, the test suite launched again before anything had changed — and one retry that reran a command with a flag you would never have typed yourself. Nothing failed. The result is fine. What produced it is not something you want happening a thousand times a day.
A clean cup does not clear the run
Milk arriving at a creamery is heated and held at temperature for a fixed number of seconds before it goes anywhere near a carton. At the end of the line somebody draws a cup from the finished product and sends it off for a bacterial count, and it comes back clean. That is the result. Beside it hangs the chart from the holding tube: temperature against time for the whole run, and every moment the diversion valve tripped and sent milk that had run cold back to the start. A run can give you a clean cup and a chart with three diversions on it. Nobody releases it on the strength of the cup, because the cup only says the milk in the cup was fine. The chart says whether the run was ever under control.
An agent gives you those same two readings. One side asks whether the task succeeded, how good the answer was, how long it took. The other watches the road it travelled: which tools, in what order, how many retries, which decisions at each turn. A rubric breaks a broad word like safety into criteria that something can actually check, and when a judge does the checking, you calibrate it against people first. The overnight run passes on the first reading and fails on efficiency and safety, and the canary stops widening until somebody fixes it.
Two runs pass and one got lucky
Two agents turn the same tests green. The first reads the failing test, explores until it finds the bug, writes a patch, then checks the cases around it. The second alternates edits and test runs almost at random, keeps whatever makes the bar go green, and never looks at what else it broke on the way. Both come back marked pass. Only one of them did the work. The other got what the research calls a lucky pass, and one column of results will hire it again tomorrow.
The way to tell them apart is to label what each action was for: exploring, implementing, verifying, or arranging the work. Several passing runs of the same task then merge into a picture of how that task normally gets done, and the place where a run departs from that shape is where the luck begins. A quality score and a waste signal fall out of it. The uncomfortable finding is that ranking models this way can put them in a different order than the pass rate does — the suite had told you they were equal. Which matters most for the decision nobody writes down: which of the two you are willing to leave running unattended, since a chaotic process is fragile and expensive even on the days its last test passes.
Production rarely hands you the right answer
None of this stops at the release. A creamery does not wait for the finished carton either; cups come off the line while it runs. So the live system samples real sessions and hands them to evaluators for response quality, task completion, safety and tool use, while every change still goes through programmatic checks on the way in. Sampling is a policy you write down, not a habit, because those sessions carry other people’s data.
The word pretending belongs here. Assertions, reference answers and expected tool sequences give you a right answer where one exists, and you should use them rather than asking a model to grade what a check can decide. Where no right answer exists, you are left with evaluators that encode your domain rules and judges measured against human agreement, and saying so out loud is the difference between a measurement and a performance. Which is also why recorded runs are worth keeping as more than error logs. Search for the ones that were slow and left the user unhappy, notice a pattern of the same tool misused, save those cases, and the next release that brings the pattern back gets stopped at the door. The result tells you it worked. The road tells you whether to let it work again.