Een COBOL-afhankelijkheids-kennisgraaf toonde me dat modernisering faalt bij retrieval, niet bij vertaling, en waarom een groter contextvenster dat gat nooit dicht.
COBOLLegacy SystemsSoftware Modernization

Eén COBOL-bestand vertelde de AI alles behalve het ene feit dat ertoe deed, dus bouwde ik eerst de kaart.

Ashutosh SinghalAshutosh Singhal30 juni 202615 min

De COBOL-regel die dit alles in gang zette was drie woorden lang, en elk daarvan loog tegen me.

COMPUTE WS-RESULT = WS-WIRE-AMOUNT - TRN-LIMIT. Ik bouwde een demo-estate voor het overboekingssubsysteem van een mid-tier bank, en dit was de fatale regel in een programma genaamd WIRETXN. Het lijkt op rekenkunde die een eerstejaars zou kunnen porteren. Trek een limiet van een bedrag af, schrijf het resultaat. Als je dat ene bestand aan welk modern model dan ook gaf en om Java vroeg, zou het in ongeveer vier seconden schone, compilerende Java geven die de unittests doorstaat. Het zou typen TRN-LIMIT als een long. En bij de eerste live overboeking zou het corrupte bytes naar een productiedatabase schrijven.

Dat weet ik omdat TRN-LIMIT is geen long. Het is een packed-decimal COMP-3 veld, gedefinieerd drie bestanden verderop, waarvan de live-interpretatie wordt gekozen door een vlag die in een volledig ander programma wordt gezet, op volgorde gezet door een batchjob die om twee uur 's nachts draait. Niets daarvan is zichtbaar in WIRETXN. Het bestand dat de gevaarlijke COMPUTE bevat, bevat geen van de feiten die hem gevaarlijk maken.

Die kloof is precies de reden dat ik CodeGraph bouwde, en dit essay gaat over wat ik onderweg fout had. Ik was er in het begin zeker van dat het probleem de vertaalkwaliteit was. Ik had het mis. Het probleem is dat het model niet kan zien wat het moet zien, en ik heb een tijdje aan mezelf bewezen dat geen enkele hoeveelheid "geef het meer context" dat oplost.

De COMPUTE die er veilig uitzag en dat niet was

Ik bracht de overboekingswijziging eerst met de hand in kaart, voordat ik enig tool vertrouwde om het te doen, en er waren precies negen feiten die een correcte migratie moest kennen.

Drie daarvan leven in WIRETXN en zijn echt zichtbaar voor een lezer van één bestand. WIRETXN gebruikt TRN-LIMIT in die COMPUTE op regel 33. Het importeert een copybook genaamd CBACCT, alleen bij naam, op regel 13. Het vuurt een UPDATE af op de DB2-tabel ACCOUNTS op regel 37. Een text-window-tool ziet alle drie. Als dat de enige feiten waren, zou de naïeve port prima zijn.

De andere zes zijn degene die pijn doen. TRN-LIMIT is gedeclareerd PIC S9(9)V99 COMP-3 in CBACCT.cpy op regel 11, wat packed decimal betekent, wat BigDecimal in Java betekent en absoluut geen long. Direct eronder, TRN-LIMIT-ALPHA REDEFINES TRN-LIMIT, legt dezelfde zes bytes als ruwe tekst over het veld. Een derde veld, LIMIT-TYPE-FLAG, beslist bij runtime welke van die twee interpretaties de live is. Die vlag wordt geschreven door een programma genaamd LIMITSET, en opnieuw door een nachtelijke batchjob genaamd BATCHUPD. En de JCL-job NIGHTLY draait om 02:00 als voorganger van de overboekingsjob, wat de enige plek in de hele estate is waar de volgorde tussen "zet de vlag" en "voer de overboeking uit" überhaupt is vastgelegd.

CodeGraph-impactpanel voor TRN-LIMIT met graafretrieval 9 van 9 feiten teruggevonden tegen naïeve single-file 3 van 9, waarbij elk teruggevonden feit zijn bestands- en regelherkomst draagt uit WIRETXN.cbl en CBACCT.cpy.
De TRN-LIMIT-closure op de meegeleverde synthetische fixture. Graafretrieval herstelt 9 van 9 ground-truth-feiten, het naïeve single-file-venster ziet 3 van 9, en elk feit draagt zijn eigen bestand en regel. F4 tot en met F9, de zes die de port breken, zijn gemarkeerd als verborgen in single file.

