Skip to content

The Code Works. That's the Problem.

Published August 6, 2026
ai
software-engineering
code-quality
system-design
technical-debt
Shipped last month: could you explain it?

AI generated code is dangerous under two conditions at once, and only two. You cannot read it, and it has outlived the reason you built it fast.

Neither is a problem by itself. Code you cannot read is fine if it genuinely dies on schedule. Code that lives forever is fine if someone understands it. It is the overlap that hurts, and the overlap is where most of this ends up, because almost nothing gets deleted when it was supposed to.

That framing is worth more than another round of arguing about whether these tools are good. They are good. I use them every day and I am not giving them up. This post is about what you are holding afterwards: two tests you can actually run, and then the evidence, which is messier than either camp admits.


Test one: can you read what you shipped?

Pick something you shipped in the last month with heavy AI assistance. Not a toy. Something running. Then answer these without opening an assistant.

1
Why is it built this way?

Not what it does. Why this shape. If the only available answer is "that's what came out", you have an artifact rather than a decision, and you cannot defend it in review.

2
What happens when it fails?

Name the failure modes. What happens on a timeout, a duplicate request, a partial write, a dependency that is slow rather than down. If you cannot enumerate them you cannot tell whether the code handles them.

3
Which parts can you delete safely?

Point at code you are confident is unused. If every line feels load bearing, nothing is understood, because real systems always carry slack and you should be able to see it.

4
Could you rebuild it without the assistant?

Not identically. Could you get to something equivalent, knowing what you now know? This separates learning from luck.

5
What does it expose?

What is reachable without authentication, what lands in the logs, what ships to the client. Generated code is confidently generous here, and nothing will warn you.

Failing this test is not a moral problem. I fail it on things I have shipped. It is a status check: it tells you the code is only safe while it stays disposable, which puts all the weight on the second test.


Test two: was it allowed to survive?

There is a version of one-shotting that is entirely correct. A prototype to find out whether an idea is worth pursuing. An internal tool three people use once a week. A script that runs and gets deleted. Being precious about craftsmanship there is just slow, and slow is its own kind of failure.

Notice what those have in common. They are supposed to die.

The prototype gets thrown away once you have learned the thing. The internal tool gets replaced when it stops being enough. The script gets deleted. That is the deal that made the shortcut reasonable in the first place.

They rarely die on schedule, and the reason is the uncomfortable part: it works. It demos well. Somebody sees it. Now the prototype is in front of a customer and the internal tool has forty users and real data in it. Nobody sat in a meeting and decided to promote it to production. It quietly stopped being temporary while nobody was looking.

So put the decision back where it belongs. For anything you built fast, write down the answer to one question before it ships:

💡

What has to be true for this to be deleted, and who is watching for it?

A date. A condition ("when we know whether users want this"). A named owner. If you cannot answer, it is not a prototype, it is production with a prototype's engineering budget, and it should be built accordingly or not built yet.

That single line converts an invisible liability into a decision someone made. Which matters, because the two failures compound in a specific way.


Why the overlap is worse than ordinary technical debt

The hardest problem in this industry has always been the person who built it leaving. A new engineer inherits a codebase they have never seen, with no context, because half the reasoning lived in someone's head and walked out the door with them. They are frightened to touch anything, so they build around the old code instead of fixing it, and every team ends up with the file nobody will open.

Code nobody read is that problem on day one. Worse, actually, because when an engineer leaves, at least somebody understood it once. Here nobody ever did. You have shipped a legacy codebase with no author to ask.

This is also why calling it technical debt lets it off too easily.

✕ The Myth

Shipping code you do not understand is just technical debt, and every team carries some.

✓ The Reality

Debt is a decision. You understood the trade-off, chose speed deliberately, and can repay it because you know exactly what you borrowed. This is a liability you do not know you are carrying, at an interest rate you cannot see, with no record of the loan.

And the fuse is always the same thing: the first requirement that was not in the original prompt. The first real traffic. The first dependency update. The first security probe. The first time somebody asks for a change, you open the file, and you cannot tell which part is load bearing.

That security one is not hypothetical. When I pulled apart an AI-assisted credential sweep against my own server, every single path the sweep asked for was a mistake a one-shotted app makes by default: secrets sitting at a public path, config served rather than gated, nobody watching the logs. A model will happily generate an application with all of those holes and never mention one, because you did not ask.


What the evidence actually says

The honest summary is that the speed question is unsettled and the quality question is not.

On speed, the two best controlled trials disagree, and it is worth knowing that rather than picking the one that suits you:

21%Faster, Google randomised trial
19%Slower, METR randomised trial
74%Agent PRs merged unchanged

Google's trial with 96 engineers found them roughly 21% faster. METR's trial with experienced open source developers found them 19% slower, and the detail that should stay with you is that the developers themselves believed they had been faster. Perceived speed and measured speed came apart. METR has since published an update on that work.

On what gets left behind, there is much less argument. Veracode tested more than 100 models across 80 coding tasks and found 45% of the generated code shipped with a vulnerability from the OWASP Top Ten.

Then the number that reframes the whole debate. A 2026 study of 9,427 agentic pull requests found 74.1% merged with no changes at all. Not reviewed and approved. Merged unmodified.

That is the problem in one figure. If three quarters of machine-written changes enter the codebase without a human altering a line, then reading is not a step anyone is performing. And reading is the part you are being paid for.

ℹ️

The most on-thesis evidence is not about bugs at all. GitClear's 2026 maintainability research, covering 623 million real-world code changes from 2023 to 2026, found the code is not getting more broken. It is getting harder to live with.

Block duplication is up 81% since 2023, the highest on record. Copy-pasted code rose from 9.4% of new code in 2022 to 15.7% in the first half of 2026. Properly refactored code collapsed from 21% to 3.8%.

That last one is the tell. Refactoring is the activity that turns working code into understandable code, and it is the thing that has nearly stopped.


Knowing a stack and knowing systems

If reading is the job, it helps to be precise about what reading requires, because it is three different kinds of knowledge doing three different jobs:

What you needWhat it lets you catch
systems knowledge

Code that works correctly and falls over at scale. Where it queues, where it retries, whether the retries make things worse, what fails only because something else failed first.

stack knowledge

Code that is technically valid but fights the framework. The query your ORM actually emits, how your runtime handles concurrency, when your framework renders.

security knowledge

Code that is fully functional and quietly exposes something. What is reachable, what is stored, what is logged, what is returned in an error.

None of that is prompting. All of it is engineering.

A conversation with a senior engineer at Uber sharpened this for me. I asked what they look for in a candidate, and he said they do not care much which stack you know, because anyone can learn a language. They look for people who understand systems and can scale them. That is one engineer's view in one conversation rather than any company's stated policy, but the distinction underneath it is the most useful one here.

Knowing a stack is knowing that your ORM generates this query, that your runtime handles concurrency that way, that your framework renders at this moment. Knowing systems is knowing what happens when the thing you built meets ten thousand people at once.

The stack is where you build the intuition. The intuition is the part that transfers. That is how both halves of his answer are true at the same time: he is not saying stack knowledge is worthless, he is saying it is not the currency. Deep knowledge of one stack is evidence you can think in systems. Shallow familiarity with ten is evidence of nothing.


Code got cheap. Architecture did not.

This is the part I find genuinely clarifying, because it is arithmetic rather than optimism.

AI made code cheap. Dramatically cheap. It did not make architecture cheap. You can generate a function in seconds. You cannot regenerate the decision to shard your database that way. You cannot undraw a service boundary you got wrong eighteen months ago. You cannot walk back a data model half the company now depends on.

Code became reversible in a way it never was before. Architecture was never reversible and still isn't. When the cost of one input collapses and the cost of another does not move, the relative value of the expensive one rises.

System design is also where these models are weakest, for a reason worth stating precisely. They can produce a plausible architecture, having read every architecture ever published. What they cannot do is trade off against constraints they have never seen: your traffic shape, your team size, who on that team can maintain what you are proposing, your budget, your compliance requirements, the three year old service nobody wants to touch, and the fact that you are the one carrying the pager.

There are no correct answers in system design, only appropriate ones, and appropriate is a function of a situation the model has never been in.

The same logic explains where the leverage is going outside pure engineering. Lightcast analysed 1.3 billion job postings and found more than half the roles now asking for AI skills sit outside software entirely. The premium is not going to people who know AI. It is going to people who know AI and a field. A model knows how to write a payment integration, but not the settlement rule your industry actually operates under. It knows how to build a form, but not which of those fields your regulator forbids you from storing. It has read everything written about your domain and has never once sat in the meeting where somebody explained why the obvious solution does not work here.


So, is it a time bomb?

Only under those two conditions together, and you now have a test for each.

The fix is not to stop using these tools. I am not going to, and neither should you. The fix is to stay the person who can read what came out, and to be honest about which things were allowed to survive their own expiry date.

The code got cheap. The architecture did not. And the judgment about which is which was never for sale in the first place.