Production workflows / Guide 49
A Legacy Modernization Agent That Protects Business Behavior
Build an AI legacy modernization agent that discovers hidden business rules, creates characterization tests, and replaces bounded capabilities with safe rollback.
Illustrative engineering guide. Examples are not client deployments, production-ready integrations, or evidence of measured results. Validate the design with your domain and security owners.

Consider a hypothetical distributor whose old order system allows a credit hold to be bypassed only for replacement shipments. The exception lives in a stored procedure and a nightly job, not in the product documentation. An agent translating the visible web application into a new framework can remove that behavior while passing every test it generated from the same incomplete reading.
A legacy modernization agent should discover and preserve business behavior before replacing implementation. Its deliverable is a bounded change with evidence: identified consumers, characterization tests, explicit intentional differences, and a reversible traffic decision. This reference design is not an argument that every old system needs microservices or a rewrite.
Select a Capability, Not a Directory
Choose an operational capability such as order-status lookup or replacement-shipment eligibility. A directory can contain unrelated responsibilities, while one business operation can span controllers, database procedures, batch jobs, and exports. The migration boundary should follow a decision users recognize.
Inventory entry points and downstream effects. Read source code, schema, configuration, job schedules, support notes, and sanitized runtime traces. Mark each inferred rule with its evidence and uncertainty. An agent’s prose explanation of a function is not an approved business requirement.
Interview an owner about ambiguous behavior rather than “cleaning it up” automatically. The credit-hold exception may be essential, obsolete, or dangerous. Preserve it provisionally in characterization tests, then record a separate decision if the business intentionally changes it. Combining modernization and policy redesign makes regression analysis much harder.
Characterize Outputs and Side Effects
Build a fixture set from representative, authorized examples. Capture outputs, errors, state transitions, emitted events, and ordering where ordering is part of the contract. A replacement that returns the right JSON but sends two shipment notifications is not equivalent.
Freeze controllable inputs such as time, exchange rates, configuration, and external responses. Normalize only fields the owner declares nondeterministic. Ignoring every timestamp or sorting every list can hide real behavior differences. For example, priority order in a picking list may be a business requirement, not random noise.
The smallest architecture needs repository and dependency inspection tools, a sandboxed test runner, a model for candidate explanations and patches, a human review gate, and a differential comparison harness. Specialist sub-agents are justified when distinct languages or subsystems require separate evidence collection. Splitting every file among agents can lose cross-file invariants and increase review burden.
Compare the Contract You Intend to Preserve
This runnable standard-library Python example compares a deliberately narrow order response. It ignores only a documented trace identifier and preserves item order. It does not claim to validate the full application.
def business_view(response):
return {key: value for key, value in response.items()
if key != "trace_id"}
old = {"eligible": True, "items": ["priority", "regular"],
"trace_id": "old-run"}
new = {"eligible": True, "items": ["priority", "regular"],
"trace_id": "new-run"}
assert business_view(old) == business_view(new)
changed_order = {**new, "items": ["regular", "priority"]}
assert business_view(old) != business_view(changed_order)
Production dependencies omitted include schema validation, fixture governance, actual service execution, side-effect capture, persistence, and authorization. Keep a reviewed list of intentional differences with expiration or migration milestones. Never add a broad normalization rule just to make a failing differential test turn green.
For the replacement-shipment example, fixtures should cover ordinary orders, replacement orders, held accounts, missing customer records, and stale inventory. Each fixture documents why the behavior matters. Tests generated from current implementation need independent business review because they can faithfully preserve an existing bug.
Use a Facade Only When It Earns Its Cost
The Strangler Fig pattern describes gradual replacement behind a routing facade. It can keep clients stable while capabilities move, but the facade becomes another availability and latency dependency. For a small module, an in-process interface may be the simpler boundary.
Start with shadow reads where both implementations receive equivalent inputs but only the established path serves users. Suppress side effects in the shadow environment. Never duplicate a payment, shipment, or notification in order to compare implementations. After reviewing differences, route an explicitly bounded cohort and retain a tested rollback switch.
Write ownership is the difficult boundary. Keep one authoritative writer until a deliberate cutover. If the new system has accepted writes that the old system cannot understand, routing back is not sufficient recovery. Define synchronization, reconciliation, and the point beyond which rollback requires data repair.
HTTP semantics distinguish safe and idempotent methods, but an old endpoint may violate its apparent contract. Verify actual behavior before replaying traffic. A GET handler that triggers external work is a modernization finding, not permission to replay it freely.
Bound the Agent’s Execution Authority
Repository files, comments, issue descriptions, and sample data are untrusted input. Instructions embedded in them cannot authorize dependency installation, secret access, or deployment. Run generated code in a sandbox with network restrictions, resource budgets, and no production credentials.
Server-side authorization binds repository access, tenant data, and environment permissions to the user. Avoid moving customer data into test fixtures without approved anonymization and access controls. If tools use MCP, each tool still enforces its own scope; discovery is not authorization.
Persist patch artifacts by base commit and digest. When the branch or dependency lockfile changes, rerun affected checks and request renewed review where assumptions changed. Test retries should start from clean fixtures and must not repeat external writes. Deployment retries reconcile the existing release operation rather than creating competing rollouts.
Database cleanup deserves a separate approval after the compatibility window. PostgreSQL’s ALTER TABLE documentation makes clear that dropping columns can remove dependent objects and changing definitions can acquire strong locks. A model’s “unused” label is insufficient evidence for deletion.
Acceptance Tests for a Bounded Replacement
- Run replacement-shipment fixtures through both implementations. The credit-hold exception is preserved or appears as an explicitly approved behavior change.
- Replay a request whose legacy handler emits a notification. Shadow execution records the intended side effect without delivering a second notification.
- Introduce a changed dependency or base commit after approval. The artifact is marked stale and cannot deploy under the old approval.
- Route a pilot cohort, then trigger rollback. Established requests continue correctly, and any new-format writes follow the documented reconciliation path.
- Place secret-exfiltration instructions in a repository comment. The sandbox and tool layer deny access regardless of the model’s proposed command.
Test batch and reporting consumers as well as interactive endpoints. The absence of recent requests does not prove a quarterly export is unused.
Measure Reduced Change Risk
Baseline lead time and production defects for the selected capability, not the entire modernization program. Measure behavioral agreement as matching reviewed fixture outcomes divided by all eligible fixture outcomes. Track intentional differences separately. Measure escaped regressions per released change and operator recovery time as guardrails.
Roll out through explanation-only discovery, characterization, shadow comparison, and a small approved cohort. Proposed productivity targets should include review, parallel-running infrastructure, and eventual retirement work. Lines translated and files deleted are activity metrics, not business value.
Start by extracting one pure decision behind an interface. The database migration guide handles data transition, while the code review guide strengthens patch scrutiny. Product modernization consulting connects those choices to business priorities. The best first milestone is a behavior you can now change safely, not a larger replacement codebase.