
קובץ COBOL בודד סיפר ל-AI הכול חוץ מהעובדה האחת שחשבה, אז בניתי קודם את המפה.
שורת ה-COBOL שהתחילה את כל זה הייתה בת שלוש מילים, וכל אחת מהן שיקרה לי.
COMPUTE WS-RESULT = WS-WIRE-AMOUNT - TRN-LIMIT. בניתי סביבת הדגמה עבור תת-מערכת ההעברות הבנקאיות של בנק בינוני, וזו הייתה השורה הגורלית בתוך תוכנית בשם WIRETXN. היא נראית כמו אריתמטיקה שסטודנט בשנה א' יכול להמיר. מחסרים מגבלה מסכום, כותבים את התוצאה. אם הייתם מוסרים את הקובץ הבודד הזה לכל מודל מודרני ומבקשים Java, הוא היה מחזיר Java נקייה, שעוברת קומפילציה ובדיקות יחידה, תוך כארבע שניות. הוא היה מקליד את TRN-LIMIT כ-long. ובהעברה הבנקאית החיה הראשונה, הוא היה כותב בתים משובשים למסד נתונים בפרודקשן.
אני יודע את זה כי TRN-LIMIT אינו long. זהו שדה עשרוני ארוז מסוג COMP-3, שמוגדר במרחק שלושה קבצים, ושפרשנותו החיה נבחרת על ידי דגל שמוגדר בתוכנית אחרת לחלוטין, בסדר שמכתיבה עבודת אצווה שרצה בשתיים בלילה. אף אחד מאלה אינו נראה ב-WIRETXN. הקובץ שמכיל את ה-COMPUTE המסוכן אינו מכיל אף אחת מהעובדות שהופכות אותו למסוכן.
הפער הזה הוא כל הסיבה שבניתי את CodeGraph, והמאמר הזה עוסק במה שטעיתי בדרך לשם. התחלתי בטוח שהבעיה היא איכות התרגום. טעיתי. הבעיה היא שהמודל אינו יכול לראות את מה שהוא צריך לראות, ובזבזתי זמן להוכיח לעצמי ששום כמות של "תנו לו יותר הקשר" לא מתקנת את זה.
ה-COMPUTE שנראה בטוח ולא היה
מיפיתי את שינוי ההעברות הבנקאיות ידנית קודם, לפני שסמכתי על כלי כלשהו לעשות זאת, והיו בדיוק תשע עובדות שהגירה נכונה הייתה חייבת לדעת.
שלוש מהן חיות בתוך WIRETXN ונראות באמת לקורא של קובץ בודד. WIRETXN משתמש ב-TRN-LIMIT באותו COMPUTE בשורה 33. הוא מייבא copybook בשם CBACCT, בשם בלבד, בשורה 13. הוא מפעיל UPDATE על טבלת DB2 ACCOUNTS בשורה 37. כלי חלון-טקסט רואה את שלושתן. אם אלה היו העובדות היחידות, הפורט הנאיבי היה בסדר.
שש האחרות הן אלה שכואבות. TRN-LIMIT מוצהר כ-PIC S9(9)V99 COMP-3 ב-CBACCT.cpy בשורה 11, כלומר עשרוני ארוז, כלומר BigDecimal ב-Java ובהחלט לא long. מיד מתחתיו, TRN-LIMIT-ALPHA REDEFINES TRN-LIMIT, פורש את אותם שישה בתים על השדה כטקסט גולמי. שדה שלישי, LIMIT-TYPE-FLAG, מחליט בזמן ריצה איזו משתי הפרשנויות היא החיה. הדגל הזה נכתב על ידי תוכנית בשם LIMITSET, ושוב על ידי עבודת אצווה לילית בשם BATCHUPD. ועבודת ה-JCL NIGHTLY רצה ב-02:00 כקודמת של עבודת ההעברות, וזהו המקום היחיד בכל הסביבה שבו הסדר בין "הגדר את הדגל" לבין "הרץ את ההעברה" בכלל מתועד.

