Why Your Codebase Is Forcing Your AI to Underperform

0
1
Why Your Codebase Is Forcing Your AI to Underperform


You rolled out Copilot, Cursor, or Claude Code across hundreds of engineers. Six months in, the productivity lift is real but smaller than the slide deck promised — and uneven, with some development teams flying and others barely moving. 

The AI isn’t underperforming. Your codebase is forcing it to.

The new cost of carrying unused code

Every codebase carries weight that no longer earns its keep — methods nobody calls, libraries nobody loads, features that shipped years ago and quietly stopped mattering. Engineering leaders have always known the cost of maintaining and securing dead or unused code is expensive. What’s changed is who pays the bill. 

Until recently, the tax was paid in human attention: slower onboarding, longer code reviews, the hesitation before touching an unfamiliar branch. Painful, but bounded — a senior engineer learns to navigate around the dead zones, and the team absorbs the friction. AI coding assistants don’t get that luxury. 

To make a change in any non-trivial area, the assistant has to read the surrounding code, and its context window is finite. Every library, every unused class, every orphaned helper, every dependency the agent pulls in to “understand the area before changing it” consumes costly tokens that could have gone to the actual task. 

Unused code looks identical to live code on disk. The AI can’t know it’s irrelevant until it’s already read it. By then the cost is paid: longer prompts, weaker reasoning, more hallucinated calls to methods that no longer matter, more rework. 

The AI’s effective intelligence on your codebase is inversely proportional to your dead weight. And that translates into the consumption of AI token spend that pulls from budgets that should be allocated to leveraging AI to innovate new features and applications  

This is technical debt, and it now compounds faster

It’s worth naming this for what it is: technical debt, in the original Ward Cunningham sense — work that was rational to defer at the time, accruing interest until somebody pays it down. Every acquisition you absorb, every modernization you sequence, every feature you ship without retiring the one it replaced adds to the principal. 

Engineering teams feel it: in Azul’s 2026 State of Java Survey & Report, 63% of respondents said dead and unused code is hurting their team’s productivity, and only 6% reported no impact at all. Two things have changed in the last 24 months. 

First, the interest rate went up: AI assistants now sit in the middle of nearly every code change, and they pay the carrying cost with token usage on every prompt. Second, the principal grew faster than your team did — in the same survey, every respondent reported using AI code-generation tools, and 30% said more than half their new code is now written by AI. More code, written faster, with less of it being deleted on the way in.

If you’re an engineering leader making AI investment decisions today, the implication is uncomfortable. The same productivity tool that promises to clear your backlog is also expanding the surface area it has to reason over. Without an intentional countermeasure, you’re funding both sides of the trade. 

Why the obvious answer — “just run static analysis” — only gets you partway 

Most engineering organizations already have static analysis wired into CI, flagging unreachable branches, unused imports, and dead variables. It’s the right baseline: if no code path reaches a method, deleting it is safe. 

But static analysis is conservative by design. The tools would rather miss real dead code than flag something that turns out to be live — a wrong deletion is catastrophic, a missed one is merely wasteful. And they can only reason what they can see in the source: anything called through reflection, dependency injection, configuration-driven dispatch, feature flags, or runtime service lookup appears reachable on paper, even if that path hasn’t fired in production for three years. 

The analyzer leaves it alone, correctly, because it has no way to know. So the easy 10–20% of unused code — the stuff with no caller at all — gets cleaned up by these static analysis and IDE tools you already own. The other 80% — code that compiles, has callers, passes the linter, and never actually runs — sits in the repository, in the context window, and on your AI bill.

Runtime evidence: ask what ran, not what could run 

The category that closes the gap is runtime evidence — observing applications as they execute in production and cataloging which classes, methods, and libraries actually run. Azul Intelligence Cloud’s Code Inventory is the most direct expression of this approach for Java estates. It works on any JVM — Azul, Oracle, Eclipse Temurin, Microsoft, Red Hat, IBM — so a single dataset covers the whole footprint. 

Where static analysis asks could this code be called, Code Inventory knows whether it was or not. Over a normal business cycle — long enough to capture quarter-end jobs, the annual reporting module, the seasonal promotion path — the picture of what your code actually does in production resolves with high confidence. 

Code that has callers on paper but never executes shows up as exactly what it is: dead weight that static tools cannot see. One Azul customer described it concisely after an acquisition: millions of lines of unfamiliar code, months of reading ahead of them, and instead they used Code Inventory to identify large portions of unused code and archive it. That’s the shape of the win — not a marginal refactor, but a defensible decision to remove code, backed by evidence rather than guesswork. 

Pair Code Inventory with an automated refactoring platform like Moderne and OpenRewrite, and the removal step scales across tens of millions of lines instead of becoming its own multi-quarter project. 

Cleanup is the multiplier on your AI spend 

Here is the part that matters for the budget conversation. Removing unused code is not a competing line item against AI tooling. It’s the multiplier that determines what your AI tooling is actually worth. Every line that comes out of the repository pays compounding dividends. 

AI agents read less to understand any given change, so more of the context window is available for the actual problem. This means better suggestions and fewer fabricated calls to methods that no longer exist. Human reviewers stop second-guessing whether the dead branch matters. 

Vulnerability triage shrinks: fewer dependencies, fewer CVEs to investigate, fewer hours spent on the false-positive treadmill that 30% of teams now report consumes more than half their vulnerability-triage time, much of it spent on code paths that never run in production. Tests for retired features can be deleted along with the features themselves. 

None of these benefits show up on the AI vendor’s pricing page, but every one of them shows up in the ratio of AI spend to delivered output. The inverse is also true, and it’s the case worth making to your CFO. 

If you scale AI tools across a codebase carrying years of unused code, you are paying full price for AI sessions that spend a significant fraction of their context budget reading material that should have been deleted. That cost is invisible on the invoice and very real in the output. 

Sequence the work 

You don’t have to choose between cleanup and velocity, and the framing of “pause AI rollout to do refactoring” is the wrong one. The work runs in parallel, in this order: 1. Instrument production with runtime evidence and let it build the picture of what’s actually used. This is passive — engineering teams keep shipping while the data accrues. 2. Remove what the evidence says is safe to remove. Use static analysis for the structurally unreachable cases and runtime evidence for the much larger category it can’t see. Where the volume justifies it, automate the removal with rules-based refactoring rather than treating it as bespoke developer work. 3. Scale your AI tooling against a codebase where every line earns its place in the context window. 

The cheapest line of code to maintain has always been the one that isn’t there. In the AI era, it’s also the cheapest line for your assistants to read, the cheapest to keep secure, and the cheapest to leave out of every prompt your engineers will run for the rest of the product’s life. That’s the line item worth funding first. 

 

Erik Costlow