COBOL依存関係の知識グラフを築き、モダナイゼーションが翻訳ではなく取得で失敗すること、より大きなコンテキストウィンドウではその溝が埋まらない理由を示す図。
COBOLLegacy SystemsSoftware Modernization

ひとつのCOBOLファイルは、重要なその1事実以外のすべてをAIに伝え、だから私は先に地図を作った。

Ashutosh SinghalAshutosh Singhal2026年6月30日15 min

このすべてを始めたCOBOLの1行はわずか3語で、そのどれもが私を欺いていた。

COMPUTE WS-RESULT = WS-WIRE-AMOUNT - TRN-LIMIT. 私は中堅銀行の電信送金サブシステム向けのデモ資産を構築しており、これが次のプログラム内の運命的な1行だった。WIRETXN。一見、1年生でも移植できそうな算術に見える。金額から限度額を引き、結果を書き出す。その単一ファイルをどの現代的なモデルに渡してJavaを求めても、約4秒でクリーンにコンパイルが通り、単体テストに合格するJavaを返すだろう。それはTRN-LIMITlongとして型付けする。そして本番の最初の電信送金で、本番データベースに破損したバイト列を書き込むことになる。

それが分かるのは、TRN-LIMITlongではないからだ。これはパック10進数のCOMP-3フィールドであり、定義は3ファイル先にあり、その実行時の解釈はまったく別のプログラムで立てられたフラグによって選ばれ、午前2時に走るバッチジョブで順序づけられている。そのどれもがWIRETXNには見えない。危険なCOMPUTEを含むファイルには、それを危険にしている事実がひとつもない。

その溝こそが、私がCodeGraphを作った理由のすべてであり、このエッセイはその途上で私が間違えたことについてのものだ。私は最初、問題は翻訳の質だと確信していた。間違っていた。問題は、モデルが見るべきものを見られないことであり、「もっと文脈を与えれば」の量では決して直らないことを、しばらくかけて自分に証明した。

安全に見えて安全ではなかったCOMPUTE

私はまず手作業で電信送金の変更を地図に描き、どのツールも信頼する前に、正しい移行が知らなければならない事実が正確に9つあることを確かめた。

そのうち3つはWIRETXNの内部にあり、単一ファイルの読み手にも本当に見える。WIRETXNは、そのTRN-LIMITをそのCOMPUTEの33行目で使う。コピーブックCBACCTを名前のみ13行目で取り込む。UPDATEをDB2テーブルACCOUNTSに対して37行目で発行する。テキストウィンドウのツールはこの3つをすべて見る。もし事実がこれだけなら、素朴な移植でも問題ない。

痛いのは残りの6つだ。TRN-LIMITPIC S9(9)V99 COMP-3としてCBACCT.cpyの11行目で宣言されており、これはパック10進数を意味し、JavaではBigDecimalであって絶対にlongではない。その直下で、TRN-LIMIT-ALPHA REDEFINES TRN-LIMITが同じ6バイトを生のテキストとして重ねる。第三のフィールドLIMIT-TYPE-FLAGが、実行時にどちらの解釈が生きているかを決める。そのフラグはLIMITSETというプログラムが書き、夜間バッチジョブBATCHUPDもまた書く。そしてJCLジョブNIGHTLYが02:00に電信送金ジョブの先行として走り、「フラグを立てる」と「送金を実行する」の順序が資産全体で記録されている唯一の場所になっている。

TRN-LIMITのCodeGraph影響パネル。グラフ取得は9件中9件の事実を回復し、素朴な単一ファイルでは9件中3件。回復した各事実にはWIRETXN.cblとCBACCT.cpyからのファイルと行の出典が付く。
出荷済み合成フィクスチャ上のTRN-LIMIT閉包。グラフ取得はグラウンドトゥルース9件中9件を回復し、素朴な単一ファイル窓は9件中3件しか見ず、どの事実にも独自のファイルと行が付く。F4からF9——移植を壊す6つ——は単一ファイルでは隠されていると印されている。

6つの事実。どれも真実で、どれも荷重を担い、どれも実際に計算を行うファイルからは構造的に見えない。そう並べたとき、私を動揺させたのは素朴な移植が間違っていたことではなかった。素朴な移植には、自分が間違っていると知る術がなかったということだ。渡された1ファイルを読み、その1ファイルは重要な6つの事実について沈黙していた。

危険な行を含むファイルには、それを危険にしている事実がひとつもない。それは翻訳バグではない。翻訳バグの服を着た取得失敗だ。

コンテキストウィンドウを大きくするのをやめた理由