שש עובדות. כל אחת מהן נכונה, כל אחת מהן נושאת עומס, וכל אחת מהן בלתי-נראית מבנית מהקובץ שבעצם מבצע את החישוב. כשסידרתי אותן כך, מה שהטריד אותי לא היה שהפורט הנאיבי היה שגוי. זה היה שלפורט הנאיבי לא הייתה שום דרך לדעת שהוא שגוי. היא קראה את הקובץ האחד שניתן לה, והקובץ האחד שתק לגבי שש העובדות שחשבו.
הקובץ שמכיל את השורה המסוכנת אינו מכיל אף אחת מהעובדות שהופכות אותה למסוכנת. זו אינה באג תרגום. זהו כשל אחזור שלובש בגדי באג תרגום.
מדוע הפסקתי לנסות להגדיל את חלון ההקשר
האינסטינקט הראשון שלי היה אותו אינסטינקט שיש לכולם עכשיו, ואני רוצה להיות כן שאפילו רדפתי אחריו זמן מה: פשוט תנו למודל יותר.
ההיגיון הרגיש אטום. אם הכשל הוא שהמודל ראה רק קובץ אחד, אז תזינו לו גם את ה-copybook. תזינו לו את התוכניות שנוגעות בדגל. תזינו לו את ה-JCL. חלונות ההקשר עצומים עכשיו וגדלים בכל רבעון, אז בוודאי שהתשובה היא להפסיק להיות קמצנים ולשפוך את כל שכונת הקוד לפרומפט. באמת ציפיתי שזה יעבוד, ובדוגמת צעצוע זה בערך עובד, כי כשאתם כבר יודעים אילו שישה קבצים להדביק, כבר פתרתם את הבעיה האמיתית ביד.
זה היה הסדק. כדי להזין למודל את ההקשר הנכון, קודם הייתי חייב לדעת איזה הקשר הוא ההקשר הנכון. ולידע ש-TRN-LIMIT — שהטיפוס שלו נקבע על ידי דגל שנכתב ב-BATCHUPD ומסודר על ידי עבודת JCL ב-02:00 אינו דבר שחולצים בקריאה קפדנית יותר של WIRETXN. זהו דבר שאפשר להשיג רק אחרי שכבר עקבתם אחרי גרף התלויות. חלון ההקשר אינו אומר לכם מה לשים בחלון ההקשר. ניסיתי לענות על השאלה עם התשובה.
ואז המספרים הפכו את הנקודה לקבועה. הסביבות שהבנקים האלה באמת מריצים אינן שישה קבצים. הן מיליון עד עשרה מיליון שורות COBOL, לפעמים יותר, ו-220 מיליארד שורות ממנה עדיין בפרודקשן פעיל בכל התעשייה (מטא-אנליזה תעשייתית, 2025). שינוי אמיתי בהעברות בנקאיות עשוי להיות בעל סגירה טרנזיטיבית של ארבעים קבצים או ארבע מאות. זה לעולם לא נכנס לחלון ההקשר, לא היום ולא בגרסת המודל שתישלח בעוד שלוש שנים, כי הסביבה גדלה מהר יותר מהחלון והחלון מעולם לא היה האילוץ בכלל. האילוץ הוא לדעת אילו ארבעים קבצים מתוך העשרה מיליון הם אלה שהשינוי נוגע בהם, ולהוכיח שמצאתם את כל הארבעים ולא רק שלושים ושמונה.
חלון ההקשר גדול יותר הוא תשובה טובה יותר לשאלה שהפסקתי לשאול. השאלה אינה "האם המודל יכול להחזיק יותר קוד," אלא "איזה קוד, ואיך מוכיחים שזה כולו."
מסגור מחדש זה הוא כל הסיבה ש-CodeGraph אינו מתרגם. במכוון איני מדביק COBOL ומחזיר Java. המפה היא המוצר, ותרגום הוא מקרה שימוש במורד הזרם שכל כלי יכול לעשות ברגע שהמפה קיימת. מה שאני בונה הוא שכבת ההבנה שמתחת. ב-fixture שנשלח הסביבה מפורסרת לגרף ידע מטיפוסים של 47 צמתים ו-70 קשתות, ו"השפעת שינוי" היא מעבר בגרף, הסגירה הטרנזיטיבית של כל מה שהשינוי נוגע בו, כאשר כל קשת נושאת את file:line שממנו הגיעה. זו במכוון עבודת גרף משעממת ב-Python פשוט, בלי מודל בנתיב החם, כי מה שאני צריך שזה יהיה אינו חכם. אני צריך שזה יהיה שלם וניתן לשחזור. אותו fixture פנימה, אותה סגירה החוצה, בכל פעם מחדש.
אני ממשיך לומר לעצמי את זה ככלל. סוכנים מייעצים, הקוד מחליט. שכבת השפה האופציונלית בהדגמה, החלק שיענה על שאלות על הסגירה באנגלית פשוטה, כבויה כברירת מחדל ונעולה מאחורי מפתח. הערך אינו תלוי בה. הערך הוא האחזור וההוכחה, ואף אחד מאלה אינו יכולת של מודל.
מה המבט הנאיבי באמת מוחק?
בניתי מתג להדגמה במיוחד כדי שאוכל לראות את שש העובדות נעלמות, כי לא האמנתי לגמרי בכשל עד שראיתי אותו קורה.
סמנו "Naive AI context view" והגרף מתכווץ לקובץ המקור הבודד פלוס חלון שורות סביב השינוי, שזה בדיוק מה שכלי חלון-טקסט מזין למודל. הלוח שקרא 9 מתוך 9 יורד ל-3 מתוך 9. שלוש העובדות בתוך הקובץ נשארות מוארות. שש האחרות מאפירות ונשקטות: ה-COMP-3 כטיפוס, ה-REDEFINES ככיסוי, הדגל השולט, שני הכותבים חוצי-המודולים שלו, והקודם ב-JCL ב-02:00. באנר אדום מפרט את התוצאה במילות האפליקציה עצמה, שכשמזינים רק את שלוש העובדות הנראות מודל פולט long TRN_LIMIT ומשחית את מסד הנתונים.

