Use case · Legacy modernisation

Rewrite the old system without losing what it knows.

Agents map every program, copybook and job step, turn buried logic into specifications business owners can sign, and generate tests from production-like inputs. Translation proceeds one module at a time, with old and new code running side by side until their outputs agree. Your engineers approve every merge.

For cIOs and heads of engineering at banks, insurers, public bodies and travel operators whose core processing still runs on COBOL, PL/I, RPG or unsupported Java and .NET.

Legacy logic, carried across intactLEGACY · COBOLPERFORM 2100-CALC-INTCOMPUTE WS-INT ROUNDED = WS-BAL * WS-RATEIF WS-DATE > 19991231 MOVE 'Y' TO WS-FLAGEND-IFMODERN · JAVAinterest = calcInterest( balance, rate, RoundingMode.HALF_UP)if (date.isAfter(Y2K)) flag = true;}Module translatedReplay both versionsDiff investigatedEngineer mergesold and new run side by side · outputs compared

Read the small print

Twelve lines that quietly hold a lending policy.

A generic interest paragraph of the kind found in most savings and loan systems. Every line carries a decision someone made long ago; a literal translation keeps the syntax and loses the meaning.

INTCALC.cbl, paragraph 2100-APPLY-RATEIllustrative excerpt; identifiers are invented
2100-APPLY-RATE.
IF WS-OPEN-DATE < 19980401
PERFORM 2150-LEGACY-TIER
ELSE
MOVE WS-STD-RATE TO WS-APPLIED-RATE
END-IF.
COMPUTE WS-DAILY-INT ROUNDED =
WS-BALANCE * WS-APPLIED-RATE / 365.
ADD WS-DAILY-INT TO WS-ACCRUED.
PERFORM 2900-WRITE-AUDIT.
* CHARACTERISATION: 19980331 / 19980401, 29 FEB, HALF-CENT TIE
* RULE R-114: SIGNED OFF BY PRODUCT OWNER

Where teams usually are

Three people understand the overnight run.

The core system still works. It posts interest or issues entitlements every night, as it has for decades. What has changed is the people around it: the authors of the tricky parts have left, and those who remain are cautious because they know what a small change can break.

So there is a change freeze in all but name. Product requests wait for a twice-yearly release window. When an auditor asks how a calculation works, the answer comes from reading source code aloud, because the specification predates the current team.

Earlier rewrites stalled because nobody could prove the new system matched the old one in every case.

Inside the migration

From copybook to merged pull request.

Each module passes through three stages, and none moves on until a person has reviewed the evidence.

Legacy logic, carried across intactLEGACY · COBOLPERFORM 2100-CALC-INTCOMPUTE WS-INT ROUNDED = WS-BAL * WS-RATEIF WS-DATE > 19991231 MOVE 'Y' TO WS-FLAGEND-IFMODERN · JAVAinterest = calcInterest( balance, rate, RoundingMode.HALF_UP)if (date.isAfter(Y2K)) flag = true;}Programs parsedCall graph builtRule extractedOwner signs specold and new run side by side · outputs compared

Conceptual flow, not a live system or measured result.

01

Map the estate and write down the rules

Agents parse programs, copybooks, JCL, scheduler definitions and schemas into a dependency graph: which job calls which program, which file feeds which report. For each module they draft a plain-language specification that cites the source lines behind every rule. Business owners and senior engineers correct those drafts and sign off the rules the new system must keep. Ambiguities become logged questions with an owner and a due date, never guesses by the agent.

Legacy logic, carried across intactLEGACY · COBOLPERFORM 2100-CALC-INTCOMPUTE WS-INT ROUNDED = WS-BAL * WS-RATEIF WS-DATE > 19991231 MOVE 'Y' TO WS-FLAGEND-IFMODERN · JAVAinterest = calcInterest( balance, rate, RoundingMode.HALF_UP)if (date.isAfter(Y2K)) flag = true;}Programs parsedCall graph builtRule extractedOwner signs specold and new run side by side · outputs compared
Programs parsedCall graph builtRule extractedOwner signs spec
02

Capture behaviour before touching it

The current system becomes the reference. Agents sample masked, production-like inputs, add boundary cases suggested by the extracted rules, and record what the legacy code produces today: files, database changes and side effects such as audit records. The result is a characterisation suite describing actual behaviour, quirks included. Engineers check it for coverage gaps, such as untested branches or missing year-end runs, before it becomes the acceptance test for new code.

Legacy logic, carried across intactLEGACY · COBOLPERFORM 2100-CALC-INTCOMPUTE WS-INT ROUNDED = WS-BAL * WS-RATEIF WS-DATE > 19991231 MOVE 'Y' TO WS-FLAGEND-IFMODERN · JAVAinterest = calcInterest( balance, rate, RoundingMode.HALF_UP)if (date.isAfter(Y2K)) flag = true;}Inputs sampledOld outputs recordedEdge cases addedBaseline frozenold and new run side by side · outputs compared
Inputs sampledOld outputs recordedEdge cases addedBaseline frozen
03

Translate, replay and compare

A code agent translates one module into idiomatic Java or your chosen target, making decimal types, rounding modes and record layouts explicit. Both versions process the same replayed transactions and outputs are compared field by field. A translation fault is fixed; an intended behaviour change needs written approval from the rule owner. Only when the diff is empty or fully explained does an engineer review the pull request, read the translated code for maintainability and merge it.

