Refactoring Got Cheap. The Judgment Didn't.
AI is genuinely great at the mechanical part of a refactor, the rename across two hundred files, the extraction, the tedious restructure. Which is exactly the trap. The typing was never the hard part, and the part that was hard is the part the model still can't do for you.
Listening · Refactoring Got Cheap. The Judgment Didn't.
I've spent a good chunk of this year migrating the item system on IcePets, the community I run, out of its legacy codebase and into a new one. It's exactly the kind of job AI is supposed to be great at: read the old code, carry every item's details across, and enhance them on the way for better visibility and usability. In a lot of ways it was great. The sheer volume of mechanical moving it handled would have cost me weeks by hand.
It also broke things, missed things, and, most tellingly, invented its own conventions as it went, inconsistent ones, left, right, and centre, in a codebase that already had perfectly good conventions sitting right there to follow. That migration is the clearest lesson I've had in where AI-assisted refactoring actually helps and where it quietly hurts you, and the line between the two is not where you'd guess.
The typing was never the hard part
Here's what changed and what didn't. AI made the mechanical 80% of a refactor nearly free. Rename a concept across the whole project, extract a tangled method into three clean ones, restructure a module, scaffold the tests, all of it is now minutes instead of an afternoon. That's real, and it's great.
But the hard part of refactoring was never the typing. It was knowing what's safe to change. Which pieces are load-bearing, which assumptions other code quietly depends on, which weird-looking line is weird for a reason. That knowledge lives in your head, and honestly, barely even there. It is almost never written down in the code the model can see. So AI got dramatically better at the easy part and no better at all at the part that was actually dangerous.
The model can't see the contract nobody wrote down
This is the failure mode that matters, and if you've read what I've written about legacy code you already know its shape. In a codebase with a long memory, a lot of the "messy" code is load-bearing. It's there because of a bug someone hit in production, a client edge case, an ordering assumption two systems silently agreed on. None of that is in a comment. It lives only in the fact that the code is shaped the way it is.
An AI reads that same code and sees mess. It will confidently, helpfully, tidy it, and the tidied version is cleaner and reads better and passes the tests you have, and it also just quietly changed the thing that was holding something up. The model isn't wrong about the code being ugly. It's blind to why the ugliness was there. And it is most eager to clean exactly where your codebase is oldest and least documented, which is precisely where you're most tempted to point it and look away.
It won't follow your conventions unless you make it
There's a second, quieter cost I didn't expect until I watched it play out across a big migration. The model doesn't just miss the contracts it can't see. It also ignores the conventions it can. Hand it the same kind of task in ten places and you can get ten subtly different shapes back: naming that drifts, a pattern that doesn't match the one in the file right next door, the same idea expressed three ways. Each piece looks fine on its own. Together they're a mess, because nothing was holding them to a single house style.
That inconsistency is its own maintenance tax, and you pay it later. A codebase where similar things look similar is one you can reason about. One where every function was apparently written by a different person, because in a sense it was, is one you have to read line by line forever. So part of the judgment you're keeping is consistency: hold the model to your conventions, reject the diff that reinvents a pattern you already have, and treat "it works but it matches nothing around it" as a real problem, not a nitpick.
Let it type. Keep the wheel.
The division of labour that works is the obvious one once you name it: the AI drives the mechanical change, you own the judgment about what's safe to touch and why. In practice that's four habits.
Refactor behind a green test suite, always. Cheap, high-volume change needs a net more than careful hand-editing ever did, because you're now moving fast over a lot of surface. If a corner of the code isn't tested, AI-refactoring it is working without a net at speed, and that's when things fall quietly.
Review the changes as changes, not as output. Read every diff the way you'd read a pull request from a fast junior who doesn't know your system, because that is exactly what it is. "It compiles and the tests are green" is necessary, not sufficient, especially where the tests are thin.
Keep the blast radius small. The temptation AI creates is the big-bang refactor, because it suddenly feels easy. Resist it for the same reason you always did. Small, reversible steps. Cheap to make is not the same as safe to make, and a huge diff is a huge diff no matter who typed it.
And when the model wants to simplify something strange, treat the strangeness as a thing to investigate, not delete. The weird code is very often the contract. If you can't explain why it was written that way, you're not ready to let anyone, human or model, "clean it up" yet.
AI changed the economics of refactoring, not the risk. It made the cheap part cheaper and left the expensive part exactly where it was, in your head, which is the one place it was always going to stay. Let the model do the typing. Keep the wheel, because the wheel was always the job.