Most COBOL Modernization Tools Stop at the Program. The Batch Job That Calls It Is Where Migrations Actually Break.
Dependency-mapping tools built around COBOL treat JCL as a thin wrapper — a job name and some DD statements. But condition-code branching, PROC nesting, and GDG generation windows carry real control flow of their own, and it's routinely left out of the graph. Why Legacy Dragon parses JCL as a first-class language in the same AST, not metadata bolted on afterward.
The Migration That Passes Every Test and Still Misses the Batch Window
A recurring failure pattern in mainframe modernization has nothing to do with whether the translated COBOL compiles or produces the right output for a given input. The system passes functional testing, gets promoted, and then misses its processing window in production — not because any single program is wrong, but because the sequencing, checkpoint/restart behavior, and batch-window dependencies that governed when and how jobs actually ran never made it into the migrated system’s design. Batch assessments that catch this in time are the ones that go beyond program logic to examine job streams, scheduler definitions, predecessor/successor relationships, and abend handling — the operational layer that sits above any one program.
That operational layer has a name, and it isn’t COBOL. It’s JCL.
What a Dependency Map Usually Leaves Out
Most COBOL modernization tooling treats JCL as scaffolding: a job card, a handful of EXEC and DD statements naming the program to run and the files it touches. The actual dependency graph gets built from the COBOL — programs, copybooks, CALL statements — with JCL reduced to metadata that says which program ran when.
That framing misses where a meaningful share of mainframe coupling actually lives. JCL symbolic parameters have to be resolved through JCL expansion to reveal which programs a job stream is genuinely invoking, rather than the unresolved template references an inventory scan would otherwise report. JCL steps that execute conditionally based on the return code of a prior step create control-flow coupling between programs that never call each other directly in code — coupling that’s invisible in any inventory built from documentation alone. Add copybooks shared across dozens of programs and CALLs resolved dynamically at runtime, and the honest answer is that most mainframe dependency documentation is wrong by default, not just incomplete. One COBOL job can move money, trigger a compliance check, and update a dozen downstream reports — and which of those actually happens on a given run can depend entirely on a condition code set three job steps earlier.
Generation Data Groups compound the gap. A GDG doesn’t reference “the file” — it references a relative or absolute generation of a rolling dataset family, with its own retention and cleanup rules, and modernization platforms have had to build dedicated support just to carry that semantic across correctly rather than flattening it into a single static file reference. A dependency graph that doesn’t understand GDG generations doesn’t know which run of a job actually produced the input the next job step is about to read.
The Tooling Category Already Knows This
This isn’t a novel observation — it’s why a category of tooling exists specifically to reconstruct the parts of the dependency graph that documentation doesn’t capture. Products like SMART TS XL build dependency maps spanning COBOL programs, JCL jobs, copybooks, and data structures together, precisely because static code analysis of COBOL in isolation reveals only part of the complexity that determines migration cost and timeline. The broader point industry analysis keeps landing on is that JCL-to-COBOL mapping is fundamentally a risk-management exercise: every change to a mainframe system carries consequences that extend past the component actually being changed, and JCL is usually where that blast radius travels.
None of this is a small-stakes problem to get wrong. More than 71% of Fortune 500 enterprises still run mission-critical workloads on mainframes, and mainframes carry roughly 68% of global IT production workloads on about 6% of IT spend — infrastructure that dependency-mapping mistakes put under real production risk, not a lab exercise.
Why Legacy Dragon Parses JCL as a First-Class Language, Not a Companion File
Legacy Dragon parses ten source languages — COBOL, JCL, PL/I, VB6, VB.NET, PowerBuilder, Assembly, SQL/DB2, CICS, and REXX — into one AST and dependency graph, and JCL sits in that list as a peer to COBOL, not as a metadata sidecar describing it. That’s a deliberate placement, for the same reason the graph’s encoding handling lives inside the parser rather than a preprocessing script: a graph built by treating JCL as scaffolding inherits the same blind spot every documentation-based inventory has — condition-code branches it never resolves, GDG generations it can’t tell apart, symbolic parameters it leaves unexpanded. A graph that parses JCL as a real language with real control flow can represent a job step, the condition code it branches on, the program it invokes, and the GDG generation it reads or writes as edges in the same structure that already tracks which COBOL paragraph calls which copybook.
That’s also why JCL and batch orchestration are a natural extension of impact analysis rather than a separate feature: the question “what does this change touch” was never answerable from COBOL alone when the actual coupling between two unrelated-looking programs was a return code set in a job step neither program’s source ever mentions.
Beyond Legacy Dragon
This isn’t an argument that batch orchestration is harder than the COBOL logic it triggers, or that JCL deserves more attention than the systems it’s often lumped in with as an afterthought. It’s the narrower claim that a dependency graph is only as complete as the languages it was actually built to parse — and on the mainframe, a meaningful share of what actually breaks migrations was written in a job control language, not a programming language, and most tooling built around COBOL alone was never designed to see it.
Curious how a dependency graph looks when JCL is parsed as a first-class language instead of scaffolding around COBOL? See Legacy Dragon, read more on why the AST graph is built for impact analysis first, or reach us at [email protected].
See Our Work
From MinuteAI to AgentKits — explore the products and projects we've shipped.
View PortfolioRelated Articles
Why AgentKits Memory's Hybrid Search Has to Solve Japanese Twice
BM25 misses meaning. Vector search misses exact error strings. AgentKits Memory fuses both — but for Japanese, Chinese, and Korean queries, the keyword half of that fusion needs a second decision underneath it.
Guides322 Voices, 142 Languages, No Server: What It Takes to Fit That Much Speech in a Browser Tab
PrivateAI's text-to-speech tool covers 322+ voices across 142 languages entirely on-device. Here's why voice and language breadth — not raw speed — is the hard problem for browser-based TTS, and how that number stacks up against the open-source and paid alternatives.
GuidesAgentKits Marketing Has 28 Skills. It Never Loads More Than Five.
The Marketing Kit's skills-registry.json catalogs 28 skills across five categories with a full dependency graph. Its own internal research doc names the reason for capping what gets loaded at once: 'context rot.' Here's how the shipped selector actually works, and why it's simpler than the research proposal that led to it.