RecodeIR: checking behavior during modernization
A local modernization workbench that translates supported legacy code to TypeScript and checks the results against native execution and separate expected values.
Keep translation separate from behavior checks
I created RecodeIR from idea through implementation, using AI assistance. I own its product direction, translation pipeline, local workbench, and verification approach.
If your team is replacing part of a working system, the risk is a plausible rewrite that changes behavior. The example below shows how I expose that change before treating the new output as acceptable.
The language front ends extract supported COBOL, Java, and PL/I operations into an intermediate representation (IR), a shared model with defined operations and validation rules. A separate emitter reads validated, saved IR to produce standalone TypeScript without reopening the original source.
Compilation and result comparison run without a model call and determine the recorded match or mismatch. A large language model (LLM) can explain a captured project snapshot.
Translation and checks
- Supported legacy source
- Validated, saved IR
- Standalone TypeScript
- Native, generated and expected-result checks
Optional LLM explanation
- Captured source, mappings and recorded results
- Model explanation with evidence links
The LLM cannot edit source, run programs, or decide whether results match. Its evidence links locate captured material; they do not verify the explanation's accuracy.
One rounding change, caught and rechecked
In a synthetic interest-posting example, two balances of 1.00 at a rate of 0.0050 each produce 0.01 after rounding, for a total of 0.02. Baseline checks compare original and generated programs with independently specified expected outputs.
Agreement between the two programs alone could hide a shared mistake. The separate expected outputs provide a third reference for the baseline behavior.
The change test removes the COBOL rounding instruction in a temporary source copy and freshly compiles it. The changed original returns zero while the retained TypeScript still returns cents. Regenerating from the changed source restores agreement between the two programs.
In the private project checkout, the local walkthrough command checks the baselines, makes the temporary edit, compares and regenerates the target, then exercises the blocked-translation example. The story runs locally without an LLM call. It requires Git, Docker and the project's pinned compiler image; the wrapper can build that image if needed.
./demo.sh story
| Source and target state | Original total | Target total |
|---|---|---|
| Baseline | 0.02 | 0.02 |
| Rounding removed, old target retained | 0.00 | 0.02 |
| Target regenerated from changed source | 0.00 | 0.00 |
The regenerated match is agreement with the edited source on these cases. The original 0.02 behavior has changed; the workbench retains the baseline and original expected values for review.
Where translation stops
A separate COBOL example uses REDEFINES, where fields share the same storage. RecodeIR can inspect it but blocks translation because treating those fields as independent values would change behavior.
This is a local prototype covering supported language forms and tested cases. Matching those outputs does not establish equivalence for every program.