バイブコーディングの落とし穴:UIは綺麗なのに動かない

自然言語プロンプトだけでWebアプリを作るバイブコーディング(Vibe Coding)。最初のプロンプトで返ってくるUIは驚くほど洗練されています。しかし、2回目、3回目の修正依頼を重ねると、アプリは徐々に壊れていきます。

最も厄介なのが**サイレント障害(Silent Failure)**です。画面上は何の問題もなさそうに見えるのに、内部では完全に破綻している状態を指します。例えば「カートに追加」ボタンを押すと成功トーストが表示され、カート件数も増える。しかし実際にはDBやストレージに何も書き込まれていない、というケースです。

これをデバッグするにはUIを触り、ログを追い、結局は生成されたコードを読むしかありません。バイブコーディングの趣旨と真っ向から矛盾します。本記事では、コードを読まずにアプリの挙動を検証するアプローチを共有します。

本記事はQiita/Zennでよく議論される「AI生成コードの検証コスト」という文脈で整理しています。

AI coding agent generating a web app interface with hidden data flow bugs Coding Session Visual

FlowCheck:UI制約を静的解析クエリへ翻訳する

コロンビア大学DAP Lab発のFlowCheckは、「コードを読まずにアプリを検証する」という課題に正面から取り組みます。核となるアイデアはシンプルです。ユーザーがUIで期待する動作を形式言語で記述し、それをCodeQLクエリへコンパイルして実コードと突き合わせるのです。

4段階のパイプライン

  1. 制約の表現:アプリを新規タブで開き、オーバーレイテンプレート(When I take [action], these update: [component])にUI要素をクリックして埋めます。
  2. 形式言語への変換:テンプレートを P(event | condition) = [0, 1] 形式の制約に変換します。例えばプロモコード適用時に合計額が必ず書き込まれるべきなら P(w(total) | A(promo-input)) = 1 となります。
  3. CodeQLへのコンパイル:制約のASTを走査してアクション、イベント種別、対象要素を抽出し、path_exists(経路存在)とall_paths_write(全経路での書き込み保証)の2つのデータフロークエリへ変換します。
  4. 検証:生成コードに対してクエリを実行し、違反箇所と正確な行をフラグします。
# 制約例:プロモコード適用時に total への書き込みが必ず発生すること
# P(write(total) | action(apply_promo)) = 1

# FlowCheckが内部的に生成するCodeQLクエリ(擬似コード)
from Action a, Write w
where a.getName() = "apply_promo"
  and w.getTarget() = "total"
select a, w
// 全実行経路で a -> w に到達可能である必要がある

フロンティアモデルとの比較

Amazon、Twitter、Airbnb、Slackを模した4つのアプリに、30個の微妙なデータフローバグを注入して評価しました。

検証手法検出率備考
FlowCheck30/30 (100%)誤検知0件
Claude Opus 4.7(詳細プロンプト)26/30 (87%)最高ベースライン
DeepSeek V3 / Gemini Pro26/30未満クロスハンドラに弱い

特にLLM審査員はハンドラ間のデータフローで一貫して崩れました。プロモ適用ハンドラがカートサマリを消したのに、チェックアウトハンドラが依然としてそれを読もうとする類のバグです。両ハンドラが直接参照し合わないため、モデルは個別に評価して繋がりを見落とします。

さらに興味深いのは、プロンプトを詳細にするとむしろ精度が落ちうるという点です。詳細化するとモデルはコードをより丁寧に読む代わりに、コードを過度に信頼し、バグを「意図的な挙動」と正当化し始めます。

Developer verifying LLM-generated shopping cart app with static analysis queries Development Concept Image

注意点:万能ではない

FlowCheckが100%を記録したからといって、あらゆる場面に適用できるわけではありません。以下の限界は押さえておくべきです。

  • 制約は人間が書く必要がある:結局「何が正しい挙動か」をユーザーが定義しなければなりません。要件が曖昧なら検証も曖昧になります。
  • CodeQLへの依存:静的解析エンジンの上に載っているため、対応言語・フレームワークに制約があります。React/JSエコシステム中心に検証された研究である点は考慮してください。
  • 動的状態・非同期競合は捕捉不可:静的解析は実行時のレースコンディションやタイミング問題を検出できません。
  • UI-バックエンド境界:クライアントからサーバAPIへ渡る区間の実際の永続化は、別途統合テストが必要です。

静的解析は「コードが意図通りに流れているか」を決定論的に確認する道具であり、「プロダクトが正しいか」を判断する道具ではありません。

日本開発エコシステムでの適用文脈

日本では受託開発やSI案件でAI生成コードをそのまま納品するケースが増えています。発注側はサイレント障害を発見する手段を持たないことが多く、納品後のトラブルになりがちです。FlowCheckのような制約ベース検証をQAプロセスに組み込めば、「画面は動くが保存されない」系のクレームを大幅に削減できるでしょう。

一方、レガシー(Struts、PHPベース)が多い現場ではCodeQLの適用範囲が限られるため、新規プロジェクトやReact/Next.jsベースのコードベースから導入することを推奨します。

CodeQL data flow graph tracing UI action to storage write in generated code Software Concept Art

まとめ:次のステップ

バイブコーディングの真のボトルネックは「生成」ではなく**「検証」**です。FlowCheckはそのボトルネックをUIレベルの意図表現で回避する巧妙なアプローチです。実務にすぐ適用できなくても、この発想自体はチームのQA戦略に示唆を与えます。

  • すぐできること:主要ユーザーフローごとに「このアクション後に必ずこのデータが保存されるべき」というチェックリストを作り、E2Eテストにマッピングしましょう。
  • 次のステップ:CodeQLやSemgrepなどの静的解析ツールをCIに組み込み、データフロールールを最低限でも強制する習慣をつけると良いです。
  • 研究トレンド:LLMを審査員に使うアプローチは、プロンプトが詳細になるほど信頼バイアスが生じる点を忘れないでください。

根拠資料:Coding Agents Keep Shipping Silent Failures — Here Is How to Catch Them

あわせて読みたい

本コンテンツは、信頼性の高い情報源をもとにAIツールを活用して作成され、編集者によるレビューを経て公開されています。専門家によるアドバイスの代替となるものではありません。