Telling Agents to Test Better Makes Them Worse

In a 160-run evaluation, every named testing technique lost to saying nothing at all. The exception was five bullets written in two minutes.

Telling Agents to Test Better Makes Them Worse

The most useful testing advice I read this year fits in five bullets, and in a 160-run evaluation it beat a skill pack with 250k GitHub stars. On the way there it made TDD, QuickCheck, Lean 4 and a roomful of formal methods look worse than saying nothing at all.

Dan Luu ran the experiment that sits underneath every argument about how agents should test. Hand an agent the Zstd compression format and have it implement the thing in Rust. Then vary only the testing instruction: one batch gets "use test-driven development", another "use Lean 4", another "use QuickCheck", one batch gets "make no mistakes", and a control group gets nothing. Codex on GPT-5.6 Sol, medium and xhigh effort, 80 runs each, 26 conditions plus four skills, graded by hidden tests. The IMAP RFC at 40 runs per condition gave materially the same picture.

The control group finished above average. Hold that against your prompting habits: the instruction most of us reach for first is among the ones that drag results down.

Silence scored above average

Default, the no-instruction condition, landed well above the field average, and the joke condition "make no mistakes" was indistinguishable from it. A no-op ties the field, which tells you most of the real instructions were actively harmful.

TDD is the one I keep coming back to. Luu predicted it would underperform, pre-registered at 55 percent confidence, and it did. Agents told to do TDD produced roughly twice as many tests and shifted into a test-code-test rhythm: 67 of 160 runs had a failing test on the board before any substantial implementation, against zero in Default. More tests, earlier tests, worse outcomes. They kept writing tests that miss the hard cases, like feeding four identical bitstreams into a feature whose whole failure mode is transposing four bitstreams.

Yossi Kreinin offered a mechanism: write the tests before the code and you know less about what will be hard, so you drift into black-box testing on machinery where white-box suspicion is the entire job. True for humans, unproven for agents, and Luu says as much.

Techniques worn as costume

The formal methods conditions are the funniest part of the writeup, depressingly. Agents given Verus mostly produced proofs like "given indices in bounds, the indices are in bounds", vacuous A-implies-A statements and arithmetic comfort food, while code that could actually be wrong went unproved. The four-stream jump table, a classic Zstd stumbling block, got tested at the same rate as Default (89 of 160 runs), but Verus agents were more likely to build the test out of four identical streams, which cannot catch a transposition. Alloy and differential testing posted the second and third worst correctness scores in the eval.

QuickCheck runs checked exactly one property 63 times out of 160. Fuzzing runs sprayed random bytes that all crashed into the same invalid-input rejection path. Differential agents did "the same thing twice and encoded the same bug in both versions", which is differential testing in name only.

My favorite data point: agents consistently flagged the reversal of bitstream order between encode and decode as risky. Correct. One medium-effort run even did an independent derivation, an audit and a targeted test. The test input was palindromic, so reversing the streams changed nothing and a broken implementation sailed through its own trap detector. Knowing where the bug lives and knowing how to catch it are different skills, and agents currently have the first one.

There is a hint the capability is latent rather than absent. In 10 of 160 fuzzing runs, agents generated structured random inputs instead of raw bytes, and half of those found real, non-trivial bugs. Ten runs is nothing, but it is ten more than zero: the models can do this when pushed.

The 250k-star skill lost to a five-bullet memo

Four skills got tested. The ECC Rust testing skill, from a collection with 250k stars and 38k forks, looked acceptable on the scoreboard until you read the fine print: the seven agents that never opened it and the nine that barely glanced at it all scored 100 percent, while the agents that actually followed it landed below average, dutifully red-green-ing their way into a pile of small meaningless tests. A skill that only works when ignored is a good luck charm, not a skill.

The official Hegel skill made runs 26 to 41 percent more expensive by loading a 34k-character tutorial plus a 45k Rust reference into context, more than 20k tokens, and correctness went sideways. The Trail of Bits property-testing skill told agents to add a dependency whose approval flow cannot happen in a single-turn autonomous run, so it never got installed; only 108 of 160 agents even opened the file.

Then Luu, a self-described luddite who prompts instead of using skills, spent two minutes writing his own. Five bullets. Think about where subtle bugs will live before implementing, and design checks where a wrong interpretation produces a different answer, with asymmetric boundary cases on both sides of the boundary. Re-derive risky results in a fresh context. Randomize toward interesting states instead of no-panic checks. It got the highest score in the eval, and he is careful: agents ignored the fresh-context bullet almost completely, so it won without working as designed. He calls it a first draft, not a product. A first draft that beats everything else in the field is still worth stealing from.

Why the floor is this low

Luu's theory is unflattering to the labs. The papers that trained agents to test taught them to write unit tests the way most programmers do, which is the opposite of what people who care about correctness converged on decades ago. RL environments are cheap to build for bounded optimization problems, so agents got genuinely good at those. Nobody built the environments for testing, so agents inherited the internet's median test suite.

What I changed in my own briefs

I stopped naming techniques in agent instructions. The technique's name carries nothing; the failure modes it guards against carry everything. Instead of "use property-based testing", the brief now says: here is where this component goes wrong, write checks where a wrong reading of the spec produces a different output, put boundary cases on both sides of every edge, and if you randomize, generate structured inputs that reach interesting states instead of bytes that bounce off the validation layer.

And I verify claims, because an agent will say it wrote a snapshot test, and you look and it is a unit test wearing the name. That is Jamie Brandon's anecdote, and what fixed it was not insistence: tests moved into a separate crate, with instructions in AGENTS.md to keep them there. Structure survives attention lapses. Instructions do not.

The five bullets are still a draft. The finding underneath is already load-bearing for me: an instruction transfers exactly as much as you understand about why it exists. That is why a 20k-token tutorial lost to five bullets, and why "write more tests" will keep making agent code worse until we stop saying it.

Sources