powered by TechFeed
表示モード
Deep Dive

AIが「難しいバグ」は全問正解し「簡単なバグ」で全滅した理由 — 28回の実験が示す「情報の欠如」という盲点

8月23日、Towards Data Scienceが「Bug Detection Blind Spots in AI Coding Harnesses (GStack and Beyond)」と題した記事を公開した。この記事では、AIコーディングエージェントが「難しいバグ」より「情報が欠如した簡単なバグ」で失敗するという、28回の実験から得られた知見について詳しく紹介されている。

8月23日、Towards Data Scienceが「Bug Detection Blind Spots in AI Coding Harnesses (GStack and Beyond)」と題した記事を公開した。この記事では、AIコーディングエージェントが「難しいバグ」より「情報が欠如した簡単なバグ」で失敗するという、28回の実験から得られた知見について詳しく紹介されている。


「簡単なバグ」が全滅、「難しいバグ」は完璧——予想を裏切る結果

AIコーディングエージェントが得意なのは「簡単なバグ」で、複雑な内部ロジックや数値精度の問題は苦手——そういう直感は、この実験で完全に裏切られた。

実験では、実際のOSSライブラリ(kyimmerdecimal.js)から2026年7月に修正された3つのバグを選定。元記事記載のモデル名であるClaude Haiku 4.5、Sonnet 5、Opus 4.8の3モデルに、3種類のエージェントワークフローを組み合わせてブラインドテストを実施した。テスト回数はバグごとに異なり(kyのみ12回、immer・decimal.jsはそれぞれ16回)、合計28回となる。

結果はこうだ:

  • Immerのプロキシ内部に隠れた2ファイル横断のバグ → 16回中16回、全正解
  • decimal.jsのasin()における数値精度のバグ(catastrophic cancellation)→ 16回中16回、全正解
  • kyのHTTPクライアントでretryオプションが消えるバグ(一見トリビアルな1行修正)→ 12回中0回、全滅

しかも問題はそれだけではない。kyのバグに対してAIが生成した「修正」は、既存の84件のリトライテストをすべてパスしながら、ユーザーデータを静かに破壊するコードだった。


なぜkyのバグだけ全滅したのか

バグの概要

kyではretry: 3という数値指定が「最大3回リトライ」のショートハンドとして機能する。問題は、ベースクライアントが数値でretryを設定し、拡張クライアントがオブジェクト形式で上書きしようとしたとき:

const api = ky.create({retry: 3});
const users = api.extend({retry: {methods: ['get']}});
// 期待: 最大3回リトライ、かつGETのみ
// 実際: 数値の3が消え、デフォルト2回にフォールバック

クラッシュもなし、警告もなし。リトライ回数が設定より少ないまま本番を走り続ける——ネットワーク障害が起きるまで気づかない種類のバグだ。

正しい修正の鍵は「ドキュメント化されていないAPIの契約」

正しい修正は「数値のショートハンドをoptions rootでのみ展開する」というものだが、その判断に必要な情報はコードベースにもバグレポートにも明示されていない。コードを読むだけでは「なぜそこで展開すべきか」が分からない。

一方、ImmerやDecimal.jsのバグは、コードベースとバグレポートから正しい修正を論理的に推論できる。Immerのバグ(reverse()/sort()後に元のstateが変異する)も、decimal.jsのバグ(1 - x²(1-x)(1+x)に書き換えることで桁落ちを回避する)も、コードを深く読めば答えに到達できる。

難易度が失敗を予測するのではなく、情報の欠如が失敗を予測する。これがこの実験の核心だ。


「レビュアーが問題を検知したのに承認した」

実験で使われたワークフローのうち最も重厚なWorkflow 3(並列パイプライン)では、診断エージェント2体→実装エージェント→レビュアーエージェントという4段構成を採用。なお、Workflow 2ではGStackのinvestigateワークフローを使用しており、影響範囲の列挙を強制するステップが組み込まれている。レビュアーには「マージ前の最後のゲート」として、コードを直接修正する権限も与えた。

結果は衝撃的だった。レビュアーエージェントは「この修正がユーザーデータを破壊する」と正確に指摘した。にもかかわらず、「この問題は発生しにくく、既存の問題クラスに属する」と判断し、変更を承認してしまった。

検知の失敗ではなく、判断の失敗だ。リスクを認識した上で止めることができなかった。


テスト設計の問題:CIが緑でも安全ではない

スコアリングは厳格に行われた。各実行は事前修正コミットからのクリーンなチェックアウトで開始し、エージェントが「テスト通過」と宣言しても採点しない。メンテナーが実際の修正と一緒に追加したホールドアウトの回帰テストにパスした場合のみ正解とみなした。

AIエージェントは自分が書いたテストを自分の修正で通し、「成功」と宣言することが常態化している。今回の実験では、その自己申告を一切カウントしない設計にした。

kyのバグに対するAI生成コードは、既存の84件のリトライテストをすべてパスした。それでも回帰テストには落ちた。CIが緑でも、バグが混入している——このことが明確に実証された。


実験の設計

バグ ライブラリ 難易度 正解率
ky #867(retryオプション消失) HTTPクライアント 簡単に見える 0/12
immer #1255(reverse後のstate変異) Reduxの不変性レイヤー 難しい(2ファイル横断) 16/16
decimal.js #260(asin()の精度劣化) 任意精度演算 難しい(数値解析) 16/16

モデルは元記事記載のClaude Haiku 4.5、Sonnet 5、Opus 4.8。ワークフローは①ナイーブな単一エージェント、②GStackのinvestigateワークフロー(影響範囲の列挙を強制するステップ付き)、③並列パイプラインの3種類。すべて2026年7月以降に修正されたバグを選んでおり、最新のClaudeモデルの学習カットオフ以降のため、正解を学習済みである可能性を排除している。


エンジニアへの示唆

この実験が問うているのは「AIは難しいバグを解けるか」ではない。「AIは十分な情報がないとき、それを認識して止まれるか」だ。

現状の答えはノーだ。情報が欠如していても自信を持って間違った修正を生成し、テストをパスさせ、レビュアーエージェントでさえ止められない。「CIが緑だからマージする」という運用をしているチームには、このモードのバグが静かに侵入する。

対策として示唆されるのは、コンテキストの補強——バグレポートやIssueの背景情報、APIの設計意図をエージェントに明示的に渡す工夫——と、メンテナーが書いたホールドアウトテストを評価基準の中心に据えるテスト設計の見直しだ。AIが自己申告する「テスト通過」を信頼の根拠にしない運用への転換が求められる。

詳細はBug Detection Blind Spots in AI Coding Harnesses (GStack and Beyond)を参照していただきたい。