אני רוצה להיות זהיר כאן, כי זה בדיוק המקום שבו מייסד מתפתה להגזים במכירה. תוצאת ה-9-מול-3 נמדדת על ה-fixture הסינתטי להעברות בנקאיות ששוחרר, סביבה שכתבתי ביד להדגמה הזו, בדיוק כדי שקבוצת התלויות האמיתית תהיה ידועה ומספר ה-recall יהיה מדידה מתויגת אמיתית ולא תחושת בטן. זו אינה הבטחה לגבי ה-COBOL שלכם. המבט הנאיבי הוא סימולציה, לא צינור z/OS חי. הגרף הוא בזיכרון עם SQLite מתחת, לא פלטפורמת גרף בפרודקשן. בניתי בנק סינתטי כי לא יכולתי להראות לכם בנק אמיתי מבחינה אתית, וכי אמת-קרקע ידועה היא הדרך הכנה היחידה לומר "הגרף קיבל את כל התשע והקובץ הבודד קיבל שלוש."
אבל צורת הכשל אינה סינתטית, וזה החלק שחשוב. שדה ה-COMP-3 שטיפוסו נקבע במקום אחר, הדגל שמוגדר על ידי עבודת אצווה, הסדר שקיים רק ב-JCL — אלה המרקם הרגיל של סביבה בנקאית בת ארבעים שנה, לא מקרי קצה אקזוטיים. כשבערך 70 עד 80 אחוז מפרויקטי המודרניזציה של מיינפריים נכשלים בעמידה ביעדיהם (מטא-אנליזה תעשייתית, 2025), אני כבר לא חושב שזה כי שלב התרגום גרוע. שלב התרגום בסדר. מאכילים אותו בתמונה ששש העובדות החשובות ביותר נחתכו ממנה.
הוכחה, או שזה לא נחשב
התכונה שאני הכי גאה בה היא זו שמודה במה שאינה יכולה לעשות, ולא הערכתי את זה עד ששיחת תאימות ניסחה מחדש את זה עבורי.
מהנדס רוצה הגירה נכונה. רגולטור רוצה משהו אחר וקשה יותר: ראיות. תחת DORA, בנק חייב מלאי נכסי ICT. תחת SOC-2, הוא חייב קבלות של בקרת שינויים. אף אחד מאלה אינו מסופק על ידי מודל שאומר "תסמכו עליי, מצאתי את התלויות." הם צריכים הוכחת שלמות, הצהרה על כמה מבסיס הקוד הכלי באמת הצליח לפתור, וחשוב מכך, דגל כנה על מה שהוא לא יכול היה. אז בניתי שער שלמות. כל PERFORM, CALL, COPY, והפניית DB2 ב-fixture חייבים להיפתר לצומת אמיתי בגרף או להיות מסומנים "דורש סקירה." שום דבר אינו מורשה להיעלם בשקט.
ב-fixture, השער הזה פותר 33 מתוך 34 הפניות, שזה כיסוי של 97.1 אחוז. האחת שהוא אינו יכול לפתור היא תוכנית בשם DISPATCH, שמבצעת CALL WS-PROGNAME דינמי, יעד שמחושב בזמן ריצה שמנתח סטטי אינו יכול לעקוב אחריו כי היעד אינו ידוע עד שהתוכנית רצה. וההתנהגות הנכונה שם אינה לנחש. היא להרים דגל שאומר "אדם צריך להסתכל על זה," ולהשאיר את זה בדוח.

