/modernize-uplift migrates one representative project end-to-end and writes its lessons to analysis/<system>/PLAYBOOK.md before touching the rest. The remaining projects then fan out through a new uplift-migrate workflow, one uplift-migrator agent per project, in dependency-aware escalating batches behind a per-batch circuit breaker. A recorded per-test baseline (analysis/<system>/BASELINE.md) gates the migration, and the delta catalog reports a test framework whose runner does not support the target as its own highest-blast-radius dependency. The three execution commands (uplift, transform, reimagine) read MODERNIZATION_BRIEF.md and treat their phase's scope and entry and exit criteria as gates, so editing the brief steers execution. For a same-stack uplift the brief requires the delta catalog and applies the same ordering overrides the execution command does. /modernize-preflight opens with a short interview (scope, local build and test, bespoke build infrastructure, prior attempts, what is off limits) without blocking on the answers, reads the CI/build definition for how the system builds, escalates the smoke test to a whole-project restore and build, and adds a scope-boundary check that enumerates inbound and outbound dependencies when the system directory is a slice of a larger repository. Workflow scripts accept args delivered as either a JSON string or an object.
5.7 KiB
| description | argument-hint |
|---|---|
| Transform one legacy module to the target stack — idiomatic rewrite with behavior-equivalence tests | <system-dir> <module> <target-stack> |
Transform legacy/$1 module $2 into $3, with proof of behavioral
equivalence.
This is a surgical, single-module transformation — one vertical slice of the
strangler fig. Output goes to modernized/$1/$2/.
Step 0a — Toolchain check (fail fast on target, adapt on legacy)
Verify the build environment before planning, not when the tests first run:
- Target stack ($3) — required. Runtime, package manager, and test
framework all respond (
java -version+mvn -v,node -v+npm -v,python3 -V+pytest --version, …). If any are missing, stop and report what to install — the new code and its tests cannot run without them, so a plan gate now would just defer the failure an hour. Suggest/modernize-preflight $1 $3for the full readiness report. - Legacy stack — advisory, never a blocker. Try a syntax-only compile
of the module being transformed (e.g.
cobc -fsyntax-only). Legacy code often cannot build locally by nature, not by misconfiguration — CICS/IMS programs have no local translator, and the real runtime may be a mainframe you don't have. A failed or impossible legacy compile does not stop the transform; it changes the equivalence strategy:- dual-execution proof is off the table — characterization tests assert against recorded traces / golden-master fixtures (real production outputs, captured reports/screens, SME-confirmed examples) instead of live legacy runs
- say so explicitly in the Step 0b plan and later in TRANSFORMATION_NOTES.md ("equivalence is trace-based; legacy was not executable in this environment"), so reviewers know the strength of the proof they're approving
Step 0b — Plan (HITL gate)
The brief is binding — read it first. If analysis/$1/MODERNIZATION_BRIEF.md
exists, this transform is one phase (or one module of a phase) of that plan:
read it before deciding anything below. Find the phase that names this
command with $2 in scope, and treat that phase's scope, entry criteria,
exit criteria, and any edits the user made to it as binding on the plan
you present below. Entry criteria are gates, not context: if one is not
met (a prior phase's exit criteria, an SME sign-off the brief requires),
meeting it is the next step — do not proceed past it and do not silently
re-plan around it. If the brief exists but no phase covers $2, stop and
ask which phase this is. The user steers execution by editing the brief; a
brief the execution command never reads cannot steer anything.
Read the source module and any business rules in analysis/$1/BUSINESS_RULES.md
that reference it. Then present the plan and stop — write no code until
the user explicitly approves (use plan mode if the session supports it):
- Which source files are in scope
- The target module structure (packages/classes/files you'll create)
- Which business rules / behaviors this module implements
- How you'll prove equivalence (test strategy)
- Anything ambiguous that needs a human decision NOW
Wait for approval before writing any code.
Step 1 — Characterization tests FIRST
Before writing target code, spawn the test-engineer subagent:
"Write characterization tests for legacy/$1 module $2. Read the source,
identify every observable behavior, and encode each as a test case with
concrete input → expected output pairs derived from the legacy logic.
Target framework: <appropriate for $3>. Write to
modernized/$1/$2/src/test/. These tests define 'done' — the new code
must pass all of them. Follow your secret-handling rules: no credential
literal from legacy code becomes a fixture; substitute fake same-shape
values and read anything genuinely live from environment variables."
Show the user the test file. Get a 👍 before proceeding.
Step 2 — Idiomatic transformation
Write the target implementation in modernized/$1/$2/src/main/.
Critical: Write code a senior $3 engineer would write from the
specification, not from the legacy structure. Do NOT mirror COBOL paragraphs
as methods, do NOT preserve legacy variable names like WS-TEMP-AMT-X.
Use the target language's idioms: records/dataclasses, streams, dependency
injection, proper error types, etc.
Include: domain model, service logic, API surface (REST controller or equivalent), and configuration. Add concise Javadoc/docstrings linking each class back to the rule IDs it implements.
Step 3 — Prove it
Run the characterization tests:
cd modernized/$1/$2 && <appropriate test command for $3>
Show the output. If anything fails, fix and re-run until green.
Step 4 — Side-by-side review
Generate modernized/$1/$2/TRANSFORMATION_NOTES.md:
- Mapping table: legacy file:lines → target file:lines, per behavior
- Deliberate deviations from legacy behavior (with rationale)
- What was NOT migrated (dead code, unreachable branches) and why
- Follow-ups for the next module that depends on this one
Then show a visual diff of one representative behavior, legacy vs modern:
delta --side-by-side <(sed -n '<lines>p' legacy/$1/<file>) modernized/$1/$2/src/main/<file>
(Fall back to diff -y --width=160 if delta isn't installed.) Never
pick a credential-bearing line range for this diff, and mask any
credential-like literal quoted in TRANSFORMATION_NOTES.md — the notes
live in modernized/ and get committed.
Step 5 — Architecture review
Spawn the architecture-critic subagent to review the transformed code against $3 best practices. Apply any HIGH-severity feedback; list the rest in TRANSFORMATION_NOTES.md.
Report: tests passing, lines of legacy retired, location of artifacts.