私の最初の直感は、いま誰もが抱くのと同じ直感で、しばらく追いかけたことは正直に言っておく。モデルにもっと与えればいい、と。

理屈は鉄壁に思えた。失敗がモデルに1ファイルしか見えなかったことなら、コピーブックも渡せばいい。フラグに触れるプログラムも渡せ。JCLも渡せ。コンテキストウィンドウはいま巨大で、四半期ごとに大きくなっているのだから、ケチをやめて近傍のコードを全部プロンプトに流し込めば答えになるはずだ。私は本気でこれが効くと思っていたし、おもちゃの例ではある程度そうなる——すでに貼るべき6ファイルを知っているなら、肝心の問題は手作業で解いてしまっているからだ。

そこに亀裂があった。モデルに正しい文脈を与えるには、まずどの文脈が正しい文脈かを知らなければならない。そしてTRN-LIMITの型が、BATCHUPDで書き込まれたフラグによって決まり、02:00のJCLジョブで順序づけられていることは、WIRETXNをより注意深く読んでも抽出できるものではない。それは、すでに依存関係グラフをたどっていなければ得られないものだ。コンテキストウィンドウは、コンテキストウィンドウに何を入れるべきかを教えてくれない。 私は答えそのもので問いを解こうとしていた。

そして数字がその点を決定的にした。銀行が実際に動かしている資産は6ファイルではない。COBOLで100万〜1,000万行、時にはそれ以上であり、業界全体では2,200億行がいまも本番で稼働している(業界メタ分析、2025年)。本物の電信送金の変更の推移的閉包は40ファイルかもしれないし、400かもしれない。それは今日も、3年後に出荷されるモデルでもコンテキストウィンドウには収まらない。資産はウィンドウより速く育ち、そもそもウィンドウが制約ではなかったからだ。制約は、1,000万行のうちこの変更が触れる40ファイルがどれかを知ること、そして38ではなく40をすべて見つけたと証明することだ。

より大きなコンテキストウィンドウは、私がもう問わなくなった問いに対するより良い答えだ。問いは「モデルはもっとコードを持てるか」ではなく、「どのコードか、そしてそれがすべてだとどう証明するか」だ。

その捉え直しこそが、CodeGraphが翻訳器ではない理由のすべてだ。私はわざとCOBOLを貼ってJavaを返さない。地図がプロダクトだ。翻訳は地図ができてしまえばどのツールでもできる下流のユースケースだ。私が築いているのはその下の理解レイヤーだ。出荷済みフィクスチャでは、資産は47ノード・70エッジの型付き知識グラフに解析され、「変更の影響」はグラフ走査——変更が触れるすべての推移的閉包——であり、各エッジには由来のfile:lineが付く。意図的に退屈な素のPythonのグラフ作業で、ホットパスにモデルはない。必要なのは賢さではない。完全で再現可能であることだ。同じフィクスチャを入れれば、毎回同じ閉包が出る。

私は自分にルールとして言い続けている。エージェントは助言し、コードが決める。 デモの任意の言語レイヤー——閉包について平易な英語で答える部分——は既定でオフで、キーの後ろにゲートされている。価値はそれに依存しない。価値は検索と証明であり、どちらもモデルの能力ではない。

素朴なビューは実際に何を削除するのか?

私はデモにトグルを組み込み、6つの事実が消えるのを見られるようにした。失敗を目の当たりにするまで、自分は完全には信じていなかったからだ。

「Naive AI context view」をオンにすると、グラフは単一のソースファイルと変更周囲の行窓にまで縮み、テキストウィンドウのツールがモデルに渡すものとまったく同じになる。9件中9件と読めていたパネルは9件中3件に落ちる。ファイル内の3事実は点灯したまま。残り6つは灰色に落ちて黙る。COMP-3の型、REDEFINESの重ね合わせ、制御フラグ、その2つのモジュール横断の書き手、そして02:00のJCL先行だ。赤いバナーが、アプリ自身の言葉で結果を示す——見える3事実だけを渡されたモデルはlong TRN_LIMITを出し、データベースを壊す、と。

CodeGraphのNaive AI context viewをオンにした状態。9事実のうち6つが灰色に沈み、WIRETXN.cbl内に生きているのは9件中3件だけで残りはテキストウィンドウのツールには見えない、と赤いバナーが述べる。
素朴な単一ファイルビュー——テキストウィンドウのツールが実際に見るもののシミュレーションであり、ライブ接続ではない。6事実が灰色に沈む。バナーは消えたものを名指しする。COMP-3の型、REDEFINESの重ね合わせ、制御フラグ、その2人の書き手、02:00の先行だ。