אותו DISPATCH המסומן — הקריאה — הוא הדבר האהוב עליי בכל הבנייה, ואני מתכוון לזה. כלי שפותר 97 אחוז ואומר לכם בדיוק אילו 3 אחוזים הוא לא יכול היה שווה יותר מכלי שטוען 100 ומסתיר את הפער, כי הפער המוסתר הוא המקום שבו חיה ההעברה הבנקאית המשובשת. שער השלמות מפיק "דוח טופולוגיית בסיס קוד ושלמות" שניתן לייצוא, JSON ו-HTML להדפסה עם סיכום הצמתים והקשתות, הסגירות לכל מודול עם מקור file:line, תוצאת ה-recall, והפריטים המסומנים עם חותמת זמן. הארטיפקט הזה הוא הנקודה. זה הדבר שאפשר למסור לרגולטור, להריץ מחדש ברבעון הבא, ולקבל את אותה תשובה זהה כי זה דטרמיניסטי.
אני מעדיף לשחרר מספר שמודה בחור שלו מאשר מספר עגול יותר שמסתיר אותו. ה-CALL הדינמי המסומן אינו חולשה בהדגמה. הוא ההדגמה.
זה גם החלק שאינו מתיישן. מודל מושלם, אחד שלעולם אינו מהזה שורת Java אחת, עדיין אינו יכול להוכיח לרגולטור אילו תלויות הוא אחזר. הוא עדיין אינו יכול לעקוב אחרי CALL שמחושב בזמן ריצה באופן סטטי, כי זו תכונה של הקוד ולא של הקורא. מקור ושלמות הם תכונות של המערכת שאתם בונים סביב המודל, לא יכולות שפותחים על ידי הגדלתו.
הסדר שבו נוגעים בדברים
הדבר האחרון שהגרף נתן לי היה משהו שאפילו לא יצאתי לבנות: סדר בטוח לעשות את העבודה בו.
ברגע שיש לכם את טופולוגיית התלויות המלאה, אפשר לדרג כל תוכנית לפי כמה היא סבוכה. אני משתמש בנוסחה פשוטה, צימוד משוקלל מול מלכודות COMP-3, קריטיות JCL, וקריאות שלא נפתרו, והיא מדרגת את ארבע-עשרה התוכניות ב-fixture לסדר חילוץ בסגנון תאנה חונקת. התוכנית בסיכון הנמוך ביותר מחולצת ראשונה, תוכנית-האל אחרונה. ב-fixture, AUDITLOG יוצא בדירוג 1 עם ציון סיכון אפס, כי אין לו צימוד ושום דבר אינו תלוי בכך שיהיה נכון. זה המקום הבטוח להתחיל. WIRETXN, התוכנית שדאגנו לגביה, יושבת בדירוג 11, נושאת את מלכודת ה-COMP-3 האחת שלה ואת קריטיות ה-JCL שלה. DISPATCH, עם הקריאה הדינמית שלא נפתרה, יושב בדירוג 12. ו-ACCTMGR, תוכנית-האל שהכול נשען עליה, מחולצת אחרונה בדירוג 14 עם ציון סיכון של 15.