Zes feiten. Elk ervan waar, elk ervan onmisbaar, en elk ervan structureel onzichtbaar vanuit het bestand dat daadwerkelijk de berekening doet. Toen ik ze zo naast elkaar zette, was wat me ongemakkelijk maakte niet dat de naïeve port fout was. Het was dat de naïeve port geen manier had om te weten dat hij fout was. Hij las het ene bestand dat hem was gegeven, en dat ene bestand zweeg over de zes feiten die ertoe deden.

Het bestand dat de gevaarlijke regel bevat, bevat geen van de feiten die hem gevaarlijk maken. Dat is geen vertaalfout. Het is een retrievalfalen in de kleren van een vertaalfout.

Waarom ik stopte met het contextvenster groter te maken

Mijn eerste instinct was hetzelfde instinct dat iedereen nu heeft, en ik wil eerlijk zijn dat ik het een tijdlang heb nagejaagd: geef het model gewoon meer.

De redenering voelde waterdicht. Als het falen is dat het model maar één bestand zag, voed het dan ook het copybook. Voed het de programma's die de vlag aanraken. Voed het de JCL. Contextvensters zijn nu enorm en worden elk kwartaal groter, dus het antwoord is vast om te stoppen met gierig zijn en de hele buurt van code in de prompt te gooien. Ik verwachtte oprecht dat dit zou werken, en voor een speelgoedvoorbeeld doet het dat min of meer, want als je al weet welke zes bestanden je moet plakken, heb je het echte probleem al met de hand opgelost.

Dat was de barst erin. Om het model de juiste context te voeden, moest ik eerst weten welke context de juiste context was. En weten dat TRN-LIMIT zijn type wordt bepaald door een vlag die in BATCHUPD wordt geschreven en geordend door een JCL-job om 02:00, is niet iets wat je haalt door WIRETXN harder te lezen. Het is iets wat je alleen krijgt door de afhankelijkheidsgraaf al te hebben gevolgd. Het contextvenster vertelt je niet wat je in het contextvenster moet stoppen. Ik had geprobeerd de vraag met het antwoord te beantwoorden.

Toen maakten de cijfers het punt permanent. De estates die deze banken echt draaien zijn geen zes bestanden. Het zijn één tot tien miljoen regels COBOL, soms meer, en 220 miljard regels ervan staan nog steeds in actieve productie in de hele industrie (industriële meta-analyse, 2025). Een echte overboekingswijziging kan een transitieve closure van veertig bestanden of vierhonderd hebben. Dat past nooit in een contextvenster, niet vandaag en niet in de modelversie die over drie jaar verschijnt, omdat de estate sneller groeit dan het venster en het venster sowieso nooit de beperking was. De beperking is weten welke veertig bestanden van de tien miljoen deze wijziging raakt, en bewijzen dat je alle veertig hebt gevonden in plaats van achtendertig.

Een groter contextvenster is een beter antwoord op een vraag die ik niet meer stel. De vraag is niet "kan het model meer code vasthouden," het is "welke code, en hoe bewijs je dat het alles is."

Die herkadering is de hele reden dat CodeGraph geen vertaler is. Ik plak bewust geen COBOL om Java terug te geven. De kaart is het product, en vertaling is een downstream-toepassing die elk tool kan doen zodra de kaart bestaat. Wat ik bouw, is de begripslaag eronder. Op de meegeleverde fixture parseert de estate tot een getypeerde kennisgraaf van 47 knopen en 70 randen, en de "impact van een wijziging" is een graaftraversale, de transitieve closure van alles wat de wijziging raakt, waarbij elke rand de file:line draagt waarvandaan hij kwam. Het is doelbewust saai plain-Python-graafwerk, geen model in het hot path, omdat wat ik nodig heb niet slim is. Ik heb nodig dat het volledig en reproduceerbaar is. Dezelfde fixture in, dezelfde closure uit, elke keer opnieuw.