ここは慎重になりたい。創業者が大げさに売りたくなるまさにその地点だからだ。9対3の結果は出荷済みの合成電信送金フィクスチャで測ったものだ。真の依存集合が既知で、再現率が雰囲気ではなくラベル付きの実測になるよう、このデモのために私が手で書いた資産だ。あなたのCOBOLについての保証ではない。素朴ビューはシミュレーションであり、ライブのz/OSパイプラインではない。グラフはSQLiteの上のインメモリで、本番のグラフ基盤ではない。本物の銀行を倫理的に見せられず、既知のグラウンドトゥルースだけが「グラフは9つすべて、単一ファイルは3つ」と正直に言える唯一の方法だから、合成銀行を作った。

だが失敗の形は合成ではない。そこが重要な部分だ。型が他所で決まるCOMP-3フィールド、バッチジョブが立てるフラグ、JCLにしか存在しない順序——これらは40年ものの銀行資産のありふれた質感であり、珍しいエッジケースではない。メインフレーム・モダナイゼーション案件のおよそ70〜80%が目標を達成できないとき(業界メタ分析、2025年)、私はもう翻訳ステップが悪いせいだとは思わない。翻訳ステップは問題ない。最も重要な6事実が切り取られた絵を渡されているのだ。

証明がなければ、それは数に入らない

いちばん誇りに思う機能は、できないことを認める機能だ。コンプライアンスの会話がそれを捉え直してくれるまで、私はそれに気づいていなかった。

エンジニアが欲しいのは正しい移行だ。規制当局が欲しいのは別のもので、しかも難しい。証拠だ。DORAの下では、銀行はICT資産インベントリを負う。SOC-2の下では変更管理の領収証を負う。どちらも「依存関係を見つけた、信じてくれ」と言うモデルでは満たせない。完全性の証明——ツールがコードベースのどれだけを実際に解決できたかの声明と、より重要なのは解決できなかったものへの正直なフラグ——が必要だ。だから私は完全性ゲートを作った。フィクスチャ内のすべてのPERFORMCALLCOPY、およびDB2参照は、グラフ上の実ノードに解決されるか、「要レビュー」と印されなければならない。何も黙って消えてはいけない。

フィクスチャでは、そのゲートは34参照中33を解決し、カバレッジは97.1%だ。解決できない1つはDISPATCHというプログラムで、動的なCALL WS-PROGNAMEを行う。実行時に計算される宛先で、プログラムが走るまで行き先が分からないため、静的パーサはたどれない。そこでの正しい振る舞いは推測ではない。「人間がこれを見る必要がある」とフラグを上げ、レポートに残すことだ。

CodeGraphの監査タブ。参照の97.1%が解決され、1件がレビュー対象としてフラグ。フラグ対象はDISPATCH.cbl 15行目のDISPATCHの動的CALL WS-PROGNAMEで、黙って落とされずフラグされている。
フィクスチャ上の完全性ゲート。34参照中33が解決し97.1%。未解決の1つ——実行時計算ターゲットへのDISPATCHの動的CALL——は落とされずレビュー対象としてフラグされる。たどれない1つについての誠実さこそが本旨であり、脚注ではない。

そのフラグ付きのDISPATCH呼び出しは、このビルド全体でいちばん気に入っているもので、本気でそう思う。97%を解決し、できなかった3%を正確に教えてくれるツールは、100を主張して隙間を隠すツールより価値がある。隠れた隙間にこそ、壊れた電信送金が住むからだ。完全性ゲートはエクスポート可能な「Codebase Topology and Completeness Report」を生み出す——ノードとエッジの要約、file:line出典付きのモジュールごとの閉包、再現率の結果、タイムスタンプ付きのフラグ項目を含むJSONと印刷可能なHTMLだ。その成果物こそが本旨だ。規制当局に渡せ、来四半期に再実行し、決定論的だから同一の答えが得られるものだ。

自分の穴を認める数字を出荷するほうが、それを隠す丸い数字よりいい。フラグ付きの動的CALLはデモの弱点ではない。それがデモだ。

これはまた、陳腐化しない部分でもある。Javaの1行も幻覚しない完璧なモデルでも、どの依存関係を取得したかを規制当局に証明できない。実行時に計算されるCALLを静的にたどることもできない。それはコードの性質であって読み手の性質ではない。出典と完全性は、モデルのまわりに築くシステムの性質であり、スケールで解き放つ能力ではない。

手をつける順序