לא ציפיתי לדאוג לרצף כמו שאני דואג עכשיו. אבל זה אותו שיעור בפעם השלישית. איפה אפשר להתחיל בבטחה הוא עובדה על הטופולוגיה, לא דעה שרבים עליה בפגישת תכנון. צוות שמביט במיליון שורות אינו באמת חולק על איך לתרגם פסקה. הוא חולק, ללא סוף וביוקר, על איפה להתחיל ומה נשבר אם נוגעים בדבר הלא נכון קודם. זו שאלת גרף, והגרף עונה עליה באותה דרך בכל הרצה.
סדר החילוץ, שער השלמות, סגירת ההשפעה — כולם אותו אובייקט שנצפה משלוש זוויות. אחזרו את הפרוסה האמיתית, הוכיחו שהיא הפרוסה השלמה, ודרגו את הפרוסות לפי סיכון. אף אחת משלוש אלה אינה בעיית תרגום, ואף אחת מהן אינה נפתרת על ידי מודל חכם יותר.
השאלה שאני חוזר אליה שוב ושוב
התחלתי לשאול שאלה אחת בכל מצגת מודרניזציה מבוססת AI שאני רואה, כולל שלי, והיא בשקט הפכה ליחידה שאני סומך עליה.
לא "האם הוא יכול לכתוב Java טובה," כי התשובה כמעט תמיד כן וכמעט אף פעם לא משנה. השאלה הקשה יותר היא זו ששורת ה-TRN-LIMIT לימדה אותי: האם הוא יכול להוכיח, עכשיו, אילו תלויות הוא אחזר, והאם ההוכחה הזו תשרוד רגולטור שרצה שהיא תיכשל. אם הכלי אינו יכול להראות לי את הסגירה עם מקור file:line ואינו יכול לומר לי בכנות מה הוא לא יכול היה לפתור, אז לא משנה כמה הפלט נשמע שוטף. הוא מנחש עם דקדוק טוב, וראיתי בדיוק את הניחוש הזה מקליד long מעל שדה עשרוני ארוז ומושיט יד למסד הנתונים.
התעשייה בילתה עשור בשיפור שלב התרגום בזמן ש-70 עד 80 אחוז מהפרויקטים המשיכו להחטיא את יעדיהם (מטא-אנליזה תעשייתית, 2025), ואני חושב שזה כי שלב התרגום מעולם לא היה המקום שבו חי הסיכון. הסיכון חי בטופולוגיה, בשש העובדות הבלתי-נראות, בדגל שמוגדר בשתיים בלילה. אם אתם רוצים לראות גרף משחזר את שש העובדות האלה ואז מסמן את האחת שהוא בכנות אינו יכול, ההדגמה כאן: veriprajna.com/he/demos/legacy-cobol-modernization.
ואם אתם מעדיפים לצפות בזה מאשר לקרוא אותי מתאר, הנה הדבר כולו רץ מקצה לקצה.
אני כבר לא מאמין ששחרור המודל הבא הוא מה שפותח את ההגירות האלה. חלון גדול יותר מחזיק יותר קוד; הוא אינו יודע איזה קוד, ואינו יכול להוכיח שמצא את כולו. זה היה נכון כשהקלדתי את השורה הראשונה של המנתח, ואני חושב שזה עדיין יהיה נכון הרבה אחרי שהמודל שבו השתמשתי לבנות את זה יצא לגמלאות. המפה תמיד הייתה החלק הקשה. פשוט המשכנו להסתכל על התרגום כי זה היה החלק שידענו איך לדרג.