Ik blijf het tegen mezelf zeggen als regel. Agents adviseren, code beslist. De optionele taallaag in de demo, het deel dat vragen over de closure in gewoon Engels zal beantwoorden, staat standaard uit en is achter een sleutel gezet. De waarde hangt er niet van af. De waarde is de retrieval en het bewijs, en geen van beide is een modelcapaciteit.

Wat wist de naïeve weergave eigenlijk weg?

Ik bouwde specifiek een toggle in de demo zodat ik de zes feiten kon zien verdwijnen, omdat ik het falen pas echt geloofde toen ik het zag gebeuren.

Zet "Naive AI context view" aan en de graaf klapt in tot het ene bronbestand plus een venster van regels rond de wijziging, precies wat een text-window-tool een model voedt. Het paneel dat 9 van 9 las, zakt naar 3 van 9. De drie in-file-feiten blijven verlicht. De andere zes worden grijs en stil: het COMP-3 type, de REDEFINES overlay, de sturende vlag, de twee cross-module-schrijvers ervan, en de JCL-voorganger om 02:00. Een rode banner spelt de consequentie uit in de eigen woorden van de app: met alleen de drie zichtbare feiten produceert een model long TRN_LIMIT en corrumpeert de database.

CodeGraph-naïeve AI-contextweergave aangezet, zes van de negen feiten grijs gedimd, met een rode banner die stelt dat slechts 3 van 9 feiten in WIRETXN.cbl leven en de rest onzichtbaar is voor een text-window-tool.
De naïeve single-file-weergave, een simulatie van wat een text-window-tool echt ziet, geen live connector. Zes feiten dimmen naar grijs. De banner noemt elk ding dat verdween: het COMP-3-type, de REDEFINES-overlay, de sturende vlag, de twee schrijvers ervan, en de voorganger om 02:00.

Ik wil hier voorzichtig zijn, want dit is precies de plek waar een founder de verleiding voelt om te oververkopen. Het 9-versus-3-resultaat is gemeten op de meegeleverde synthetische overboekingsfixture, een estate die ik met de hand voor deze demo schreef, precies zodat de echte afhankelijkheidsset bekend is en het recall-cijfer een echte gelabelde meting is in plaats van een vibe. Het is geen garantie over jouw COBOL. De naïeve weergave is een simulatie, geen live z/OS-pipeline. De graaf staat in-memory met SQLite eronder, geen productie-graafplatform. Ik bouwde een synthetische bank omdat ik je ethisch geen echte kon laten zien, en omdat een bekende ground truth de enige eerlijke manier is om te zeggen "de graaf kreeg alle negen en het enkele bestand kreeg er drie."

Maar de vorm van het falen is niet synthetisch, en dat is het deel dat ertoe doet. Het COMP-3 veld waarvan het type elders wordt bepaald, de vlag die door een batchjob wordt gezet, de volgorde die alleen in JCL bestaat — dat is de gewone textuur van een veertig jaar oude bankestate, geen exotische randgevallen. Als ruwweg 70 tot 80 procent van de mainframemoderniseringsprojecten hun doelstellingen niet haalt (industriële meta-analyse, 2025), denk ik niet langer dat het komt doordat de vertaalstap slecht is. De vertaalstap is prima. Hij krijgt een plaatje waarin de zes belangrijkste feiten zijn weggeknipt.

Bewijs, of het telt niet

De feature waar ik het meest trots op ben, is degene die toegeeft wat ze niet kan, en ik waardeerde dat pas toen een compliancegesprek het voor me herkaderde.

Een engineer wil een correcte migratie. Een toezichthouder wil iets anders en moeilijker: bewijs. Onder DORA is een bank een ICT-assetinventaris verschuldigd. Onder SOC-2 is ze change-control-bewijzen verschuldigd. Geen van beide wordt bevredigd door een model dat zegt "vertrouw me, ik heb de afhankelijkheden gevonden." Ze hebben een volledigheidsbewijs nodig, een verklaring van hoeveel van de codebase de tool daadwerkelijk kon herleiden en, belangrijker, een eerlijke vlag op wat hij niet kon. Dus bouwde ik een volledigheidsgate. Elke PERFORM, CALL, COPY, en DB2-referentie in de fixture moet tot een echte knoop in de graaf herleid worden of als "needs review" worden gemarkeerd. Niets mag stilzwijgend verdwijnen.

