Encase It in Amber Before You Refactor It
Before you let anyone touch the internals of a legacy system, human or AI, there's one question that has to be answered first: how will you know if its behavior changed? Not "did the code get cleaner," not "does it still compile," but does the system, in every case that matters, still do what it did before. If you can't answer that with something more rigorous than "it looks right," you're not ready to refactor yet.
The technique for this has a name: characterization testing, sometimes called a golden master test, and it's not new. You take the system as it actually behaves today, quirks, undocumented edge cases, and all, and you capture that behavior as a baseline: run it against a wide range of real or realistic inputs, record the outputs, and treat that recorded behavior as the specification, whether or not it matches what anyone originally intended. Then any change, refactor, migration, AI-assisted rewrite, anything, gets checked against that baseline. A deviation isn't automatically wrong. But it becomes a conscious decision instead of an accident nobody notices until a customer does.
I think of this as encasing the current functionality in amber. You're not deciding yet whether every quirk in there is a feature or a bug, that's a separate conversation. You're just making sure nothing changes without someone choosing that it should.
Why this matters more with AI in the loop
A human refactoring legacy code at least has some intuition for what's odd about it, some sense of "that looks intentional" versus "that looks like a bug nobody noticed." An AI coding assistant doesn't have that intuition. It has the code in front of it, and it will happily "fix" a quirky-looking conditional that was actually load-bearing, because it read as an obvious bug rather than a deliberate, undocumented workaround for some hardware timing issue three layers down. I've seen that exact failure mode by hand, long before AI tooling existed, reverse-engineering an algorithm after the person who understood its quirks was gone. The only reliable way I had to know I hadn't broken anything was locking down its actual observed behavior first and checking every version against it.
That's the whole argument for characterization tests before any AI-assisted refactor: they're not a replacement for understanding the system, they're the mechanism that lets you safely not have to understand every corner of it before someone, or something, starts changing it.
Without that baseline, "the AI generated a plausible-looking fix" is just a guess dressed up as confidence.
This is close to step one of any legacy modernization engagement I run. Before touching architecture, before discussing what the code should look like, lock down what it actually does now. Everything after that is safer because of it.
If you're staring down a legacy system you want to modernize, with or without AI-assisted tooling, and you don't have a reliable way to detect a behavior change yet, that's the place to start.
Read: A Test Plan Is How You Review Code You Didn't Write → See Legacy Modernization →