How to read: on the left, the one-way arrow — the rewrite that loses the rules no one documented. On the right, the path through the trail: first discover and lock down the current behavior (cyan), then migrate one piece and compare. AI should reduce risk, not increase it.
Learning path map
Detailed content
🏚️ Safe modernization of legacy systems
Dependency mapping, hidden business rules, characterization tests, hidden integrations, boundary isolation, and gradual migration with comparison.
The inventory of what exists: modules, integrations, jobs, databases, who calls what, and what is already dead code.
AI is excellent at this — reading a lot of code and summarizing its structure is where it delivers the most value. And without the map, you don't know where it's safe to cut.
Inventory before planning · Dead code is the cheapest cut · Who calls whom defines the possible boundary.
Extracting the actual rules that exist only in the code: historical exceptions, special customer cases, rounding, deadlines, and regulatory behavior.
These are the ones that break during a rewrite. And they’re invisible to anyone who only looks at the documentation—which almost always describes the system that was intended.
Code is the truth · Historical exceptions usually have an owner · A discovered rule becomes a test, not a comment.
Tests that record what the system does today — including what seems wrong — so any behavior change shows up immediately.
This is the safety net that makes modernization possible. Without it, “I refactored it and everything works” is an unsupported claim.
Characterization ≠ validation · Known bugs are behavior too · AI generates these tests in volume, and it’s great at that.
The search for undocumented consumers: scripts, spreadsheets, jobs owned by another team, reports that read directly from your database.
It’s the main source of post-migration incidents: you turned off something “no one used,” but someone did.
Access logs reveal consumers · Turn things off in stages (announce, deprecate, remove) · Silence isn’t proof something is unused.
Creating a seam between the old and the new — an adapter that lets you swap the implementation without changing its consumers.
Without a defined boundary, the migration becomes a rewrite: each piece pulls in another and the scope explodes.
An adapter decouples the schedule · A good boundary has few consumers · Gradual strangler migration > big bang.
Run both implementations side by side with the same input, recording differences before switching over completely.
This is the strongest proof there is that the new version does what the old one did—including in cases no one remembered to test.
Divergence is information, not an error · Gradual rollout by percentage · AI reduces risk; it doesn't expand it.
🗺️ Agent-Readable Architecture
Predictable structure, clear boundaries between modules, documentation close to the code, explicit contracts, standardized commands, AGENTS.md, skills, playbooks, and single sources of truth.
An organization where the directory and file names let people predict where something is—for new people and agents.
A predictable repository reduces the context an agent needs to load and the number of assumptions it makes.
Convention > configuration · Consistent naming is infrastructure · Predictable structure helps both people and machines.
Declared boundaries between domains, with import rules that can be checked automatically.
An agent respects the boundaries it can see. A boundary that exists only in the architect’s head will be crossed.
Verifiable rule > agreed-upon rule · Imports are the evidence · Boundaries also limit task scope.
Documentation versioned in the repository: architecture, domains, decisions, and playbooks, reviewed alongside the code they describe.
Docs in the repository are part of review and the agent's context. Docs outside it become folklore in three months.
Documentation is part of the diff · Decision records explain why · Outdated docs are worse than no docs.
A single, documented command to install, test, lint, build, and validate—one that works the same on everyone’s machine and in CI.
It’s what lets the agent close the loop on its own. Without a standard command, it makes one up—and gets it wrong.
Fast local tests are agent infrastructure · Same command locally and in CI · Script > prose instruction.
A file with an overview, key commands, project rules, where the documentation is, limitations, quality criteria, prohibited actions, and references to skills and playbooks.
It shouldn’t hold all the project’s knowledge—it should serve as a map. Even humans won’t read a 900-line AGENTS.md.
The map points the way; it doesn’t describe everything · Prohibited actions are highlighted · It’s reviewed like code.
A single canonical place for each piece of information—commands, contracts, conventions—with no conflicting copies scattered around.
When faced with two conflicting sources, the agent chooses one—and you discover which one during review, at the worst possible time.
Few conflicting sources · Reference > duplicate · Duplicated truth always diverges.
🪓 Overengineering and AI-generated technical debt
The smallest possible change, premature abstractions, unnecessary dependencies, semantic duplication, superficial tests, and code that passes tests but violates the intent.
The default instruction: implement the smallest change that meets the acceptance criteria; don’t create new abstractions, dependencies, or layers without a demonstrated need.
AI tends to produce seemingly complete solutions even when a smaller solution would suffice — and the cost shows up in maintenance.
Preserve the existing structure · Justify every new component · Smaller diffs are easier to review.
Layers, interfaces, and “internal frameworks” created for hypothetical cases no one asked for and that may never arise.
A bad abstraction is more expensive than duplication: it must be undone before any future change.
Abstract after the second (or third) real use · A hypothetical case is not a requirement · Simple and extensible: compare the two.
Prohibit new dependencies without approval and limit the number of files changed per task.
Every dependency is an attack surface, an update cost, and an abandonment risk. And diffs that are too large don’t get reviewed — they get accepted.
Dependencies have a permanent cost · File limits reveal when scope has ballooned · Out-of-scope refactoring can wait for another PR.
Two or more implementations of the same concept, written differently—impossible to find with text search, but discoverable by an agent that reads the repository.
This is the kind of debt AI generates most, because each task starts without remembering what already exists.
"Does something like this already exist?" before creating it · Inconsistencies between modules confuse the next agent · Consolidation is recurring work.
Tests that run the code without asserting relevant behavior: they cover the happy path, boost the metric, and catch no defects.
They create the worst possible combination: a sense of security with zero protection—and they block refactors by testing the implementation.
A good test fails when behavior changes · Errors and edge cases > happy path · A test that only runs is debt, not an asset.
A solution that satisfies the verifier without solving the problem: a special case hardcoded to pass the test, a swallowed exception, a cache that hides the bug.
It’s the most dangerous flaw in AI-driven development because it passes through every automated gate with a green signal.
Read the diff, not just the result · Intent review is human · A metric becomes a target and stops being a good metric.