Your Coding Agent Has No Reason to Write Good Code

Coding models are trained on a pass/fail test signal. Maintainability isn't graded, so it isn't learned — and no harness you build can fix that.

TL;DR: The pitch of the moment is that if you engineer enough harness — better orchestration, more review bots, tighter sandboxes — you can delete code review and let agents run the factory unattended. I don’t think that works, and I don’t think it’s a skill issue. Coding models are trained against a reward that fires on one question: did the tests go from red to green without breaking anything else. Nothing in that signal grades design. A test verdict costs seconds; bad architecture bills you in months, which means there’s no fast oracle for maintainability, which means it can’t be rewarded during training, which means it was never learned. Harness engineering raises the floor. It does not move the ceiling, because the ceiling was set during training.

The pitch you’ve been hearing all year

The argument runs like this, and it’s seductive because most of it is true.

You are the bottleneck. The models are good enough. Code is effectively free now. So stop hand-crafting software and start running a factory: specs go in one side, tested and deployed software comes out the other, and the humans move up a level to writing specifications and curating test scenarios.

The most committed version of this shipped in February 2026, when StrongDM’s AI team published a charter for what they call a software factory. Two rules, stated plainly: code must not be written by humans, and code must not be reviewed by humans. Agents write it, agents test it, agents ship it. The lights stay off because nobody’s on the floor.

I want to be fair to that team, because they are not naive. They ran directly into the obvious failure — that agents grading their own work will cheat, hardcoding the value a test checks for — and they built serious infrastructure to close it, including behavioral clones of every third-party service their software touches so the tests run against something with teeth. That is not a blog post. That’s real engineering.

But the pitch that’s circulating downstream of it has been flattened into something much dumber: that the last human step, the one where somebody reads the code, is a legacy ritual you can automate away with enough linters and a prompt containing the word “adversarial.” And I’ve watched enough agent output go by to be confident that’s wrong in a specific, mechanical way that no amount of tooling fixes.

The receipts are in, and they’re not good

We now have data instead of vibes, and the data is uncomfortable for everyone selling velocity.

Faros AI published a study in April 2026 — 22,000 developers across more than 4,000 teams, two years of telemetry pulled from trackers, IDEs, static analysis, CI, version control, and incident management. Output went up, exactly as promised: task throughput per developer up 33.7%, epics completed per developer up 66%. So did everything else:

  • Bugs per developer up 54%
  • Incidents-to-PR ratio up 242.7%
  • Median time in review up 441.5%
  • Pull requests merged with no review at all up 31.3%
  • Code churn up 861%

Read those last two together, because that’s the whole story in two lines. Review time exploded, so review got skipped. Not because anyone decided to skip it — because a review queue that grows faster than the humans reading it has exactly one release valve, and that valve is the merge button.

This is correlation, and I’ll say so plainly. It doesn’t prove the agents caused the incidents. But it matches what I see week to week, and it matches the shape of the failures I’ve catalogued from my own sessions in the agent bugs I catch every week. Directionally, I believe it.

“You’re holding it wrong” — you’re not

The standard response to all of this is that you’re doing it wrong. Not enough context engineering. Not enough tokens. You’re still reading the diffs like it’s 2023, grandpa. Let go.

I want to be careful here, because I’m not the guy who tried agents for a weekend and wrote a thinkpiece. I’ve committed 4,154 times in six months with agents doing nearly all the typing, on a product that went zero-to-production in sixty days and has customers on it. I like these tools. I’m not going back.

So this isn’t a warning from the sidelines. It’s the opposite: the more time I spend inside the loop, the more convinced I am that the thing people are trying to prompt their way around isn’t in the prompt at all. It’s in the weights. And you cannot fix a training problem with a harness.

What actually gets graded

To see why, you have to look at what “make the model better at coding” means concretely.

The loop is roughly: generate a bunch of agent traces attempting a coding task, score each trace against a verifier, then update the weights so high-scoring traces get more likely and low-scoring ones get less likely. Repeat several million times. That’s reinforcement learning with a verifiable reward, and it’s the machinery behind essentially every serious coding model shipping today.

Everything hinges on the verifier. So what does it check?

Take the canonical setup, the one most of this work descends from — SWE-bench and the training harnesses built on top of it. A task is scraped out of a real repository — an actual bug, an actual fix. The model gets the repo checked out to the commit right before the fix landed, plus the issue text. It writes a patch. Then the grader throws away any edits the model made to test files (yes, that’s necessary), applies the benchmark’s own test patch, and runs the suite against two lists:

  • FAIL_TO_PASS — the tests that were broken. Do they pass now?
  • PASS_TO_PASS — the tests that already worked. Are they still fine?

Both green, reward is 1. Anything else, reward is 0. That’s it. That’s the entire signal, and the research literature is direct about the consequence: execution-based feedback cannot distinguish between trajectories that yield the same outcome. Two patches, one clean and one a disaster, both turning the suite green, are literally the same number to the optimizer.

So ask what the model learns from millions of iterations of that.

It learns to make tests pass. It learns it extremely well — that’s why these tools work at all. What it never learns, because it is never once asked, is whether the codebase is better or worse for what it just did. There is no penalty for a fix that works by wrapping the call site in a try/rescue and swallowing the error. There’s no penalty for adding the eleventh special case to a function that needed refactoring at the third. There’s no penalty for solving the ticket in a way that makes the next ticket harder.

There is no penalty for eroding maintainability. Not a small one. Zero.

The asymmetry that makes this hard to fix

The obvious response is: fine, add quality to the reward. People are trying. It’s harder than it sounds, and the reason is structural, which means it won’t age out with the next model release.

