Why Do AI Projects Fail?
They fail for the same two reasons every software project has always failed. AI does not introduce a new failure mode — it changes the rate constants of the old ones, in the worst possible combination.
To answer why AI projects fail, we first have to answer why any project fails. There is a fundamental answer, and it has two parts. Neither is about tooling, methodology, or talent. Both are structural, and both were true long before a model wrote a line of code.
Mechism one: every handoff is a lossy channel
A project is a chain of transmissions. Intent becomes requirements. Requirements become design. Design becomes code. Code becomes a deployed system. Each step is a transmission between people, artifacts, and tools — and every transmission loses fidelity.
This is not a metaphor about disorder. It is the ordinary behaviour of a noisy channel. If each stage transmits faithfully with probability p, then across n stages fidelity is pⁿ. Errors do not add. They compound multiplicatively.
Five stages at 90% fidelity each leave you at 59%. Not because anyone was careless — because that is what serial transmission does absent correction.
The empirical version of this is older than most working programmers. Lehman's second law of software evolution, stated in 1974 and confirmed repeatedly since: as a system evolves, its complexity increases unless work is done to reduce it. The important clause is the last one. Degradation is the default. Order is the thing that costs energy.
Information theory also tells us the remedy, and names it precisely: error-correcting codes. You do not fix a noisy channel by transmitting more carefully. You fix it by adding redundancy and checking at each stage. In software, those checks are gates — types, tests, review, CI, staged rollout. And coding theory is explicit about the crucial property: correction must happen at every stage. A single check at the end cannot recover error that has already compounded through four uncorrected transmissions.
That is the entire argument for gating, and it is why a project with review only at release fails no matter how good that review is.
Mechanism two: complexity lives in the edges
The second mechanism is not about errors at all. It is about what an error costs once it exists.
Take a system of n components. If any component may interact with any other, the number of possible interfaces is n(n−1)/2 — quadratic. Add a component and you add n new potential interactions.
Architecture is the discipline of preventing that. Its job is to bound each component's degree: this module talks to those three and no others. Then the interaction count is O(n) rather than O(n²), and — this is the part that matters — the blast radius of any change is bounded by the component it lives in and its declared neighbours.
That is the real definition of good architecture. Not layers, not diagrams, not patterns. Bounded blast radius. A change whose consequences you can enumerate.
Without it, every change is potentially global. You cannot reason about a modification because you cannot enumerate what it touches. The system becomes one in which small changes produce disproportionate and unpredictable effects — not because anything is mysterious, but because the interaction graph is dense and nobody is holding it in their head.
The two mechanisms multiply
Here is the part that usually goes unsaid, and it is the whole point:
damage ≈ (errors introduced) × (blast radius per error)
Gating attacks the first term. Architecture attacks the second. Neither is sufficient alone.
Perfect review of a hairball still yields chaos: your errors are few but each one propagates everywhere. Beautiful architecture riddled with unreviewed errors still fails: each error is contained, but there are too many. Projects survive by holding both terms down, and they fail when either one is abandoned.
This also explains a familiar and otherwise puzzling observation: a project can look healthy for a long time and then collapse quickly. The two terms move independently, and the product is what kills you. A team can degrade its architecture for a year while strong review keeps error count low — and then lose two senior reviewers and fall off a cliff.
What a healthy project looks like
Correction at every stage. Not one gate at the end. Requirements reviewed against intent, design against requirements, code against design, deployment against tests. Each stage catches its own class of error, because the class of error each stage introduces is different — and because uncorrected error at stage two is multiplied by everything downstream.
Architecture as coupling control. Explicit boundaries, enforced. Modules that declare what they depend on. Interfaces narrow enough to enumerate. The measure of success is not elegance; it is that you can answer "what does this change affect?" without reading the whole system.
Do both, and errors still enter — they always do — but they enter at a controlled rate and stay where they land.
What a failing project looks like
No effective gating. Errors introduced at requirements survive design, survive implementation, and are discovered in production, where they cost orders of magnitude more to fix and arrive wrapped in the consequences of everything built on top of them.
No architecture. Coupling grows unmanaged. Every change becomes an integration event. Estimates stop being meaningful because the blast radius of a change is unknown before you make it. The team develops the characteristic learned helplessness of the legacy codebase: nobody knows what will break, so nothing is touched without ritual.
The end state is a system whose complexity exceeds anyone's ability to reason about it. And notice what has actually failed at that point: not the code. The specification. Nobody can any longer say what correct behaviour is, which means nobody can tell whether a change is right.
Now add AI
AI does not create a third mechanism. It changes the rate constants — and it changes them in exactly the wrong combination.
It raises the error count, mostly through volume. Per line, on a narrow well-specified task, a good model is competitive with a competent engineer. That is not the problem. The problem is that ten times the code contains ten times the defects even at an equal rate, and the review capacity on the other end did not increase.
It shifts the error distribution, and this is the underrated half. Human errors tend to fail loudly: the code doesn't compile, the obvious case crashes, the reviewer sees something odd. AI errors compile, read idiomatically, follow local convention, and pass a skim. They are plausible. Gates designed to catch human failure modes are poorly matched to them.
I will make this concrete, from a system I evaluated closely. It had a static check whose entire job was to enforce declared boundaries between modules — which module is permitted to depend on which. The check compared the wrong side of the relation. Where it should have asked whether the depending module held permission, it asked about the depended-upon one.
The consequence was total: it accepted every forbidden dependency, and rejected several legal ones.
It survived because it looked functional. It emitted well-formatted, plausible-sounding errors — enough of them, and specific enough, that a reviewer would conclude the gate worked. Only by writing a deliberate violation and watching it compile does the failure become visible. Everything downstream had inherited a guarantee that did not exist.
A gate that does not gate is worse than no gate, because it converts unverified work into apparently-verified work. That is the characteristic AI-era defect, and it is not a coding error. It is a verification error.
It optimizes locally with no global view. This is the most dangerous property. An agent pursues the goal in front of it. It does not hold an architectural principle established three weeks ago in a different subsystem. It will satisfy the compiler, pass the test, close the ticket — and if the cheapest path there increases coupling or degrades a global property, it takes that path, because nothing in its objective penalizes it.
Concretely, from a performance-sensitive system I measured: a change introduced an optimization that skips work the system can prove it doesn't need. The optimization was correct. It also ran its setup cost on every request — including the ones with nothing to skip, which paid the cost and received none of the benefit.
The cheapest operation in that system's own performance suite became roughly six times slower, turning a previously winning result into the worst in the set. It then survived dozens of subsequent commits, because every gate in place still passed. Nothing had been allocated. No new external effect was performed. The only thing that regressed was time — and nothing measured time.
That is greedy optimization against a global constraint, and it is what an unattended agent does by construction. Note that no human reviewer would likely have caught it either: the change looks correct in isolation, and it is correct in isolation. The defect exists only in the relationship between the change and the workload.
Why more compute does not rescue it
The intuition is that if AI created the mess, more AI can clean it up. The arithmetic disagrees.
Generation cost per change is roughly constant. Producing a change costs about the same whether the system has ten modules or ten thousand.
Verification cost scales with coupling. To know a change is correct you must consider what it interacts with. In a well-architected system that is a bounded set. In a densely coupled one it is O(n) per change, and O(n²) cumulatively across a project's lifetime.
So generation grows linearly and verification grows quadratically, and the gap widens with every commit. Past a threshold you are producing changes faster than any amount of compute can establish they are correct — and correctness is not a property you can sample your way to, because the failures are in the interactions you did not enumerate.
And there is a harder wall behind that one. When complexity exceeds anyone's ability to state what the system should do, more generation produces more unverifiable code. You cannot test your way out of an unspecified system, because tests encode a specification and you no longer have one. At that point compute is not merely ineffective — it actively accelerates the collapse.
What actually works
The prescription follows directly, and it is not "review more carefully." Human review does not scale with generation volume; that is arithmetic, not attitude.
- Gates must be machine-applied. If the check requires a human to read the code, it is not a gate — it is a hope. Types, contracts, capability declarations, dependency rules, property tests, benchmarks-as-gates. Anything a machine enforces on every commit without asking.
- Architecture must be machine-enforced. A diagram is not architecture; it is a claim about architecture. Architecture is a boundary the build refuses to cross. If your module dependencies live in a wiki page, they are already wrong and nobody knows it yet. If they live in a manifest the compiler checks, they cannot silently drift — and an agent optimizing locally cannot increase coupling, because the build stops it.
- Guard the properties nothing else measures. Every project gates on "does it compile" and "do tests pass." Almost none gate on "did latency regress," "did the dependency graph grow an edge," "did binary size jump," "did this module acquire a capability it didn't have." Those are exactly the properties local optimization degrades, and exactly the ones that fail silently.
- And verify the verifiers. The gate that enforces nothing is the highest-cost defect in this entire model, because it disables a term in the damage equation while appearing to hold it down. Test your gates the way you test your code: write the violation, confirm the build rejects it. If you have never seen your architecture check fail, you do not know that it works.
The uncomfortable conclusion
None of this is new. Brooks and Parnas and Lehman described these mechanisms decades ago, and the discipline that answers them — gate at every stage, bound the coupling — has been known and unevenly practised ever since.
What AI changes is the margin for not doing it. A team writing code by hand generates errors slowly enough that mediocre gating mostly holds, and grows coupling slowly enough that architectural neglect takes years to become fatal. Both of those were slack, and the slack came from human slowness. It is gone.
So the projects that fail in the AI era will fail for entirely traditional reasons, on a compressed timeline, and — this is the part that should worry you — with better-looking intermediate artifacts than failing projects have ever had. The code will read well. The tests will pass. The gates will report green.
Right up until someone measures.
Why we built the claim layer. The prescription above — machine-applied gates, machine-enforced architecture, guarding the properties nothing else measures — is the design spec for SuperJ's claim layer. capabilities is a machine-applied gate ("this package may not do net"), architecture is machine-enforced layering ("this package may not import sj.http"), noalloc guards the property nothing else measures ("this hot path may not allocate"), and superj capabilities --test is the verify-the-verifier step. The four prescriptions, one mechanism each. Written by AI. Read by human.