Migration strategy

Lift-and-shift vs. verified migration: why "it runs" isn't "it's right"

Every mainframe modernization program runs on a deadline. The hardware is end-of-life, the people who understood the system are retiring, the maintenance contract is a line item nobody wants to renew. So the pressure is to move fast: lift the workloads, shift them to the new platform, prove the jobs run, and declare victory. Speed is a legitimate goal. The problem is what speed hides — because the fastest path to "done" measures the easiest thing to measure, which is execution, and quietly skips the hardest thing to measure, which is correctness.

A lift-and-shift gives you a green pipeline. The data extracts, the converter runs, the target system loads, the smoke tests pass. That is real signal — it tells you the plumbing is connected. It tells you nothing about whether the values that came out the far end are the values that went in.

Three things a passing pipeline does not prove

Structure parses is not values correct. A converter can walk a copybook, honor every field offset, and emit perfectly well-formed records — and still have decoded the contents wrong. Parsing proves the layout was understood. It says nothing about whether the bytes inside each field were interpreted faithfully. A record that is structurally flawless and numerically corrupt looks identical to a correct one until someone does the arithmetic.

Types valid is not values faithful. A schema check confirms that a field holds the kind of thing it should. It does not confirm the thing is right. A COMP-3 packed decimal that gets read as a string is still, technically, "a value" — it is a non-null token that satisfies a string column. The migration reports success. The premium amount is now five bytes of garbled BCD pretending to be text, and every downstream calculation built on it inherits the error. Type validity is a floor, not a guarantee.

Loaded is not reconciled. Row counts matching between source and target is the comfort metric everyone reaches for, and it is nearly worthless on its own. The same number of records can arrive with their REDEFINES resolved to the wrong view, their sign nibbles dropped, their implied decimals shifted. Everything loaded. Nothing reconciled. A count tells you the records made the trip; it does not tell you they arrived intact.

Where verification belongs

If the risk lives at the moment bytes are reinterpreted, then verification has to live there too — at the conversion boundary, not bolted on weeks later in user acceptance testing. By the time a bad value surfaces in a report, it has already propagated through indexes, derived fields, and downstream feeds, and you are doing forensics instead of validation.

The second requirement is harder to swallow and more important: verification has to be performed independently of the converter. The systems integrator that wrote the migration cannot also be the party that grades it. Not because anyone is dishonest, but because a converter and a self-check built by the same team share the same blind spots — they encode the same assumptions about that ambiguous REDEFINES, the same handling of the sign nibble, the same reading of the controlling count on a variable-length array. A check that inherits the converter's misunderstanding will cheerfully confirm the converter's mistake. Grading and doing have to be separate hands. This is the same reason the silent failure modes in a conversion are so dangerous: they are invisible precisely to the tooling that produced them.

What "verified migration" adds over QA sampling

The standard answer to data quality is sampling: pull a few thousand records, eyeball them or run them through a reconciliation script, extrapolate. Sampling is a probabilistic bet. It catches systematic, high-frequency errors and misses exactly the kind of defect mainframe data is full of — the rare clause, the one policy with eight coverages instead of one, the single field whose REDEFINES only flips under a condition that appears in 0.2% of records. The corner cases that sampling is statistically designed to skip are the corner cases that cost the most.

A verified migration replaces the bet with proof on two axes. First, 100% field coverage: every field on every record is checked, not a sample of rows. Second, a byte-identical round-trip: decode the migrated representation back into the original record format and compare bytes. If sha256(re-encoded) == sha256(original), every packed decimal, every sign nibble, every array boundary was decoded correctly — because a single wrong bit anywhere breaks the hash. There is no sampling error in a hash. It either matches the whole record or it does not. That is the difference between "we checked some and they looked fine" and "every field is provably preserved."

Done versus proven

The honest reframing is this: a lift-and-shift can tell you a migration is done. Only verification can tell you it is proven. Those are different claims, and the gap between them is exactly where regulatory findings, failed reconciliations, and silent corruption live. "It runs" is a statement about the pipeline. "It's right" is a statement about the data, and it requires evidence the pipeline cannot produce about itself.

The artifact that closes the gap is a signed parity receipt — an independent, deterministic record that the migrated data round-trips to the source, field for field, with a cryptographic guarantee anyone can re-verify. Not a status email saying the job exited zero, but a portable proof you can hand to an auditor. The full structure of that proof is in the Parity Receipt spec. The point is the shift in standard: stop accepting "it runs" as the finish line, and start requiring "it's right, here is the receipt."

See it on a real record

IronParse verifies a migration independently of the converter and signs a parity receipt. Generate one against a sample ACORD record, or read the spec.

Live parity receipt → The spec
← All insights