- A COBOL migration ships Java that compiles, passes every unit test, then corrupts a live wire transfer in UAT. The bug was never in the translation. It was one line of a copybook nobody in the context window could see 🧵
- The variable is TRN-LIMIT. Read only WIRETXN.cbl and you get 3 facts: it is used in a COMPUTE, a copybook is imported, an UPDATE hits DB2 table ACCOUNTS. Hand those 3 to any model and it emits long TRN_LIMIT. Reasonable. Wrong.
- TRN-LIMIT is PIC S9(9)V99 COMP-3, packed decimal, which maps to BigDecimal, not long. That fact lives in CBACCT.cpy, three copybooks from the call site. It is structurally invisible in a single-file context window.
- It gets worse. TRN-LIMIT-ALPHA REDEFINES the same 6 bytes as text, and LIMIT-TYPE-FLAG decides which reading is live at runtime. That flag is set in a different program (LIMITSET), and again by BATCHUPD in the nightly batch run.
- The flag is written before the wire runs only because a JCL job, NIGHTLY at 02:00, is sequenced ahead of WIREJOB. That ordering edge exists nowhere in the COBOL source. It lives only in the JCL. Reading the .cbl never recovers it.
- Nine facts govern that one variable. A single-file window sees 3. The six it drops (the COMP-3 type, the REDEFINES, the flag, its two cross-module writers, the JCL ordering) are exactly the ones that corrupt ACCOUNTS on the first live transfer.
- So we stopped reading code as text and built the topology first. We parse the estate into a typed knowledge graph, then resolve the transitive closure of a change. On this fixture: 47 nodes, 70 edges, every edge carrying its file:line source.
- On the TRN-LIMIT closure the graph recovers 9/9 against a 3/9 single-file baseline, scored on a ground-truth dependency set we know because the estate is synthetic and authored. Same fixture, same result every run. Scope: this one labeled scenario.
- It also proves its own coverage. 33 of 34 references resolved, 97.1%. The one it cannot resolve, DISPATCH's dynamic CALL WS-PROGNAME with a runtime-computed target, is flagged for review, never silently dropped. The honesty is the point.
- For the GraphRAG builders: when you retrieve a code slice for a model, do you measure recall against a known dependency set, or trust the model to ask for what it needs? Where do you prove you retrieved all of it? #GraphRAG #COBOL #MainframeModernization #KnowledgeGraph
- We built this as a demo (in-memory graph, synthetic estate, no live z/OS pipeline). If your team is modernizing a mainframe and wrestling with retrieval completeness, we would like to hear how you draw it. Walkthrough: https://veriprajna.com/demos/legacy-cobol-modernization
Published on X · July 27, 2026
On social media
See this post on its original platform
In our archive