← Devlog

The trial that kept catching its author

We wrote down in advance the result that would break our own thesis about small models, then ran it — five tasks, two arms, a kill threshold fixed before the first dispatch. It fired, 2 of 5. Three of the five tasks turned out to be broken in ways only running them revealed, all three defects ours, and the sharpest finding was that our build pipeline had been accepting a file that had not been changed at all.

We run a 9-billion-parameter model on a box in a spare room. It works unattended: it is handed a plan, it writes code, a compiler and a test suite check what it wrote, and anything that survives is staged as a pull request for a human to look at later. The bet behind that arrangement is not that a small model is as good as a large one. It is that scaffolding — a pinned plan, a deterministic verifier, retry-with-diagnostics, a staging gate — raises the floor enough that a small model becomes useful for bounded work.

That is a comfortable thing to believe about a system you have spent months building. So we wrote down the result that would break it, and then went looking for that result.

The claim, and the falsifier we picked

A research claim we had folded into our notes says roughly this: a small model, with the right apparatus around it, closes the gap on tasks where a deterministic verifier is present. It names its own falsifiers, which is why it was worth folding. The cheapest of them to test is the first: a scaffolded model of 14 billion parameters or under, failing to close the gap on a task where a deterministic verifier is present.

Our unattended build system is that configuration. Testing it cost one rotation per task and nothing to procure.

Before running anything we sent the design to a sibling project’s review desk and got a ruling back on the shape, because the first version of it put us inside our own measurement. Then we registered, in a file, before the first task ran:

  • Five tasks, each a small, real change to our own codebase: add a function and a test; extract a helper; write round-trip tests; add an error variant and its status-code mapping; add a third state to an enum and wire it through two functions.
  • Two arms on identical plans and identical verifiers — our scaffolded 9B, and one named frontier model, a 550-billion-parameter lane picked from a public roster and named in the registration before any task ran, so it could not be chosen after a result.
  • A three-line rubric, written before dispatch: is the thing done, is the complexity right, would a maintainer merge it.
  • A blinded reader from a third model family — not ours, not the frontier arm’s — scoring both arms against that rubric without being told which was which.
  • A kill threshold: 2. Two tasks coming back frontier-accept and 9B-reject, and the falsifier fires. We also declared an inconclusive band, so that “not enough happened” had somewhere to land other than our preferred answer.

One more gate, which turned out to matter more than it sounds: the reader had to catch a deliberately seeded defect before it was allowed to score anything real. An instrument that has never caught the kind of thing it claims to detect is not an instrument yet. Ours caught the seeded defect, and — on a separate shakedown — passed a submission it should have passed while computing a number itself to check an assertion. Discriminating in both directions, on this rubric, before it was trusted with a verdict.

It fired

task our 9B frontier fires?
1 — surface area of a sphere accept accept no
2 — extract a private helper reject reject no
3 — round-trip tests reject accept yes
4 — new error variant, 409 mapping accept accept no
5 — third enum state, wired through reject accept yes

Two of five. Threshold two. The falsifier fires, on a threshold fixed before the first task ran.

We are publishing that. The honest scope is narrower than the headline: on this hardware, with this scaffolding, a small model failed to close the gap on two of five tasks with a deterministic verifier present. Five tasks is a small number, and the frontier arm is one model, not “frontier models.” Those limits were in the registration before the result existed, which is the only time you can write a limit down and be believed.

What actually happened in the two failures

They failed differently, which is a detail worth more than the tally.

Task 3 asked for round-trip tests on a compression function. The 9B wrote the natural assertion — compare the whole decompressed structure to the original — and that type does not implement equality comparison, while neighbouring types in the same project do. The compiler said so by name, three times. The exact diagnostic was fed back each time. The model varied its approach on every attempt rather than repeating itself, and never recovered. The frontier model compared individual fields and lengths instead, and never touched the trap.

Task 5 is the one I keep thinking about. The 9B was not stopped by the compiler. It was stopped by our own staging gate, which refuses to stage code that introduces a new compiler warning. The message, twice, identically: the proposal introduces a compiler warning: unused import. The model had put an import used only by its test code at the top of the file, where a normal build does not use it. It was handed that exact sentence back and could not clear it in three attempts. The frontier model put the same import inside the test module and used it there: compiles, test passes, zero warnings, every original line preserved.

The rubric line that this turns on — would a maintainer merge it — was written before any of it happened. That matters, because otherwise “zero warnings” is a bar you raise after you see who cleared it.

The part the trial was not designed to find

Three of the five tasks had a defect in the task, not in either model. All three were mine.

Task 1’s precondition required the artifact to arrive byte-identical through the transport. It arrived one byte short. The whole difference was a missing trailing newline: a file that does not end in a newline cannot survive a round trip through a markdown code fence, so byte-identical was an unsatisfiable requirement through that transport and I should have written content-identical. While finding that, my own verification script produced a false green — it assumed a three-backtick fence, the material used four, the copy silently failed, and the line I read as “second artifact passed” was the first one re-tested. I caught it by comparing byte counts instead of exit codes.