グラフが最後にくれたのは、最初から作ろうとも思っていなかったものだ。作業の安全な順序だ。

完全な依存トポロジーがあれば、どのプログラムも絡み具合で採点できる。私は素の式を使い、結合度をCOMP-3の罠、JCLの重要度、未解決の呼び出しに対して重み付けし、フィクスチャの14プログラムをストラングラーフィグ抽出順に並べる。リスク最低のプログラムが先、神プログラムが最後だ。フィクスチャではAUDITLOGがランク1・リスクスコア0で出てくる。結合がなく、正しくあることに誰も依存していないからだ。始めるのに安全な場所だ。私たちが心配してきたWIRETXNプログラムはランク11に座り、その1つのCOMP-3の罠とJCL重要度を抱える。DISPATCHは未解決の動的呼び出しを抱えランク12。そしてACCTMGR——すべてが寄りかかる神プログラム——は最後のランク14、リスクスコア15で抽出される。

CodeGraphの抽出タブ。フィクスチャの14プログラムをストラングラーフィグ順にランク付け。AUDITLOGがランク1・リスク0、ACCTMGRがランク14・リスク15。結合度、COMP-3の罠、JCL重要度の列。
フィクスチャ上のストラングラーフィグ抽出順。AUDITLOGがリスク0で最初に抽出され、神プログラムACCTMGRがリスク15で最後。WIRETXNとDISPATCHはCOMP-3の罠と未解決の動的呼び出しのためリスト上位に座る。順序はグラフの性質であり、判断の問題ではない。

順序づけをこれほど気にするとは思っていなかった。だが同じ教訓の三度目だ。どこから安全に始められるかは、トポロジーに関する事実であり、計画会議で言い争う意見ではない。 100万行を見つめるチームが本当に食い違っているのは、段落の翻訳の仕方ではない。どこから始め、間違ったものを先に触ると何が壊れるかについて、果てしなく高くついて食い違う。それはグラフの問いであり、グラフは毎回同じ答えを返す。

抽出順、完全性ゲート、影響閉包——どれも同じ対象を三つの角度から見たものだ。真のスライスを取得し、それが全体のスライスだと証明し、リスクでスライスを順位づける。その三つはどれも翻訳の問題ではなく、どれも賢いモデルでは解けない。

何度も立ち返る問い

私は見かけるAIモダナイゼーションの売り込み——自分のものも含め——に一つの問いを投げ始め、それが静かに、信じられる唯一の問いになった。

「良いJavaを書けるか」ではない。答えはほぼ常にイエスで、ほとんど問題にならないからだ。より難しいのは、TRN-LIMITの行が教えてくれた問いだ。いまこの瞬間、どの依存関係を取得したかを証明できるか。そしてその証明は、失敗させようとする規制当局にも耐えるか。ツールがfile:line出典付きの閉包を見せられず、解決できなかったものを正直に言えなければ、出力がどれほど流暢でも意味がない。それは良い文法での推測であり、私はまさにその推測がパック10進数フィールドに対してlongを型付けし、データベースに手を伸ばすのを見てきた。

業界は翻訳ステップを良くすることに十年を費やし、案件の70〜80%は目標を外し続けた(業界メタ分析、2025年)。リスクが翻訳にあったことが一度もなかったからだと思う。リスクはトポロジーに、見えない6事実に、午前2時に立てられるフラグにある。その6事実をグラフが回復し、正直にたどれない1つにフラグを立てる様子を見たいなら、デモはここだ。veriprajna.com/ja/demos/legacy-cobol-modernization

読むより見るほうがいいなら、端から端まで動いている全体がここにある。

私はもう、次のモデルリリースがこれらの移行を解き放つとは思わない。より大きなウィンドウはより多くのコードを持つ。どのコードかを知らず、すべてを見つけたと証明もできない。パーサの最初の1行を打ったときもそうだったし、これを作るのに使ったモデルが引退したずっと後も、そうであり続けると思う。難しいのはいつも地図だった。私たちは採点の仕方を知っていた翻訳ばかりを見続けていただけだ。

関連リサーチ

他のプラットフォームでも公開

確かな信頼のもとに、AIを構築する。

次世代のエンタープライズAI構築において豊富な経験を持つチームと、ぜひご一緒ください。信頼できるAI戦略の設計・構築・導入を、私たちがお手伝いします。

Veriprajna ディープテック・コンサルティング は、ヘルスケア・金融・規制対応分野における安全性重視のAIシステム構築を専門としています。当社のアーキテクチャは確立されたプロトコルに照らして検証され、包括的なコンプライアンス文書を備えています。