Legacy logic, carried across intactLEGACY · COBOLPERFORM 2100-CALC-INTCOMPUTE WS-INT ROUNDED = WS-BAL * WS-RATEIF WS-DATE > 19991231 MOVE 'Y' TO WS-FLAGEND-IFMODERN · JAVAinterest = calcInterest( balance, rate, RoundingMode.HALF_UP)if (date.isAfter(Y2K)) flag = true;}Module translatedReplay both versionsDiff investigatedEngineer mergesold and new run side by side · outputs compared
Module translatedReplay both versionsDiff investigatedEngineer merges

Sequencing

Four gates between the old platform and the new one.

Cut-over follows the strangler pattern: traffic moves a slice at a time, and the legacy path stays available until each slice earns its retirement.

  1. Phase 1

    Map and specify

    Graph dependencies for the agreed scope and draft specifications for its rules.

    Move on when

    Everything in scope is mapped; the first slice's rules carry a named owner's sign-off.

  2. Phase 2

    Build the test harness

    Create characterisation tests and a replay environment using masked data.

    Move on when

    The harness reproduces current outputs reliably and engineers accept its coverage.

  3. Phase 3

    Translate and run in parallel

    Translate the slice and run it beside the legacy code on replayed, then shadow, traffic.

    Move on when

    Outputs match over an agreed period and every difference has an approved explanation.

  4. Phase 4

    Cut over incrementally

    Switch live traffic for the slice to the new service, keeping the legacy path warm for rollback.

    Move on when

    The slice survives a full business cycle, month-end included, before legacy code is retired.

What can go wrong

Five failure modes planned for from the first week.

Risk

Behaviour drifts in rare cases sampled data never exercises.

Mitigation

Rule-derived boundary cases supplement sampled inputs, and shadow running spans period-end processing.

Risk

Decimal arithmetic differs between packed decimal and the target language.

Mitigation

Every monetary field declares scale and rounding mode, floating point is banned from calculation paths, and comparisons are exact.

Risk

Hidden batch dependencies surface after cut-over.

Mitigation

The map covers scheduler definitions, datasets and downstream file consumers, confirmed by each slice's owners before traffic moves.

Risk

Unclear licence or ownership of generated code.

Mitigation

Contracts assign generated code to you, provider terms are checked to match, and licence scanning runs before merge.

Risk

Knowledge leaves with the people who held it.

Mitigation

Senior engineers review and sign the specifications, so what they know lives on in documents and tests.

Evidence of progress

Measures that show equivalence, not activity.

01Equivalence pass rate
Replayed transactions whose outputs match the legacy system field for field, or differ by an approved exception.
The primary proof that behaviour survived translation.
02Business rules signed off
Extracted rules approved by a named owner, against all rules identified in scope.
An unapproved rule is an unverified assumption.
03Modules cut over
Modules serving live traffic with their legacy path retired.
Separates real migration from code not yet trusted.
04Defect escape rate
Behavioural defects found in production after cut-over, per slice.
Tests whether the harness catches what matters.
05Run-cost delta
Change in infrastructure, licence and support cost once legacy components are switched off.
Savings appear only when the old platform stops doing the work.

Say no early

Cases where translating the old code is the wrong move.

  • The system is stable, affordable and still understood by an adequately staffed team. Migration may cost more than the risk it removes.
  • A packaged product covers the process and you will adopt its way of working. Replace rather than translate when the old rules are not a differentiator.
  • No realistic test environment or masked data can be provided. Without replay, equivalence cannot be shown.
  • The mandate is a single weekend cut-over on a fixed date. We only run incremental migrations with rollback.

Questions from architects and CIOs

What engineering leaders ask before committing.

Why not run a code converter over the whole estate?

Converters tend to produce Java that reads like COBOL and carries every quirk forward unexplained. We use agents to understand the code, document its rules and build tests first, then translate into maintainable code. Conversion tooling can still handle mechanical steps such as copybook-to-class mapping.

Do engineers review everything the agents write?

Yes. Rule owners and senior engineers review specifications, test suites are checked for coverage, and every translated module arrives as a pull request a named engineer approves. Agents read, draft and compare at scale; merge rights stay with your team.

Can it handle PL/I, RPG, Assembler or older .NET?

The method is language-agnostic: map, specify, characterise, translate, compare. Support for a given dialect or framework version is tested on a sample of your code during mapping. Assembler and macro-heavy code usually need more human analysis, and we will tell you so.

Does our source code leave our environment?

It need not. Agents can run in your cloud tenancy or on-premises, using model endpoints that meet your data terms. Replay data is masked before use, generated artefacts stay in your repositories, and access to source code follows your existing permissions, approvals and logging.

What happens when new and old code disagree?

Each difference is classified. A translation error is fixed and replayed. If the legacy behaviour is a defect you want corrected, the rule owner approves the change in writing and the baseline is updated with a recorded reason. Unexplained differences block the merge.

How long does a migration take?

That depends on estate size, test data access and how many rules prove ambiguous. Mapping produces an evidence-based plan for the remaining slices, so estimates come from your code, not a template. We do not commit to an end date before that work is done.

Go deeper

The pieces behind this workflow.

02Your starting point

What would you like to move forward?

Start with the outcome that feels closest. We'll help give the next step a useful shape.

04Let's find your next move

One conversation. A clearer direction.

Tell us what you want to improve. A few sentences are enough to start.

shayan@coldai.org

Last reviewed 25 September 2026.