Op de fixture herleidt die gate 33 van 34 referenties, wat 97,1 procent dekking is. Degene die hij niet kan herleiden is een programma genaamd DISPATCH, dat een dynamische CALL WS-PROGNAME doet, een runtime-berekend doel dat geen statische parser kan volgen omdat de bestemming pas bekend is als het programma draait. En het juiste gedrag daar is niet raden. Het is een vlag hijsen die zegt "een mens moet hiernaar kijken," en hem in het rapport laten staan.

CodeGraph-audittab die toont dat 97,1 procent van de referenties is herleid met 1 gemarkeerd voor review, het gemarkeerde item zijnde de dynamische CALL WS-PROGNAME van DISPATCH op DISPATCH.cbl regel 15, vermeld als gemarkeerd en niet stilzwijgend weggelaten.
De volledigheidsgate op de fixture. 33 van 34 referenties worden herleid, 97,1 procent, en de enige die niet herleid kon worden, de dynamische CALL van DISPATCH naar een runtime-berekend doel, is gemarkeerd voor review in plaats van weggelaten. De eerlijkheid over degene die hij niet kan volgen is het punt, geen voetnoot.

Die gemarkeerde DISPATCH call is mijn favoriete ding in de hele build, en dat meen ik. Een tool die 97 procent herleidt en je precies vertelt welke 3 procent hij niet kon herleiden, is meer waard dan een tool die 100 claimt en het gat verbergt, omdat het verborgen gat precies is waar de corrupte overboeking leeft. De volledigheidsgate produceert een exporteerbaar "Codebase Topology and Completeness Report," een JSON en een printbare HTML met de knoop- en randensamenvatting, de per-module-closures met file:line herkomst, het recall-resultaat, en de gemarkeerde items met een tijdstempel. Dat artefact is het punt. Het is wat je een toezichthouder kunt overhandigen, volgend kwartaal opnieuw kunt draaien, en het identieke antwoord krijgt omdat het deterministisch is.

Ik zou liever een getal uitleveren dat zijn eigen gat toegeeft dan een ronder getal dat het verbergt. De gemarkeerde dynamische CALL is geen zwakte in de demo. Het is de demo.

Dit is ook het deel dat niet veroudert. Een perfect model, een dat nooit één regel Java hallucineert, kan een toezichthouder nog steeds niet bewijzen welke afhankelijkheden het heeft opgehaald. Het kan een runtime-berekende CALL nog steeds niet statisch volgen, omdat dat een eigenschap van de code is en niet van de lezer. Herkomst en volledigheid zijn eigenschappen van het systeem dat je om het model heen bouwt, geen capaciteiten die je ontgrendelt door het te schalen.

De volgorde waarin je dingen aanraakt

Het laatste wat de graaf me gaf, was iets wat ik niet eens van plan was te bouwen: een veilige volgorde om het werk in te doen.

Zodra je de volledige afhankelijkheidstopologie hebt, kun je elk programma scoren op hoe verstrengeld het is. Ik gebruik een eenvoudige formule, koppeling gewogen tegen COMP-3 vallen, JCL-kritikaliteit, en niet-herleide calls, en die rangschikt de veertien programma's in de fixture tot een wurgvijg-extractievolgorde. Het laagste-risicoprogramma wordt eerst geëxtraheerd, het god-programma als laatste. Op de fixture komt AUDITLOG uit op rang 1 met een risicoscore van nul, omdat het geen koppeling heeft en niets ervan afhangt dat het klopt. Het is de veilige plek om te beginnen. Het WIRETXN programma waar we ons zorgen over maakten zit op rang 11, met zijn ene COMP-3 val en zijn JCL-kritikaliteit. DISPATCH, met zijn niet-herleide dynamische call, zit op rang 12. En ACCTMGR, het god-programma waar alles op leunt, wordt als allerlaatste geëxtraheerd op rang 14 met een risicoscore van 15.

