The grader is the system under test
A coding agent finishes a change and reports: all tests pass. It wrote the change, chose what to test, ran the tests and wrote the report. Each step is useful. None of them is independent of the agent's own idea of what "done" means.
In evaluation terms, that is a model grading its own output. You would not accept a benchmark score where the model wrote the test cases after seeing its answers, and a passing suite the agent wrote for its own change has the same problem. Public coding benchmarks avoid it by design: SWE-bench grades a patch with tests taken from the real fix, which the model does not see. Your own workflow needs the same separation, at a smaller scale.
A worked example: the agent's tests and the spec's tests
The spec says: truncate(text, limit) returns text no longer than limit characters, and marks a cut with .... The agent writes a fix and two tests. Someone else writes two tests from the spec without reading the fix.
def truncate(text: str, limit: int) -> str:
"""The agent's change: cut text to at most `limit` characters, ending in '...'."""
if len(text) <= limit:
return text
return text[:limit] + "..."
# Tests the agent wrote alongside its change.
agent_tests = {
"short text is unchanged": lambda: truncate("hello", 10) == "hello",
"long text keeps its start": lambda: truncate("hello world", 5).startswith("hello"),
}
# Tests written from the spec by someone who did not write the change.
spec_tests = {
"never longer than the limit": lambda: len(truncate("hello world", 5)) <= 5,
"marks a cut with '...'": lambda: truncate("hello world", 5).endswith("..."),
}
for suite, tests in [("agent", agent_tests), ("spec", spec_tests)]:
for name, check in tests.items():
print(f"{suite:5} {name:28} {'pass' if check() else 'FAIL'}")Run on Python 3.12, it prints:
agent short text is unchanged pass
agent long text keeps its start pass
spec never longer than the limit FAIL
spec marks a cut with '...' passThe agent's docstring even states the requirement its code breaks: "hello world" with a limit of 5 comes back as "hello...", eight characters. Its tests checked what it thought to check, and the length rule was not among them. The spec tests work like a held-out set: written before, and apart from, the thing they grade.
Why passing tests are weak evidence
Three separate facts explain the gap.
The tests measure what someone thought to assert. A suite passes for any behavior its assertions do not encode. When the same agent writes the change and the assertions, the blind spots line up. Test gaming, measured on small models shows what happens when the agent may also edit the tests.
A model-written report is not a record. The book's Chapter 20 asked small local models to write an end-of-day report from structured records, 180 times. Only 2 of the 180 reports were complete and honest, and one of those two invented an event that had not happened. Those were small local models on a different task, not a measurement of any coding agent. The lesson transfers anyway: rely on records, such as the diff, the test output and the measurements, not on the agent's summary.
One pass is one trial. Chapter 20 applies the Wilson interval to a single passing run: one success out of one is consistent with a true pass rate as low as about 21%. A coding agent earns trust across many runs, each checked independently.
In automation, gate on evidence the agent cannot write for itself: claude -p exits with code 0 on success and non-zero on failure, so a CI job can gate on the exit status and on your own test command rather than on anything the agent says.
Prithvi Rajasekaran's engineering note on harness design at Anthropic describes long-running application harnesses that separate planning, generation and evaluation (Anthropic, "Harness design for long-running applications," https://www.anthropic.com/engineering/harness-design-long-running-apps). The reported comparisons are specific to that setup, not a measurement of this site. The shape applies: an evaluation step is worth most when it can see what the generator cannot check for itself.

The same gap in a rendered page
Interface changes add a layer that unit tests rarely reach: what the page looks like after it renders. Some of that can become an assertion. Width and height come first, but they are not enough:
from dataclasses import dataclass
@dataclass
class Box:
x: float
y: float
width: float
height: float
def size_ok(badge: Box, expected: int = 40) -> bool:
return badge.width == expected and badge.height == expected
def overlaps(a: Box, b: Box, gap: float = 0.0) -> bool:
"""True when the rectangles overlap or sit closer than gap pixels."""
return not (a.x + a.width + gap <= b.x or b.x + b.width + gap <= a.x
or a.y + a.height + gap <= b.y or b.y + b.height + gap <= a.y)
# Authored rectangles for one card at 320 px; not a browser measurement.
badge = Box(x=264, y=16, width=40, height=40)
title_ok = Box(x=24, y=16, width=228, height=48)
title_long = Box(x=24, y=16, width=256, height=72)
assert size_ok(badge)
assert not size_ok(Box(x=264, y=16, width=39, height=40))
assert not overlaps(badge, title_ok, gap=8)
assert overlaps(badge, title_long, gap=8)
print("Size check passes for both titles; only the overlap check catches the long title")The size check passes in both layouts. Only the overlap check, which compares the badge with its neighbor, catches the long title running under it. In a real test the rectangles come from the browser: tools such as Playwright return an element's bounding box after the page renders, at a viewport width you set. Measure each element and its neighbors, in every state, at the widths where the layout changes.
Assertions still stop short of acceptance. A gap of 8 pixels passes the check; whether 8 pixels reads as comfortable is a judgment, and the threshold itself was a choice someone made.
Lesson-number badges on this site's course cards were squeezed by long titles. An agent moved each badge into a fixed grid column as a 40-pixel circle, then reported 113 test files and 696 tests passing, plus 42 badges measured by headless Chrome at 320, 375 and 1280 pixels, each 40 by 40 with clearance flagged as passing. The measurements came from a local development server, not production.
Then it marked the work held, not done, and asked the operator whether the circles and spacing looked right on phone and desktop, including card 10. Its record says the instrument proves dimensions and behavior and does not grant aesthetic acceptance. That is the behavior to copy: strong mechanical evidence, plus a named list of what the evidence did not cover.

A check that saves screenshots proves the screenshots exist. It does not show that anyone looked at them. Record the human verdict as its own field; an empty field means the change is not accepted.
A verification protocol for agent changes
Have a person or a separate process write tests from the requirement before reading the agent's code. Run them next to the agent's own tests and report the two suites separately.
Run your own test command in CI and gate on its exit status. Treat the agent's summary as a pointer to evidence, never as evidence.
Use the boundary values, the longest real input, the highest item number, and for interfaces the expanded and collapsed states, keyboard focus and larger text settings.
Say whether results came from a development server or a deployed build, and pin the commit they describe.
Keep the person's answer next to the measurements, not merged into the same pass field. Until it is recorded, the change is held.
Check the decision
Why this matters in a lab
Coding agents write a growing share of research and product code, and teams evaluate them the way the code gets graded: by tests. When the agent writes both the change and the assertions, a pass tells you less than it seems. A team will expect you to know where that gap is and to close it with evidence the agent cannot produce for itself: held-out tests, exit codes, rendered measurements and a named human verdict where judgment is required. It is the same skill as building an eval that a model cannot game, which is central to AI agents and applied AI engineer roles.
An interviewer might ask, "Your coding agent says all tests pass. What do you check before merging?" A strong answer asks who wrote the assertions, which inputs and states they cover, where the measurements came from, and who has looked at the result.
What would prove this wrong
If the agent's tests are written independently, by a person or a separate process working from the spec, they are stronger evidence than tests it wrote for its own change. If a browser check compares every relevant pair of rectangles in every state and width that matters, the overlap part of the gap closes, and what remains is whether the chosen clearance matches what readers find comfortable. The practical falsifier for the badge case is simple: load the page at 320 pixels with card 10 expanded and see whether the badge crowds the title.
See why a model-written report is weak evidence, how one passing run bounds a pass rate, and how to decide what is ready to operate.