Running a test suite gives you a clean verdict in seconds. That speed is the entire reason RL can afford millions of iterations — the oracle is cheap, so you can consult it constantly.

Now price the oracle for architecture. The cost of a bad design decision doesn’t materialize in seconds. It shows up the first time somebody opens that file for a one-line change and discovers the one line lives in eleven places. It shows up in the review that takes three days because nobody can hold the blast radius in their head. Eventually it shows up as the problem I laid out in the onboarding playbook for an agent-heavy codebase: a new person, or a new session, unable to form an accurate model of how the system fits together.

That bill arrives in weeks, months, sometimes years. Tests answer in seconds; architecture answers in quarters. You cannot put a quarters-long feedback loop inside a training loop that needs to run millions of times, and no clever engineering collapses that gap, because the gap is what maintainability means. Maintainability is defined by future change. It is unobservable in the present. That’s not a tooling limitation — it’s the definition.

Which lands us somewhere uncomfortable: the single property that determines whether your codebase survives contact with an agent for a year is the one property the training process structurally cannot grade.

Why more review bots raise the floor and not the ceiling

Here’s where the harness argument comes back, and it deserves a real answer.

More review agents do help. I run them. They catch the dumb stuff — the unused import, the missing nil check, the obvious injection, the test that asserts nothing. That’s genuine value and I’d keep them even if the rest of this post is wrong.

But look at what a review agent is. It’s the same class of model, running the same weights, asked to grade instead of generate. Its ability to recognize bad design is bounded by whatever design sense survived training — which is the exact thing we just established was never rewarded.

And that leads to the trap sitting under every “just add an AI reviewer” plan: a model that could reliably tell good code from bad would have written the good version in the first place. The generator and the judge are drinking from the same well. Stacking more judges gets you more coverage of the failures the model already recognizes. It does not get you a new capability neither model has.

So the floor comes up. The ceiling doesn’t move. And on a long-running codebase, the ceiling is what you’re actually betting.

The frontier is moving, slowly, and honestly

I want to be careful not to argue this is impossible. It isn’t. It’s unsolved, and the hype is running well ahead of the discipline — those are different claims.

The most serious attempt I’ve seen is Cognition’s FrontierCode, and it’s interesting precisely because it refuses the pass/fail frame. Instead of asking “did the tests go green,” it asks whether a maintainer would actually merge the patch. Tasks were built with open-source maintainers at 40-plus hours of input each, and the rubric grades regression safety, scope, cleanliness, test correctness, and maintainability as separate dimensions, each scored on its own, instead of collapsing everything into one bit. They report an 81% lower false-positive rate than the previous generation of benchmarks.

That is the right direction. It’s the first evaluation I’ve seen that takes seriously the idea that a patch can be correct and still be bad.

It’s also still a rubric applied by models and humans, with all the cost and subjectivity that implies, and it doesn’t escape the well problem above — it just puts more careful humans upstream of it. I’d call it real progress and I would not yet bet a production codebase on the models it produces. Both of those can be true.

The other honest position is: maybe a future model just gets this and the whole problem dissolves. Maybe. If you want to hold your codebase’s fate against that bet, that’s a choice you’re allowed to make. I’ve got systems in production this quarter.

What I actually do instead

None of this argues for using agents less. It argues for putting the human effort in the one place the training process left empty. Four things, all of which I run daily.

Front-load the alignment, don’t back-load the cleanup. The oldest trick in the trade still works and works better than ever: time spent agreeing on the approach before generation is worth many multiples of time spent untangling afterward. The generation step compressed hard; deciding what to build and how it should be shaped didn’t compress at all, and that step is now the highest-leverage hour in the week. A well-shaped change reviews fast. A sprawling one doesn’t review at all — see the 441% number.

Keep architecture human-owned, explicitly. The agent proposes the module boundary; a person decides it. This is the same principle behind never letting the agent be the only thing between a change and production, applied one level earlier — at the design decision instead of the deploy. Structural decisions are precisely the ones with a feedback loop too slow for the model to have ever learned from.

Write the constraints down where the agent reads them. Most of what a senior engineer knows about a codebase is unwritten, which means the agent doesn’t have it and can’t infer it. The fix is a file it reads every session — the CLAUDE.md entries that earned their place after 50 commits: the boundaries, the patterns this repo actually uses, the things that look reasonable and are forbidden here. It doesn’t give the model design taste. It gives it this codebase’s design decisions, already made, which is the part it was never going to derive.

Spend your reading budget asymmetrically. You cannot read everything at agent throughput, and pretending otherwise is how teams end up merging without review. So don’t distribute attention evenly — concentrate it where an error is expensive and irreversible, and let the mechanical stuff ride on tests and bots. Which is also why TDD holds up unusually well with agents: a test the agent has to satisfy is a constraint that survives the session, and it converts some of your review budget into something that runs automatically forever.

The step you can’t delete

The lights-off factory is a good story with one bad assumption inside it: that code review is a bottleneck to be automated rather than the only stage in the pipeline where anyone asks whether the system is getting better or worse.

Every other step has a fast, cheap, automatable verdict. Does it compile, do the tests pass, did it deploy, is it paging anyone. Review is the odd one out precisely because it’s slow and human — it’s where the quarters-long question gets asked in the present tense, by the one participant who’ll still be maintaining this thing next year.

Delete it and you don’t get a faster factory. You get the Faros numbers: more output, more incidents, more churn, and a codebase drifting toward the state where the only remaining option is the expensive one — throw it out and write it again by hand.

You can move fast. I do, and the receipts are public. You just can’t skip the one step that nobody trained the model to care about.