4.2 Migrating to MAGE
Most readers do not begin on a blank page. You inherit code, tests, schemas, architectural documents, CI rules, permissions, dashboards, conventions, and operational lore. Some of that inheritance is debt; some is useful engineering structure that has become fragmented, stale, or difficult to reuse. Migration is therefore partly an exercise in recovery: find the representations and controls the system already owns, reconnect them to the territory they describe, repair or retire what has drifted, and invest in new structure where recurring engineering costs justify it.
SOFTWARE ENGINEERINGInset — Software evolves; its engineering structure must evolve with it
Software engineering has long treated change as a normal property of successful systems rather than an exceptional maintenance phase. Lehman's work on software evolution observed that systems embedded in a changing real-world environment must continually adapt, while their complexity tends to increase unless engineers act to control it 11. Meir M. Lehman and L. A. Belady, Program Evolution: Processes of Software Change (Academic Press, 1985)..
MAGE extends that maintenance obligation beyond implementation. Models, validators, gates, runbooks, and other governance mechanisms describe or constrain a system that continues to change. They can therefore drift, preserve assumptions that no longer hold, or impose costs that no longer earn their keep. A governed engineering environment is not a finished artifact. Its engineering structure must evolve with the system it governs.
Two axes fix the starting move. The first is how much system already exists. A mature system gives you implementation, history, and latent models to recover; a new system does not. The second is how settled the relevant intent is. A detailed contract can justify substantial modeling and enforcement before implementation; an exploratory product question cannot. These axes are independent. Greenfield does not imply uncertainty, and brownfield does not imply settled intent: a blank-page regulated system can carry highly settled obligations, while a mature product may still be exploring what its users need.
Figure 4.2-1 crosses how much of the system already exists with how settled the relevant intent is. Each cell suggests the starting move.
Settledness does not determine whether an obligation requires judgment. "Make this explanation useful to its audience" can remain a stable objective without admitting a deterministic oracle. In that case, preserve and improve the representations, knowledge, examples, and procedures used to make the judgment rather than pretending to mechanize it. Conversely, exploratory work can contain settled sub-obligations that the environment can enforce. Decide enforcement obligation by obligation, and revisit that decision when better models or evidence make stronger controls feasible.
Brownfield work enters through many doors, but two are useful extremes. At one end is the fast-built system whose implementation outran its explicit engineering account: code exists, perhaps even a working product, but the architecture, obligations, and operating rules were never made durable. DocAble began near this end: a plausible product was built quickly, then migrated into a governed one. At the other end is the established organization with years of accumulated structure: ADRs, schemas, ownership files, developer portals, CI policy, tests, and operational playbooks. Its problem is not absence but fragmentation.
A fast-built system must author more of its initial models. An established system can recover and reconcile more of what it already knows. Both begin by inventorying the representations and controls already present, then investing where missing structure repeatedly consumes judgment.** A similar interpretation appears in recent developer-portal practice: a developer portal's value was never its UI but the curated context underneath — service and API catalogs, golden-path templates, ownership, CI/CD signals — and agentic engineering turns that human-facing surface into an execution substrate, "the portal isn't dying; it's becoming infrastructure" 22. Red Hat, “Why Developer Portals Matter More in the Age of AI Agents,” Red Hat, 2026, https://www.redhat.com/en/blog/why-developer-portals-matter-more-age-ai-agents..
Neither starting condition requires a complete governed environment before useful work begins. Preserve the obligations already worth preserving, surface the representations already worth trusting, and let implementation and operation expose what is still missing. The method is constant; the justified starting stock is not. A safety-critical project may begin with extensive explicit requirements and heavy validation; a product search may begin with a few non-negotiable constraints and measurements; a brownfield system begins with the accumulated evidence of its own history, however poorly represented.
Model-first and implementation-first suit different starting conditions. Where consequential intent is already known and costly to reconstruct, representing it before implementation narrows the search toward useful candidates. Where the right shape of the system is still uncertain, implementation is itself the experiment: build cheaply, watch what the result teaches, and model what proves consequential.
So the practical question is not how much to model in the abstract. It is how much structure the next unit of work needs. A familiar problem with strong tests and a well-matched reasoner may need little added representation; an unfamiliar domain with weak observability may need substantial modeling before autonomous work can be trusted. Add enough representation and evidence for the next unit of work to be delegated and evaluated responsibly; then let realization proceed.
At the low-structure extreme, implementation-first agentic development is heuristic search driven largely by the model's learned prior. In a familiar domain a capable agent can infer adequate abstractions, architecture, and implementation from surprisingly little explicit structure. Repeated failure changes the calculation. When agents keep reconstructing the same concept, cross the same hidden boundary, or re-search the same unproductive region, another attempt is worth less than changing how the problem is represented. Implementation-first becomes churn when the search repeatedly reconstructs structure whose explicit representation would cost less than continued rediscovery.
4.2.1 Start with What You Already Have
Begin with two questions, because representation and enforcement are different things. First, what does the organization already reason through? Which documents, schemas, graphs, tests, or configurations repeatedly save someone from reconstructing the system from raw implementation? Second, what is already enforced? Which permissions, types, validators, CI checks, reviews, or operational gates currently constrain or admit work, and what can each actually decide? A mature system may already contain substantial local Alignment even when its system-level representations are weak. A schema may reject invalid data, a type system may exclude states, and CI may block a merge. The migration problem is therefore not simply to build a better map and add controls afterward. Strengthen representation and enforcement together: connect useful representations to the territory they describe, make important obligations explicit enough to evaluate, and place enforcement where the required semantics are available.
A wiki is a useful first path because many organizations already have one and the migration distance is short. Treat it as an informal model: a reduced representation people already use to reason about the system, even though its semantics are weak and nothing mechanical guarantees correspondence with the code. Pages supply nodes of a kind, links supply relationships of a kind, and search supplies navigation. That does not make the wiki equivalent to the structured graph Part 2 built. It makes it raw material.
AGENT HARNESSInset — Knowledge Graphs
MAGE's move from informal system knowledge toward structured, queryable representations appears in current agent infrastructure partly through knowledge graphs. Documentation, source structure, ownership records, APIs, schemas, tickets, and other artifacts can be represented as entities and relationships that an agent can traverse rather than repeatedly reconstructing those relationships from raw text. A harness can then use the graph to assemble task-specific context: given a service, change, or question, retrieve the connected components, owners, dependencies, documentation, and other relevant knowledge.
This graphification can be a useful migration step. A wiki already contains weak structure in its pages and links; source code and organizational systems contain more. Extracting that structure into a graph can improve navigation, retrieval, impact analysis, and context construction. The resulting graph need not encode every engineering distinction, however. An extracted relationship may be incomplete, stale, or simply descriptive. A graph that records that service A depends on service B, for example, answers a different question from an architectural model that distinguishes observed dependencies from permitted ones.
This is why MAGE treats knowledge graphs as one substrate for externalized system knowledge, rather than as the Modeling abstraction itself. The engineering question still determines the representation: which entities and relationships need to be explicit, how trustworthy they must be, and what later reasoning or analysis will consume them. A knowledge graph earns its place when making those relationships explicit saves later work from reconstructing them and supports questions the engineering environment actually needs to answer.
The first improvement is connection, not replacement. Important claims should point to the code, tests, configuration, or runtime evidence that realizes them; important implementation regions should point back to the pages that explain why they exist.†† The earlier Parts develop the stronger form of this join: every model node can point to the implementation it represents, and that implementation can point back to the model node that explains it. The resulting trace is not yet a proof that the prose is true. It is a disciplined join that lets audits and later mechanisms discover when the map and the territory disagree. Figure 4.2-2 draws the two independent ways that join can be strengthened.
Brownfield representations can be strengthened incrementally from informal descriptions to structured, machine-readable models and, where a consumer justifies the cost, executable models.
4.2.2 Finding Models in the Implementation
Brownfield models need not begin with an engineer inventing the right abstraction in advance. Existing implementation often contains repeated structures that point toward models the system has never named. Static analysis, search, clustering, and other detectors can surface those patterns at scale, but their findings are evidence rather than conclusions. Repetition may reveal a missing domain concept; it may instead reflect appropriate low-level implementation, a protocol boundary, test scaffolding, or ordinary local cleanup. The detector finds places worth examining. Engineering judgment determines whether the repeated structure carries a shared meaning worth representing.
DocAble encountered this problem through a primitive-density detector, which identifies interfaces expressed heavily through bare strings, integers, tuples, and other low-level values. Primitive density is intentionally a weak signal: such interfaces sometimes indicate that a concept is being repeatedly reconstructed rather than represented explicitly, but they are also common in perfectly legitimate code. The detector therefore produced hundreds of findings without claiming that hundreds of models were missing. Most findings needed ordinary annotations or local cleanup, or occurred in test fixtures and protocol adapters where primitive-heavy interfaces were appropriate.
A smaller subset behaved differently. Across related document mutators, the same parameter shapes recurred: language mutations repeatedly carried the same language and provenance concepts; alt-text mutations repeatedly carried description and attribution state. Looking across those instances revealed something that no individual finding established on its own. The repeated primitives were not merely similar code. They were recurring expressions of domain concepts that the implementation had never named.
Repetition alone is not enough to make that inference. The finding must be interpreted in its architectural context. A primitive-heavy external protocol adapter is different from primitive-heavy internal domain code: the former may be faithfully representing an external interface, while the latter may be forcing every consumer to reconstruct a concept the system already understands. The same distinction applies more generally. A recurring structure may be legitimate shape, mechanical debt, or evidence of a latent concept. The useful question is therefore not simply does this pattern repeat? but what explains the repetition, and would naming the shared meaning change future reasoning?
This gives a practical route from weak implementation signals to explicit models. Surface repeated structure; partition findings by architectural role and likely cause; compare related instances for shared meaning; name a concept only when that meaning earns a representation; then migrate consumers and enforce whatever narrower relationships the new model makes decidable. Figure 4.2-3 summarizes that process. The schematic is intentionally simpler than the judgment that produces it: detection narrows the search space, while engineering interpretation decides whether there is a model to recover.
Field record — Primitive-density migration
The primitive-density backlog fell from 698 file-level findings on June 8 to 472 on June 9 and 299 on June 10. The declining count is not the important result. What matters is that the remaining population was repeatedly reclassified as it shrank:
- June 8 — 698 findings, partitioned into cluster-uniform, mechanical, per-site-judgment, boundary, and test-fixture-or-exempt buckets.
- June 9 — 472 findings.
- June 10 — 299 findings, dispositioned as annotate, exempt, extract-a-model, redesign, retire, or defer-for-judgment.
Some findings disappeared through mechanical work, some exposed missing shared types, some warranted exemptions or lint changes, and some required design judgment. The chronology records those observations; it makes no claim that a single planned wave caused each step of the decline.
PROBLEM SOLVINGInset — Rotate the problem
When a problem is difficult, try looking at it from another angle. George Pólya made this a basic strategy of problem solving: draw a figure, introduce different notation, consider a related problem, work backward, or restate the problem in another form 33. George Pólya, How to Solve It: A New Aspect of Mathematical Method, 2nd ed. (Princeton University Press, 1957).. These moves do not change the underlying problem. They change the representation in which you are trying to solve it. In engineering, the same move can turn an awkward collection of conditions into a state machine, a tangle of calls into a graph, or a complicated sequence of events into a lifecycle.
Metaphor and analogy provide another way to rotate the problem. They let us understand an unfamiliar system using relationships we already understand elsewhere. Lakoff and Johnson argue in Metaphors We Live By that metaphor is not merely decorative language: it shapes what we notice and how we reason 44. George Lakoff and Mark Johnson, Metaphors We Live by (University of Chicago Press, 1980).. This is useful for modeling because a good analogy can suggest a useful representation. But every representation emphasizes some relationships and suppresses others. Calling a system a pipeline makes stages and flow easy to see, while directing attention away from other aspects of the same system.
The goal, then, is not to discover the one correct representation. Different representations can make different aspects of the same system easier to reason about. Rotate the problem and ask what becomes visible: a graph may expose reachability, a state machine may expose legal transitions, and a lifecycle model may expose temporal obligations. Keep the representations that make consequential engineering questions easier to answer, and use more than one when the questions demand it. This is why Part II develops several model classes rather than prescribing a single universal model.
4.2.3 Reconcile the Map, Then Promote Obligations
Begin with audit. Join the representation to the implementation and surface disagreement without blocking work. A legacy map is expected to drift; making every inherited claim binding before reconciling it would merely enforce old errors. Repair disagreements through ordinary feature and maintenance work without assuming in advance that prose or code is correct: the representation may be stale, the implementation may be wrong, or the representation may be asking the question at the wrong grain. Promote selected obligations only after the representation is trustworthy enough for the consumer that will rely on it. Add structure when retrieval, analysis, generation, validation, measurement, or gating will use it; do not enrich a model merely because more structure can be represented. The companion From-Drifted-Wiki-to-Trusted-Model operator card holds the drill whole.
To make the shape concrete, suppose an inherited wiki describes the system but has drifted from the code, so agents and engineers repeatedly re-derive what is actually true from source. Audit the map against the implementation and reconcile disagreements through ordinary feature and maintenance work: sometimes the prose is stale; sometimes the code is wrong. Promote only claims trustworthy enough for the consumer that will rely on them. The result is a queryable model later work can use, while unresolved claims remain advisory rather than acquiring unearned enforcement.
4.2.4 Migrate One Bounded Surface at a Time
The immediate goal is not a complete model of the inherited system. It is a trusted map over the surface that matters now: important claims have known anchors, important implementation regions have explanatory homes, and agents can navigate between them without repeatedly reconstructing the relationship. Build only as much further representation and evidence as the quality case the system must defend requires — enough structural, behavioral, ownership, measurement, and traceability information to answer the properties you mean to stand behind. A live system rarely tolerates wholesale migration, so choose a bounded surface — a subsystem, service, policy family, or recurring workflow — and let old and new coexist while the replacement earns trust. Preserve reversibility, and generalize only what the bounded migration teaches you.
DocAble's serverless re-platforming ran this shape — a stateful job pipeline moved off long-lived polling workers onto instances that scale to zero behind a managed push queue; the push plane grew beside the poll plane behind a default-off toggle, proved green on a staging namespace running identical code, took the traffic, then the old cluster was deleted and preserved on an archive branch.
Within that slice, recover the representation using whichever direction the evidence supports. Top-down work starts from intended architecture or requirements and refines toward implementation. Bottom-up work induces stable abstractions from the code and rises toward a model. Removing accidental complexity — under tests — first can make either direction easier. The directions should meet at the grain where the relevant property becomes answerable.
A disagreement then has the familiar three-way diagnosis — the representation is wrong, the grain is wrong, or the implementation is wrong. Do not decide which in advance; shifting a legacy codebase from "the tests pass" to "these properties hold across all behaviors" surfaces disagreements by design.
SOFTWARE ENGINEERINGInset — When the model and the code disagree
Tighten a model against real code and it will, sooner or later, contradict the code. The disagreement usually points to one of three questions:
- Is the model wrong? It may claim something the code never promised. Refine the model.
- Is the model at the wrong grain? It may be asking a question at a level of abstraction that cannot see the answer. Build a different model at the grain the property lives at.
- Is the implementation wrong? The model may be right, the code disagrees, and the disagreement may expose an implementation defect.
The discipline is to decide which before you act. Fixing code when the model was wrong bakes in a false claim; refining the model when the code had a bug hides the bug behind an adjusted spec.
For consequential substrate changes, represent important dependencies strongly enough to query the migration blast radius before cutover; the control↔substrate dependency model gives the operator pattern.
4.2.5 Audit → Drain → Promote
A valid future invariant is not always a valid present admission rule. A legacy system may violate a worthwhile new rule everywhere on the day you introduce it. Making the rule blocking immediately does not improve the system; it simply stops existing work. Introduce the obligation in three beats: Audit, Drain, Promote.
The move — Audit → Drain → Promote
- Audit. Install the proposed rule as evidence only. It reports every detected violation and blocks no commit, so it never breaks an in-flight agent.
- Drain. A fix wave repairs the existing findings under sufficient tests and other evidence to preserve intended behavior, converting the legacy code to the new convention behavior-for-behavior.
- Promote. Once the governed surface satisfies the obligation, enforce it at the boundary so detected violations cannot re-enter.
Cloudflare's public account describes a similar approved → enforced sequence, landing each policy control advisory and flipping it to enforced once the tree is clean, so the promotion never breaks work in flight 55. Timo Reimann, “How Cloudflare Enforces Engineering Standards Using Ai,” Cloudflare, August 4, 2026, https://blog.cloudflare.com/engineering-standards-enforcement/.. Figure 4.2-4 draws the three beats as one lint is worn into a legacy tree.
The final step requires care. DocAble did not promote primitive density itself into a universal blocking rule. The detector was a smell: useful for locating work, but too broad to define correctness. Once the findings had been understood, narrower mechanisms could prevent the specific regressions that mattered. Sometimes you promote the obligation, not the instrument that discovered it. An audit may reveal an obligation that deserves enforcement while not itself being the right mechanism to provide it; the detector can remain advisory while a narrower type, constraint, validator, or gate enforces the obligation.
4.2.6 Derive, Don't Copy
Recovering a model is only the first step. The next question is what happens to the facts it owns. A common failure is to declare one representation the source of truth while continuing to copy its facts elsewhere: ownership appears in the model and again in configuration; an architectural edge appears in the graph and again in an allowlist; a requirement relation appears in the model and again as a string in a test. Each copy creates another place that can drift. If a fact already has a queryable source of truth, derive it rather than copying it. Prefer a join over parallel lists, a stable identifier over a copied path, and generation over synchronized hand-editing when one representation can honestly own the result. Sometimes neither side should own the other; in that case, make their correspondence observable and check agreement rather than silently declaring either the model or the implementation authoritative.
Figure 4.2-5 draws the shape: once a fact has a source of truth, downstream consumers query, join, derive, or generate from it, and where neither fully determines the other, a correspondence check makes disagreement visible.
Hidden assumptions deserve the same treatment as copied facts. A control that depends on a particular runtime, directory layout, deployment topology, tool version, or model capability carries that dependency whether or not anyone wrote it down. When changing the substrate could invalidate the control, represent the dependency strongly enough that its blast radius can be queried before the change — the blast-radius move above is exactly this, worked through on a real re-platforming. Do not model every dependency. Model the ones whose rediscovery by breakage is expensive. Make consequential assumptions queryable before they become surprises.
4.2.7 Price the Investment
A recurring gap does not automatically deserve machinery. Price the expected future loss against the cost of building and carrying the response. Frequency and consequence are useful first approximations; detectability, reversibility, legal exposure, and the stability of the obligation can move the decision substantially. Cheap, rare failures often remain judgment. Cheap, frequent failures may justify a lint, script, or reusable procedure, because repeated agent and human attention is itself cost. Consequential failures justify a larger investment and a stronger assurance response: better representation, prevention by construction where possible, stronger sensing and validation, and enforcement at an appropriate boundary. Catastrophic or legally intolerable failures need not recur even once to earn that investment.
Table 4.2-1 crosses how much a failure costs against how often it happens; it gives a first-pass heuristic, not a decision rule. Do not build the larger mechanism until the expected cost of the failure justifies it.
| Cost × frequency | Rare failure | Frequent failure |
|---|---|---|
| Cheap | Judgment. | A lint, script, or reusable procedure. |
| Costly | Recovery with admission control. | Structural prevention with admission control. |
Price the upkeep as well as the construction. Models drift, validators require calibration, and skills age. Engineering capital depreciates: a control that once retired meaningful cost becomes overhead when the obligation disappears or the upkeep exceeds the return. Build the smallest asset that retires the recurring cost; retire it when the return disappears. Fleet-scale migration amplifies the same economics: Spotify reports a migration workflow in which work that previously involved hundreds of teams over weeks could be scoped by one engineer over days, with tooling targeting and scheduling concurrent agent work 66. Max Charas and Marc Bruggmann, “Honk: Autonomous Code Migration at Spotify,” Spotify Engineering, 2026, https://engineering.atspotify.com/..
Worked Examples
DocAble. A fast-built prototype was matured in place as domain models, typed seams, and controls were introduced incrementally — a roughly 300,000-line codebase reduced to roughly 200,000 production lines, lint by lint and model by model. Part 5 (The Evidence) reconstructs the migration.
Takeaway. Start from the system you own. Recover useful structure, reconcile it to reality, and invest where stronger representation or enforcement repays its cost.
Works Cited
- Lehman, Meir M., and L. A. Belady. Program Evolution: Processes of Software Change. Academic Press, 1985.
- Red Hat. “Why Developer Portals Matter More in the Age of AI Agents.” Red Hat, 2026. https://www.redhat.com/en/blog/why-developer-portals-matter-more-age-ai-agents.
- Pólya, George. How to Solve It: A New Aspect of Mathematical Method. 2nd ed. Princeton University Press, 1957.
- Lakoff, George, and Mark Johnson. Metaphors We Live by. University of Chicago Press, 1980.
- Reimann, Timo. “How Cloudflare Enforces Engineering Standards Using Ai.” Cloudflare, August 4, 2026. https://blog.cloudflare.com/engineering-standards-enforcement/.
- Charas, Max, and Marc Bruggmann. “Honk: Autonomous Code Migration at Spotify.” Spotify Engineering, 2026. https://engineering.atspotify.com/.