The fire started in a function called calculateTax. The agent looked at a nested if ladder, decided it was redundant, and flattened it into something clean. It was clean. It was also wrong, because one of those branches existed solely to handle a single grandfathered account from 2014 whose contract predated a pricing change nobody had written down. The test suite didn't catch it. There was no test suite. We found out in production, on a Friday, from a customer in a timezone eight hours ahead of anyone who could fix it.
This is the postmortem on what happens when you point an AI coding agent at a 12-year-old enterprise monolith — no tests, 2008-era patterns, the kind of system that quietly pays everyone's mortgage and that nobody touches on purpose. The incident above is a composite scenario built from documented failure modes, not a log of a single real outage. Some of it was genuinely great. Some of it set things on fire. Here's the ledger, and the guardrails that flipped it from liability to leverage.
Where it actually helped: archaeology, not authorship
The real wins were not the agent writing code. They were the agent reading it.
Point Claude Code or Cursor at a 4,000-line file nobody has opened since the guy who wrote it left, ask "what does this do, and what calls it," and you get back something that used to cost two weeks of a senior engineer's attention. Dead-code detection. Dependency mapping. Reconstructing the business logic fossilized inside a 600-line stored procedure. Generating the first honest documentation the module has ever had. Proposing test scenarios for behavior that was never specified anywhere except in the running code.
This is the discovery phase — the work that's always been too expensive to fund, so nobody funds it, so the monolith stays unknowable, so it stays unfundable. The agent breaks that loop. It is an archaeologist with infinite patience for boring dig sites. That framing — archaeologist, not contractor — was the single most useful thing I took out of the whole exercise. When Anthropic positioned Claude Code for COBOL modernization in February 2026, it was the discovery pitch that landed. Reading the dead is the part that genuinely works.
Where it set things on fire
Here is the load-bearing lesson, the one I'd tattoo on a junior: the agent refactors what it thinks the code does, not what it actually does.
On a 12-year-old monolith, the weird edge cases are the spec. That if (user.id == 4173) is not a smell to be scrubbed out; it is the only surviving record of a decision someone made in a meeting in 2016 and then quit. The agent has no way to tell the load-bearing ugliness from the genuinely dead branch. It pattern-matches "ugly" to "removable." That is how calculateTax caught fire.
It gets worse with size, and the worse is measurable. Independent testing of Claude on COBOL found it surfaced 69–86% of paragraphs on a small program — but only 24–35% on a larger one, and the results weren't stable run to run. Read that twice: on the big crusty files, the exact ones you most want help with, it silently drops two-thirds of the logic, and drops a different two-thirds each time you ask. Complete coverage, exact accuracy, and run-to-run determinism are three things a probabilistic tool cannot promise — and a migration needs all three at once.
Security is its own specific cruelty on old code. Industry benchmarking puts AI-assisted code at more than 2x the rate of critical vulnerabilities and logic errors versus human-written; OX's 2026 numbers had critical findings up roughly 4x year over year, driven by AI output. The legacy-specific twist is the nasty one: the models trained on a decade of public code, so they replicate the era's flaws. Hand the agent a 2008 monolith and it cheerfully re-injects 2008-vintage SQL injection and XSS, because those patterns saturate both its training data and your repo. It does not modernize the anti-pattern. It recognizes it, agrees with it, and breeds more of it.
There's even a quality floor below which the whole thing stops working. CodeScene's sector data puts average hotspot code health at 5.15 out of 10; their research suggests you need somewhere around 9.5 to keep AI-induced bugs in check. A 2008 monolith does not live anywhere near 9.5. So the agent's error rate is structurally highest on precisely the code you most wanted to hand off. The uncomfortable conclusion: the legacy code has to be cleaned up for the AI before the AI can be trusted to clean it up.
The productivity mirage
Here's the part nobody puts on the slide. In METR's randomized controlled trial, experienced developers working in their own repositories were 19% slower with AI. Not a rounding error — measurably slower. The kicker: going in, they predicted a 24% speedup, and after finishing they still believed they'd been 20% faster. The gap between felt speed and real speed is the entire trap.
On a codebase you know in your bones, validation-and-correction overhead eats the gain. Your time goes into reading the diff and reverse-engineering whether the agent actually understood the thing you already understood cold. Juniors landing in unfamiliar code see 10–30% gains; experts on familiar legacy go negative. Which produces the genuinely counterintuitive rule of this whole exercise: the deeper you personally know the monolith, the more the agent costs you on the parts you understand — and the more it earns its keep on the parts no living person understands. Aim it accordingly.
The guardrails that flipped it
None of what made this work was the model. It was the constraints bolted on around it.
Characterization tests first. Non-negotiable. Before the agent touches anything, you pin the current behavior — bugs, weird edge cases, grandfathered-customer hacks, all of it. Pick one high-churn change point. Write one test that captures today's exact outputs. Introduce one seam around the most volatile external dependency so the test runs the same way twice:
# Pin reality before you "improve" it.
def test_calculate_tax_characterization():
# Not "correct" — just what it does RIGHT NOW, customer 4173 included.
assert calculate_tax(order_4173) == Decimal("0.00")
assert calculate_tax(standard_order) == Decimal("8.25")
That test is the entire answer to the "no tests" problem. It is the smoke detector calculateTax didn't have.
Govern the refactoring, or it optimizes for diff volume. Left alone, the agent does more edits than a human and shallower ones — it'll rename 50,000 variables and call it a day's work. CodeScene's benchmark found tool-guided refactoring delivered 2–5x more code-health improvement than raw agent attempts: structural Extract Method operations jumped from 7,550 to 21,702 once guided, while cosmetic Rename Variable ops collapsed from 54,094 to 8,640. Ungoverned, it produces motion that photographs like progress and isn't.
The rest of the kit. Automated security gates at the source, every PR, no exceptions — you cannot eyeball re-injected SQLi at scale, and at scale is the only scale this runs at. Humans stay as reviewers, and you budget the hours for it, because review is the bottleneck now, not authorship. One change point at a time, with fast rollback wired up before the first commit instead of improvised after the incident.
And scope, the hardest one to hold. The agent gets discovery and mechanical migration. It does not get autonomous, behavior-changing refactors. Ever. The day you relax that is the day you get another Friday.
The verdict
The optimistic case is real. McKinsey pegs GenAI modernization at cutting timelines 40–50% and tech-debt cost around 40% — though that's a vendor-adjacent figure and you should price it as one. IBM's rebuttal to the COBOL hype is the line I keep returning to: "decades of hardware-software integration cannot be replicated by moving code." Moving the code was never the hard part. Preserving what the code was quietly load-bearing for — the 2014 contract, the 2016 meeting, the branch nobody documented — is the hard part, and it is exactly the part the agent cannot see.
An AI coding agent on a legacy codebase is a power tool with the blade guard removed. Unboxed and pointed at a 12-year-old monolith, it will take a finger off. Bolt on the characterization tests, the security gates, the budgeted human reviewer, the one-change-at-a-time discipline, and the same tool becomes the most patient archaeologist you've ever hired. The model didn't change between those two outcomes. The guardrails did.
