Cloud Modernization Patterns Module 5 · Modernize With AI

AI-Assisted Porting at Scale

Last reviewed

Advanced

What you'll learn

~20 min
  • Build the characterization-test harness before the first line of code moves
  • Run an agent-executed port through atomic task packs with human verification gates
  • Decide what humans review deeply versus what the harness reviews for them

Revisiting the port, honestly

Lesson 2.2 waved the port through in one line — “assume that work is done” — and moved on to packaging. This lesson is that omitted work — because in 2026 the port is where AI-assisted modernization either proves itself or quietly corrupts fifteen years of business rules. The method has three legs: a harness that defines correct, an agent that does the mechanical work, and gates where humans spend their attention where it counts.

Leg 1: characterization tests define “correct” before anything moves

AssetTrack has no test suite (Lesson 1.2, weakness #3). Before porting, you do not write the tests you wish it had — you write tests that pin down what it currently does, bugs and all:

Build a characterization harness for the nightly batch jobs. For each job:
- Run it against the golden input set (last quarter's real inputs, sanitized)
- Capture every output: files, DB writes, log lines with timestamps normalized
- Store as golden outputs. The assertion is byte-equivalence (or field-level
equivalence where timestamps/sequence values legitimately differ - list each
exception explicitly and why)
Do NOT fix anything you find. If a job rounds currency oddly, the golden
output preserves the odd rounding. Behavior preservation is the contract;
improving behavior is a separate, later decision.

That last instruction is the discipline that makes the whole method safe. A port that “fixes” behavior mid-flight has changed two things at once, and when the numbers differ you cannot say which change caused it. Port first, verify equivalence, then queue improvements as ordinary tracked work against a system you once again understand.

Leg 2: the agent executes, in task-pack units

Lesson 1.4’s atomic task packs were designed for this exact executor. The port decomposes into packs — one service, one namespace, one batch job at a time — each with declared file scope, its characterization tests named as the done-check, and dependencies ordered so parallel agents never collide:

Execute task pack P3-07: port the MeterReadingImport job to .NET 10.
Scope: src/Jobs/MeterReadingImport/** only. Out of scope: shared utilities
(P3-02, already merged), the scheduler wiring (P3-14, later).
Method: preserve behavior exactly. Where a Framework API has no direct .NET 10
equivalent, choose the closest match and RECORD the substitution in the pack's
notes - do not silently improvise.
Done: characterization suite for this job passes byte-equivalent; build clean;
no new warnings suppressed.

The recorded-substitution rule matters more than it looks: the API seams (AppDomain behavior, culture-sensitive string handling, binary serialization, System.Web remnants) are exactly where silent behavior drift hides. Forcing each substitution into the pack notes turns “mysterious rounding difference in October” into “P3-07 note 4, reviewed on merge.”

Leg 3: humans verify where verification pays

At agent speed, “a human reviews every line” is a pleasant fiction that decays into “a human scrolls every diff.” Spend attention deliberately instead:

LayerWho reviewsWhat they look at
Behavior equivalenceThe harnessGolden outputs, byte-level — machines are better at this than people
API substitutionsHuman, alwaysEvery recorded substitution in the pack notes — this is where drift lives
Auth, money, and data-write pathsHuman, line-by-lineLesson 4.1’s controls: these paths get full review regardless of volume
Everything elseSampledSpot-check a pack per batch; escalate to full review if a sample fails

The harness carries the equivalence burden precisely so human attention can concentrate on the three rows machines cannot judge: whether a substitution is semantically safe, whether an authorization path is intact, and whether the sampled work smells right.

💬The port is now the cheap part

Run this way, the mechanical port of a mid-size monolith compresses from quarters to weeks — that part of the 2025-era enthusiasm held up. What did not compress: building the golden input set, negotiating which output differences are “legitimate,” and the accreditation clock (Lesson 6.4). Plan the calendar around those, and let the agents eat the part that used to eat the team.

KNOWLEDGE CHECK

Mid-port, the agent reports: 'The asset-name sort order in exported reports differs -- .NET 10 uses ICU string comparison where Framework used NLS on Windows, so names with punctuation now sort differently. I kept the new order since it is more standards-compliant.' The characterization suite now fails on row ordering. What is the right response?

Key takeaway

Characterization tests define correct before anything moves; agents execute the port in task packs that record every API substitution; and human review concentrates where machines cannot judge — substitutions, auth, money, and samples. Behavior preservation first, improvements after, and the calendar planned around the parts that did not compress.

Search lessons