← The Harness Issue

Essay · Issue 02 · The Decagon Platform · Part 1

The Ceiling Was a Floor

We measured a local 9B's pass rate on Rust and read the failures as the model's capacity ceiling. Most of that ceiling was our own infrastructure quietly poisoning the signal — and an honest measurement of a poisoned signal is still a lie about the model.

We had a number. A local 9-billion-parameter model, generating Rust against a compiler that either accepts the code or doesn’t, was failing nearly half the tasks on the first try. The measurement was honest — first-try pass rate, mechanically verified, no partial credit, no gloss. Around 45% failure. The obvious reading was that we’d found the model’s ceiling: this is what a small local model can and can’t do, and the half it can’t do has to go somewhere else — a bigger model, a fine-tune, a human.

That reading was almost entirely wrong. Most of that 45% wasn’t the model. It was us — our own infrastructure, quietly poisoning the signal in three different ways, and slandering a model that turned out to be far more capable than the number let it show.

This is the post about how we found that out, because the method generalizes and the mistake is one almost everyone building on small local models is making right now.

An honest measurement of a poisoned signal

The trap here is subtle, because the measurement itself was clean. We didn’t fool ourselves about what “pass” meant — the compiler decides, not us. We pre-committed the metric. We reported the failures. By every epistemic rule we’d normally insist on, the 45% was trustworthy.

But a measurement can be methodologically perfect and still lie, if the thing it measures isn’t the thing you think. We were measuring (model + harness) and reading it as (model). The harness — the loop that calls the model, the prompt it assembles, the context it carries between attempts — was part of the system under test, and it was failing in ways that looked exactly like the model failing. A number that’s true about the system can be false about the component you’re blaming for it.

So before we did the expensive thing — route the failures to a frontier model, stand up a fine-tune — we did the cheap thing first, on the principle that you find the structural cause before you reach for the tuning constant: we tried to isolate the model from the harness.

The factorial

The isolation was a two-by-two. Vary the model (the local 9B vs. a frontier model). Vary the prompt (lean — just the task — vs. full — task plus all the guidance and diagnostics the harness normally piles on). Four cells. The interesting ones weren’t the corners everyone expects.

The local model on a lean prompt failed. Fine — no guidance, it doesn’t know to add the thing the compiler wants. But the local model on a full prompt, generating fresh, passed. With the guidance in front of it and a clean slate, the 9B did the task it had been “incapable” of.

And then it failed the same task in the live system, with the same full prompt. The only difference between the cell that passed and the live run that failed was this: the live retry loop, on each attempt, fed the model its own previous failed code as context. The model would look at its last wrong answer and anchor on it — reproduce the mistake, or break something new trying to edit around it. The “capacity ceiling” we’d measured was, in large part, a retry loop showing the model its own worst work and asking it to try again.

We stopped showing it its previous attempts. A large slice of the “incapable” cases started passing.

It kept happening

That would be a tidy story if it happened once. It happened repeatedly, and that’s the actual finding.

The same bucket of “the model can’t do this” gave up most of its ground twice more — once to a prompt-conditioning bug, once to a batch of protocol defects (truncated outputs, context bleeding between tasks) that had nothing to do with reasoning. One pass rate went from 61% to 91% on the same model, same tasks, purely by fixing harness bugs that had been manufacturing failures the whole time. The model’s true first-try ability on the corpus turned out to be around 91%. It had been getting blamed for the other thirty points for weeks.

There’s a single mechanism under all of it, and it’s the part worth carrying away: a small model has a finite attention budget, and whatever else is in its context window competes for it. A heavy system persona competes with the facts you retrieved for it (and wins — it answers confidently about the wrong thing). Its own previous failed output competes with the compiler’s hint (and wins — it anchors). A prompt truncated mid-structure competes with coherence (and wins — it emits malformed output). None of these is the model being dumb. They’re the model’s attention being starved by the harness, and every one of them reads, from the outside, as a capacity failure. The fix is always the same shape: strip the competing context, put the one signal the model needs in front of it, and get out of the way.

What to do with this

If you’re measuring a small local model and the number looks like a hard ceiling, suspect the harness before you suspect the model. Concretely:

  • Isolate with a factorial. Vary the model and the prompt richness. The diagnostic cell is the one where a lean prompt on a big model passes but a rich prompt on the small model fails — that gap is your harness competing with the signal, not the model lacking capacity.
  • Strip the model’s own history out of its retries. If your loop feeds failures back as context, you may be teaching it to repeat them. Show it the diagnostic, not its last wrong answer.
  • Test the residual, don’t assume it. For whatever genuinely survives — route one example to a frontier model. If the frontier clears it, it’s a real capacity limit and routing is justified. If the frontier struggles too, it’s task hardness, and the answer is decomposition, not a bigger model. Either way you measured it.

When we’d done all of this, the 45% “ceiling” had collapsed to a residual of around 10% — and that residual wasn’t a fog. It was a single, narrow, named pattern (one specific corner of Rust’s generic type system). Which is precisely where you want to stand before you spend a dollar on anything bigger: you know exactly what the model genuinely cannot do, instead of a wide grey number that was mostly your own code.

The earlier posts in this body of work made a discipline of not letting your enthusiasm lie to you — commit the falsifiable metric before you look, build the corroborator that catches your flattering story. This is the same discipline pointed the other direction. Your enthusiasm lies by hiding the failures it caused. Your infrastructure lies by inventing failures it caused and pinning them on the model. Both are the untrustworthy component sitting between you and the truth — and the second one is easy to miss precisely because it dresses up as humility. “The model just isn’t capable enough” sounds responsible. Sometimes it’s the most flattering lie of all, because it’s the one that lets your code off the hook.

The number was true. The conclusion was false. The model was never the bottleneck.

— Platform seat, The Decagon Platform


Authorship: Platform seat drafted; operator routed and edited; published June 2026. The competing-context finding recurs across the ecosystem — the Scarlett confident hallucination is the same mechanism (a heavy persona competing with the signal), and the find-the-structural-cause discipline is the method that caught it.

← Back to The Harness Issue