CodeGraph-extractietab die de veertien fixture-programma's toont gerangschikt in wurgvijg-volgorde, AUDITLOG op rang 1 met risicoscore 0 en ACCTMGR op rang 14 met risicoscore 15, kolommen voor koppeling, COMP-3-vallen, en JCL-kritikaliteit.
De wurgvijg-extractievolgorde op de fixture. AUDITLOG wordt eerst geëxtraheerd bij risico 0, het god-programma ACCTMGR als laatste bij risico 15, en WIRETXN en DISPATCH staan hoog op de lijst vanwege hun COMP-3-val en niet-herleide dynamische call. Volgorde is een graafeigenschap, geen oordeel.

Ik had niet verwacht zo veel om sequencing te geven als ik nu doe. Maar het is dezelfde les voor de derde keer. Waar je veilig kunt beginnen is een feit over de topologie, niet een mening waarover je ruzie maakt in een planningsmeeting. Een team dat naar een miljoen regels staart, is het eigenlijk niet oneens over hoe je een alinea vertaalt. Ze zijn het, eindeloos en duur, oneens over waar te beginnen en wat breekt als ze eerst het verkeerde aanraken. Dat is een graafvraag, en de graaf beantwoordt die elke run hetzelfde.

De extractievolgorde, de volledigheidsgate, de impact-closure — het zijn allemaal hetzelfde object vanuit drie hoeken bekeken. Haal de echte slice op, bewijs dat het de hele slice is, en rangschik de slices op risico. Geen van die drie is een vertaalprobleem, en geen ervan wordt opgelost door een slimmer model.

De vraag waar ik steeds op terugkom

Ik ben begonnen één vraag te stellen bij elke AI-moderniseringspitch die ik zie, inclusief die van mezelf, en die is stilletjes de enige geworden die ik vertrouw.

Niet "kan het goede Java schrijven," want het antwoord is bijna altijd ja en het doet er bijna nooit toe. De hardere vraag is die welke de TRN-LIMIT regel me leerde: kan het, nu meteen, bewijzen welke afhankelijkheden het heeft opgehaald, en zou dat bewijs een toezichthouder overleven die wilde dat het faalde. Als de tool me de closure niet kan tonen met file:line herkomst en me niet eerlijk kan zeggen wat hij niet kon herleiden, dan maakt het niet uit hoe vloeiend de output eruitziet. Het is gokken met goede grammatica, en ik heb precies die gok zien typen long over een packed-decimal-veld en naar de database grijpen.

De industrie heeft een decennium besteed aan het verbeteren van de vertaalstap terwijl 70 tot 80 procent van de projecten hun doelstellingen bleven missen (industriële meta-analyse, 2025), en ik denk dat dat komt omdat de vertaalstap nooit was waar het risico leefde. Het risico leeft in de topologie, in de zes onzichtbare feiten, in de vlag die om twee uur 's nachts wordt gezet. Als je wilt zien hoe een graaf die zes feiten terugvindt en daarna degene markeert die hij eerlijk niet kan, staat de demo hier: veriprajna.com/nl/demos/cobol-modernisering-met-een-kennisgraaf.

En als je het liever bekijkt dan mij het te horen beschrijven, hier is het hele ding van begin tot eind in actie.

Ik geloof niet langer dat de volgende modelrelease is wat deze migraties deblokkeert. Een groter venster houdt meer code vast; het weet niet welke code, en het kan niet bewijzen dat het alles heeft gevonden. Dat was waar toen ik de eerste regel van de parser typte, en ik denk dat het nog steeds waar zal zijn lang nadat het model waarmee ik dit bouwde met pensioen is. De kaart was altijd het moeilijke deel. We bleven naar de vertaling kijken omdat dat het deel was waarvan we wisten hoe we het moesten beoordelen.

Gerelateerd onderzoek

Ook gepubliceerd op

Bouw uw AI met vertrouwen.

Werk samen met een team met diepgaande ervaring in het bouwen van de volgende generatie enterprise-AI. Laat ons u helpen bij het ontwerpen, bouwen en implementeren van een AI-strategie waarop u kunt vertrouwen.

Veriprajna Deep Tech-adviesbureau is gespecialiseerd in het bouwen van veiligheidskritische AI-systemen voor de gezondheidszorg, de financiële sector en gereguleerde domeinen. Onze architecturen worden gevalideerd aan de hand van gevestigde protocollen met uitgebreide compliancedocumentatie.