Skip to the content.

AI does not remove technical debt — it lets you create it faster

AI does not remove technical debt — it lets you create it faster

There is a comforting story that AI will clean up our codebases. The opposite is the default. A model that writes code ten times faster also writes debt ten times faster, because it optimises each task locally and has no stake in the whole. The productivity is real — and so is the pile it leaves behind if nothing holds it to a standard. Technical debt is not a byproduct of slow humans that speed removes; it is what accumulates when changes are made without regard for the system’s shape, and a fast generator makes changes faster than that regard can keep up. AI is an accelerator, and an accelerator points debt whichever way you were already headed.

Without a standard, faster generation means a faster-growing debt curve Two curves over time. Without guardrails, debt rises steeply with AI speed. With a guardrail floor, debt stays flat because each change is held to a standard. changes over time → debt no standard guardrail floor
Speed does not bend the debt curve down; a standard does. Without one, faster generation just climbs the curve faster.

The debt AI adds looks like progress

The dangerous thing is that AI-generated debt arrives disguised as velocity. Each diff works and ships, so the dashboard looks great — while boundaries erode, the store fills with derived fields, and the same near-duplicate component appears in five places because generating a fresh one was easier than finding the existing one:

// generated three times across the app, slightly different each time — debt as "done"
function UserBadgeV2({ user }) {
  const data = useSelector((s) => s.users.byId[user.id]);   // fetches in the UI, again
  return <span>{data?.name}</span>;
}

No single diff triggers a review flag. The pile is the sum, and the sum grows at generation speed.

The standard has to be executable

You cannot hold the line by intention when changes arrive faster than you can read them — the only backstop that scales with generation is one that runs. Encode the architecture rules as checks, and debt-adding changes fail at the door instead of merging and compounding:

// the standard, executable: a UI file that imports state fails the build
test("no state imports under ui/", () => {
  for (const f of glob("src/ui/**/*.jsx"))
    expect(read(f)).not.toMatch(/useSelector|from ['"].*\/state/);
});

Now the third duplicated, store-reaching badge does not land, and the debt curve stays flat because each change is measured before it joins the pile.

Speed is only a gift if the floor holds

The honest framing is that AI’s speed is a genuine gift conditional on a standard that holds at that speed. Pair fast generation with an executable guardrail and you get the productivity without the pile — the model does the volume, the checks keep the shape. Skip the guardrail and you get a codebase that grew a year’s worth of debt in a sprint, all of it looking like progress until the day a small change touches fifty coupled places. This is the same lesson as “executable guardrails beat review,” sharpened by throughput: the faster the generator, the more the floor matters, because there is less and less time for a human to catch what slips. The harness-atom-guardrail and harness-state-shape exercises build exactly the floor that keeps AI’s speed from becoming AI’s debt.