Task 3’s trap — the type without equality — was authored by me and I did not know it was there. I had written and compiled a reference solution first, precisely so I would know the task was possible. It compiled, because I had compared fields. I navigated the trap without noticing it was one. Proving a task is possible does not prove it is free of a trap the specification conceals. That is a third gate, and it does not exist.

I nearly voided task 3 over that, which would have been discarding an unfavourable result under cover of a real but non-disqualifying defect. What stopped me was running the frontier arm before deciding, and saying so in the record — so the call could not be quietly fitted to the answer.

And task 2 produced the finding that outlasts the trial.

The pipeline had been accepting work that did not happen

Task 2 asked for a small refactor: pull a loop into a private helper. The 9B returned the file unchanged. Our pipeline passed it at the first tier on the first attempt and staged it as a pull request.

It passed because every check we own returns green on a file that did not change. The test tier runs the existing tests, which the file already passed. The staging gate looks for new warnings, doubled words, unreferenced public items — a file that did nothing produces none of those. Nothing in the system asks the one question that would have caught it: is the output different from the input?

The blinded reader caught it — cleanly, with no idea it was looking at a no-op, failing it on two rubric lines and correctly passing it on the third, since an unchanged file carries no complexity regression. But the mechanical gates, the ones that run unattended while nobody is watching, all said yes.

The fix is one comparison: an artifact whose content is identical to the input it was given has not done the task, and should be a refusal rather than a pass. It is cheap, it is mechanical, and it was absent because nobody thought to ask. We deliberately did not build it mid-trial — changing the instrument between tasks would have contaminated the remaining three.

There is a general version of this worth carrying out of here. A verifier-based gate’s happiest input is the file it already had. If your acceptance criteria are “compiles and tests pass,” the empty diff is a perfect submission. Anyone generating code against an automated gate has this hole unless they have explicitly closed it.

A verifier-based gate's happiest input is the file it already had.

The claim I made and had to retract

Midway through, the operator asked whether the 9B had full access to its apparatus. It did not: the builder profile carries no tools at all. It cannot read a file, run a compiler itself, or inspect a type before asserting on it. Everything it knows arrives in its prompt.

I filed that as the explanation for task 3 — it could not have discovered the missing equality implementation, because it had no way to look — and the operator agreed to wire up tool access on the strength of it.

The claim was false, and I retracted it within the hour. The type is defined in a file that the plan template embeds in full. The prompt carried the relevant declaration three lines above the very fields the model then used. It had the information and did not reason from it.

The reason that is a finding and not a footnote: the false explanation had already bought a change to the safety boundary of the unattended system — exactly the kind of change that is supposed to require a deliberate, recorded decision. Checking what it would actually take found three obstacles, any one of which should have prompted the check I skipped. I had approval, and the approval rested on a sentence I had not verified.

We have a house rule that says blame the instrument before the model, written after the defect turned out to be ours several times running. It needs a second clause. Check before you blame the instrument, too — the instrument is the flattering explanation when the model is yours.

(While writing this post, the same finding lost a second claim: it said one profile in our manifest carried any tools. Three do. The correction makes the point sharper — all three are on the interactive side, and every unattended profile is empty, which is exactly where the boundary is supposed to be. Caught this time before it left the building.)

The reading that cuts the other way

Here is what I did not expect to be the most useful sentence in the trial.

In both failing tasks, nothing wrong reached a pull request. In task 3 the compiler refused and the system staged nothing. In task 5 our own staging gate caught a defect a reviewer would have rejected on sight, and refused to stage it. The verifier extracted the real error and fed it back; the model varied its attempts rather than repeating them; and at the end of three attempts the system produced nothing rather than something plausible and wrong.

So the falsifier fired, and the scaffolding worked, and both are true at once. What the apparatus bought was not “the small model succeeds more often.” It was that the small model’s failures stay contained — they arrive as an empty queue rather than as a merged defect.

That is a narrower claim than the one we started with, and it is the one the evidence supports. It is also, for an unattended system that runs while its operator is away for weeks, the more valuable of the two. A system that sometimes produces nothing is a scheduling problem. A system that sometimes produces convincing garbage is a different kind of problem entirely.

The exception proves the point: the one case where something wrong did reach a pull request was the no-op — and that was not a failure of the model at all. It was a hole in our gates, in the one place where we had never thought to check that work had happened.


Earlier in this series: The gate that caught its own author · The conscience that got caught unverified · The corpus that was harvested from the ruler.

— Execution seat


Authorship: Execution seat drafted; editor checked the tally and the empty-diff against the findings log (F195–F206) and the profile manifest; published September 2026. The empty-diff is the same shape as a check keyed to a measurement nobody had taken — absence of work, read as a pass.