AI migrated legacy COBOL programs to Java, bugs included
arxiv.org
arxiv.org
Now, no one does.
I can see the allure of moving away from a legacy cobol system. But an AI rewrite doesn't actually solve any of the issues with having a legacy cobol codebase. You just have a new system no one knows or understands.
I got a chuckle over this, but in my experience working on legacy systems, this is the case already. Using AI to translate/explain the code brings extra understanding.
More like it will hallucinate some explanation & cause even more confusion.
I do wonder how an ambitious AI would handle the maths. COBOL is renowed for its fixed no rounding maths, utterly rigid and defined in the code, Java on the other hand is not (e.g., 0.1 + 0.2 becomes 0.30000000000000004), unless they are extensivly using BigDecimal, then its already a broken migration.
I've seen projects proclaim in the past to migrate COBOL systems to Java, and fail expicly when the solution was a dtaawarehouse system and a seperate Java system using the legacy backend to do all the fancy marketing reports or whatever other department was pushing for changes they wanted without a grasp of what it truly entailed and blinded by some sales pitch.
It's not just the code that needs migrating, its the data as well, then you want solid robust infrastrucure, which is why IBM still sell those mainframes to run all that well battle tested COBOL code.
Is it impossible to migrate to Java or any othger language - no, anything can be done, but the level of devil in the details and not just software, the data and a robust system to run it upon. It is very easy for even the best to overlook a gotcha.
We have all used an AI where it has gone down one path and you then point out something and it corrects itself, without the knowledge and a load of old grey beads(or a team) to act as devil advocate and try to pull the output apart, YOU can end up with something that works for everyones satisfaction, but is hiding a few gotchas down the line. AI coding needs a full debate team with one puishing it and one countering it almost I'd say.
If it works, why change it is always a good approach and why we mostly have in certain systems a COBOL backend with APIs or datawarehousing to expose for fancy java or other language added value/functionality.
I can only image generations of directors pushing cutting edge to replace legacy systems, and learning that cutting edge can cut you. My sympathy for the IT departments who have to deal with that as it has always been a bain of IT departments who are then forced to justify why it's fooling in a constructive way and explain it to non IT people in upper managment why the case.
As for migrating COBOL to anything, I'd not do it myself, id suggest a rewrite/redesign of a new system from scratch and then run both in parallel for a long time and make sure they actually do the same job and results. Even hand migrating back in the day, would produce a lot of messy code that refactoring would make sence and yet, not what the client would pay for as that would be a rewrite.
[0] https://community.ibm.com/community/user/blogs/gregory-cerne...
Yes, you can't tell at a glance if `+` really still does what it should, but I find that problem no different from a library mis-naming a function and/or said function having strange side-effects.
`+` should do addition, period. No, not even concatenation if possible (I do find the lack of a separate concatenation operator to be a language flaw --- that said, I understand the use of `+` for concat in libraries targeting languages that offer no alternative).
I think the abuse (especially in C++ ... seriously, allowing overloading of the comma operator? --- and <iostream> working via bit-shifting streams by ${some_string} bits) gave everyone a bad taste and they kind of threw out the baby with the bathwater.
I feel like the more dynamic and/or weakly-typed the language is, the more important it is to have a separate concat operator.
The worst ones being weakly-typed and dynamic. Consider `'5' + '10'` in JavaScript vs `'5' - '10'`. I also very much dislike Python's `+` for concat, but at least it's more strongly typed.
PHP, Lua, and Erlang are three examples of dynamically-typed languages with separate concat operators (`.`, `..`, `++`; respectively), and they all are better for it.
That said, even statically-typed languages benefit greatly from it. Maybe if C++ had a concat operator, it'd never end up abusing `<<` for writing to a stream (yes, there's no opposite for reading, but maybe they wouldn't end up doing that in this case).
For example, D uses `~` in infix for concat. Even UnrealScript, a 1990s game-engine-specific language (which tend to be a mess in general) did this right (it uses `$` or `@` --- with `a @ b` being equivalent to `a $ " " $ b`, IIRC).
Your 0.1 + 0.2 example wasn't an issue than and is not an issue today.
well, we just need to learn the rewrite then ???
The guy who no longer works at the company knew it was because of a bug in the DB that wasn't fixed by the vendor after the company cancelled the maintenance contract due to financial difficulties during the great recession.
AI doesn't and can't know that. So AI proposes to "fix the bug as we port it" and remove the double INSERT. The CTO sends an email saying that the new AI fixed 174 bugs during the porting process and now the company has a much better and resilient system.
BREAKING NEWS: thousands of travelers can't get go back home after thanksgiving due to a computer glitch that accidentally cancelled their return tickets. Stay tuned to our live coverage!
Prompt the core architecutre well suited for it.
Let it write tests.
Let it vibe migrate from left to write.
Now you at least have a chance of a team being able to work on that code base and actually clean it up and make it good.
Cobold is hard, hard legacy with bad tooling.
IMHO every large software system should be developed on the basis of clear and concise functional specifications so everyone can understand what the software does and how it does so at a higher functional level.
Not true, AI does. It's AI job security...
I think COBOL systems would be plenty maintainable if the owners of the systems invested in maintaining them. If companies just let people retire, attempt to hire replacements with unremarkable salaries, then maintenance is a problem.
If they paid salaries that reflected how critical this work is, I don't think it would be that big a problem to find and keep good developers.
We have critical economic infrastructure being treated as annoyance and a cost centre.
At least if tescoverage is good, but well... That's something llms can also be used for
From the paper:
> The COBOL source is passed through an internal deterministic Migrator to produce a generated Java target.
Also, humans are not deterministic either. Give the same COBOL -> Java translation to multiple developers and each will come up with a different solution. Heck, even the same developer will produce a different output for the same task, depending on the day of the week.
Indeed, and that's why so few dare to migrate them, and so many who do fail or blow the budget many times over.
I think that was the implicit point of the comment: don't expect that with AI, suddenly we can convert all those COBOL apps with a single prompt.
And that's why it's usually a stupid idea to nilly-willy migrate large code bases to different languages (also I'm getting really tired of the "but humans aren't either" trope).
Just set the sampling temperature to zero and remove any unintended non-determinism during the parallel computation of the token probability distribution. The problem is solved? Of course, not. Non-determinism has little to do with LLMs' mistakes.
My understanding is thats not possible (different from being practical), wonder if you have any literature, research to back up that claim?
1. Local hardware, no networking or HTTP requests 2. No other parallel requests 3. 1000 runs bounded by 1000 tokens
I have worked a little bit in academia and I am not a big fan of the way favorable samples for the hypothesis are kept and unfavorable ones are thrown away. I might be wrong here, however its highly unlikely that the team would have just worked with one query. Chances are that a lot of different prompts with varying number of runs would have been tried to see what works and supports the hypothesis.
Correction: AI is not deterministic, the only realistic low-error solution is not a more complex use of non-deterministic AI, but deterministic transpilation.
The problem is that this results in COBOL-in-Java which runs correctly but it is a nightmare to maintain.
As a side note, I can't fathom why they chose Java. It's easier to teach COBOL to a competent engineer than to rewrite everything in a language that encourages onion architectures. Why not Go, for example?
The tests need to be green, the math needs to math, but the code can look a little bit different here or there.
I don't think its easy at all to educate someone on COBOL. Its carrier suicide if you want to ever do anything else again after that gig. I was writing java for years, switched for 2 years to php for another company and had a few companies complaining about these 2 years...
A good Java architecture is possible, though, but it requires planning, discipline, and restraint; and yet the ever-changing business needs can mar your beautiful castle given enough time. COBOL is simpler and more straightforward, you have to go out of your way to mess it as badly as Java allows.
Most compilers are also not deterministic, at least by default, but they don't usually make mistakes. Determinism isn't an important quality here. And if it were, AI can be deterministic, it just isn't normally for much the same reason compilers typically aren't (hint: performance).
I find it bizarre that I keep reading this here. Just one of those things that keeps getting blindly repeated without receiving any thought?
can you get some arbitrary number of 9s for consistency? Yea. You can’t get 100% deterministic though.
Computers are deterministic. When we talk about non-determinism we're just talking about where there are hidden inputs, but the fundamentals of computing means that all hidden inputs can become visible if you want them to be (although possibly at the cost of things like performance), so, yes, you can reach 100% determinism just fine if you wish to. It's just not worth the tradeoffs in most cases. But if a deterministic solution solved a problem here it would be worth it.
However, a deterministic LLM doesn't help here. LLMs don't "make mistakes" because they are typically non-deterministic. They would equally "make mistakes" when deterministic.
There are hundreds of billions of lines of cobol in production.
The IRS alone has approx 160 cobol programs, averaging 230kloc each.
Their pitch is like, "we take your COBOL code, and all the real-world data you can give us. Then we model your COBOL program as a graph, where each node has inputs and outputs. Then we use AI to port each node, making sure that it has the same (input => output) mapping for all the test data you gave us."
This is the secret sauce. You'll be responsible for any defects if you didn't prepare your test data to act like a massive unit test. Wonder how hard is to prepare the ideal test data vs writing the unit tests themselves in COBOL and verifying their translation. I guess if you throw enough data at it, the effort is minimal while the coverage becomes good enough to fix any bugs manually.
https://www.pega.com/insights/resources/break-free-legacy-ma...
https://www.ibm.com/products/watsonx-code-assistant-z
https://global.fujitsu/en-global/pr/news/2026/03/30-01
https://www.rocketsoftware.com/en-us/insights/ai-powered-cob...
Maybe.
Still not something you want to risk your business on.
Related to this, I created a tool for situations where you want to compare COBOL code with Java code. It includes a preprocessing step where IMS etc. calls are converted to mocks that return JSON (from file), and also use JSON for input/output, and GnuCOBOL to run the program. More a proof-of-concept than production, but here is a link if somebody finds it helpful.
CICS is the big issue but AFAIK there were attempts. Everything else, including sort and VSAM, has various options provided usually by COBOL compiler vendors.
This is one set of ecosystems, where .NET going cross platform still misses out to Java, and neither of those companies cares about supporting it on their platforms.
There are some half way supported Python, Go and Rust versions as well, although I think they need the "WSL" of the respective mainframe/micro OS, aka UNIX services.
COBOL code:
PROCESS-DATA.
ADD 1 TO COUNTER.
DISPLAY COUNTER.
IF COUNTER < 10 GO TO PROCESS-DATA.
Java translation: while (counter < 10) {
counter++;
System.out.println(counter);
}
If "counter" is 10 on entry, the COBOL code prints 11 while the Java code prints nothing. So not only keeping old bugs, but apparently introducing new ones too!I wrote COBOL code for a few years at a job when I was a teenager. What makes legacy COBOL code difficult IMO is it can sometimes be very hard to maintain a mental execution state when examining the code, for several reasons:
1. all variables are global, aka, WORKING-STORAGE. You list all the variables used in the program and they are accessible to the entire program.
2. programs are divided into paragraphs. Control normally flows sequentially top to bottom through paragraphs, one executing after another. Except that the PERFORM statement can drastically alter this normal flow control, and you can't tell by looking at a paragraph how it will be executed. To do that, you have to look at all PERFORM statements that mention this paragraph or any paragraph physically before it, because in COBOL you can say PERFORM PARA1 THROUGH PARA27. If PARA13 is physically between PARA1 and PARA27, it's potentially going to get executed.
3. In true legacy COBOL, before structured COBOL was a thing (circa 1985), the main control flow statement in addition to PERFORM was GOTO. Lots of flag setting, and lots of GOTOs. So in the previous example, you can't tell if PARA13 is going to get executed because any prior statement might be a GOTO PARA14, skipping execution of PARA13. But even worse, you are still under the influence of the PERFORM THRU, so after PARA27 is executed, control returns to the statement following the PERFORM THRU, wherever that was. But if you GOTO PARA27, without being under a PERFORM THRU, then PARA27 is executed followed by the next sequential paragraph. Trying to figure this out statically by looking at the program can be very difficult, especially considering PERFORMs that are nested at runtime but may not be anywhere near each other in a code listing.
See Hyrum's Law: https://www.hyrumslaw.com/
COBOL isn't hard, the tooling around it on old systems are a pain though.
My wife and son then told me I "broke" the front door. I was confused, I thought I had fixed it
Turns out, with the door coming off the hinges, it wasn't closing properly, which meant it was ajar most of the time, so our dog could push it open with her body.
Now I'd fixed it, it closed properly all the time, so our dog started whining for someone to open the front screen door for her
So I loosened the screws, and hence "fixed" it by breaking it again
"Let's just do this in COBOL for now to get it working. Add a ticket to use AI to migrate it to Java in the backlog."
As specified, please find 99997 correct parts and the 3 defects (do not use)
I recently threw in (want to check those intelligence metrics!) some real production code into a non-agentic system (just to get a feel how things perform without a custom harness) and results where ... interesting. The particular program uses some preprocessor no LLM we have access to (newest was GPT 5.5) has any clue about - so they confabulate what it could do (Gemini 2.5 didn't even notice there was a preprocessor...). This is expected of course but it somehow seems the problem of this technology that unless you feed it masses of data or mechanically break up the tasks in rote subunits, it just doesn't do anything sensible still...
I don't remember their name, hopefully they stayed in business. since probably convincing financial firms that using Rust is better than Java is a mammoth task.