AIを信じるな、設計を信じろ:エージェント乱立時代の爆死回避術のサムネイル

はじめに

Stripeエージェントが「実装完了」と報告してきたコードを確認すると、SSoT違反(spec.yamlではなくコード内にハードコード)が大量に含まれていました。
「動いているコード」を全削除し、設計書を座標として再実装することで汚染を排除しました。

AIにコードを任せて、こんなことありませんか?

AI時代、Copilot、Claude Code、Cursor...。コードを生成してくれるAIは無数にある。生産性は確かに上がった。
しかし、ある日ふと気づく。「このコード、5年後に誰がメンテするんだ?」
「動いているからOK」と目をつぶってきたが、心のどこかで不安が消えない。このまま進んで本当に大丈夫なのか、と。

この記事をお勧めしない人

  • AIが出してきたコードを、そのまま使っても全く問題ないと考える人。
  • 「今動けばいい」が座右の銘で、5年後の保守性なんて他人事だと思う人。
  • 複数のAIエージェントを使い分けていて、それぞれが最適解を出してくれると信じている人。

もし一つでも当てはまらないなら、読み進める価値があるかもしれません。

エージェントが勝手に決めた「正解」の衝突

  • 各エージェントは自分の「目先の正解」を押し付けてくるが、プロジェクト全体の整合性は無視される土壌がある。
  • AIの実装を「動いているから」と無批判に受け入れ続けると、設計書とコードの乖離が修復不可能なレベルまで広がっていく。
  • ついに誰も全体像を把握できなくなり、些細な変更が予測不能な破壊を招く、100時間のデバッグ地獄が幕を開ける。

AIを黙らせる「SSoT違反」という武器

  • AIが出してきた「動いているっぽい何か」を論理的に評価し、自信を持って修正を命じるための武器が手に入る。
  • 「SSoT違反」という概念を用いてAIの暴走を制止し、汚染されたコードを特定・排除する 設計図 を習得できる。
  • この方法は机上の空論ではなく、まさにこのブログの開発中に発生したインシデントから得られた、泥臭くも強力な実践知である。
  • 公式ドキュメントには書かれていない、複数のエージェントが入り乱れる現代の開発現場における究極の生存戦略を習得できる。

このブログもそうでした

このブログの決済機能を実装中、まさにこの問題に遭遇しました。Stripeエージェントが「実装完了」と報告してきた瞬間、「何かおかしい」という直感が働きました。
この記事で、「設計書という正解の座標」「監査役としてのAI活用」「引き算の意思決定」という3つの武器を持ち帰れるように書きました。
深掘りして具体的な実装ログと判断基準を知りたい方は、詳細な方法論を確認できます。

📝 概要

Stripe決済機能の実装中に発生した「エージェント暴走」を、Claude Codeの監査機能で検出・修正した記録です。

発生環境

  • フレームワーク : Remix v2
  • ホスティング : Cloudflare Pages / Workers
  • 決済 : Stripe
  • 開発支援AI: Claude Code, VSCode Stripe拡張

登場するエージェント

エージェント 役割 特徴
VSCode Stripeエージェント 決済機能の実装 Stripe公式のベストプラクティスに従う
Claude Code プロジェクト全体の監査・統括 プロジェクト固有の設計ルールを把握

⚠️ インシデント発生:「実装完了」という報告

ある日、VSCodeのStripeエージェントに決済機能の実装を依頼しました。

しばらくして、エージェントから報告が届きました。「実装完了」と。

一見すると、きちんと動くコードが生成されていました。Payment Element方式でフロントエンドにStripe UIを埋め込み、バックエンドでPayment Intentを作成する。Stripeの公式ドキュメント通りの実装です。

しかし、報告を見た瞬間、違和感を覚えました。

「これ、プロジェクトの設計書と違う」

🔍 調査:Claude Codeに監査を依頼

直感を確かめるため、Claude Codeに監査を依頼しました。

差分のあるファイルからストライプ関係の実装を割り出して、
どんな実装がされているのか確認して

Claude Codeは冷徹に分析結果を報告しました。

問題点・懸念点:
1. spec-yamlなし - SSoT違反。設計ファイルが未作成
2. 金額ハードコード - ¥1,000がcheckout.tsxに直接記述
3. スタイル不整合 - style jsx使用(プロジェクト標準はTailwind CSS)
4. テストなし - TDDプロセス未実施

AIが、AIの罪を数え上げました。

この瞬間、確信しました。「あぁ、こいつ(Stripeエージェント)は、プロジェクトを殺しにきている」と。

💡 根本原因の特定:「正解」の衝突

原因 :
Stripeエージェントは「Stripeのベストプラクティス」に従っていた。しかし、それはこのプロジェクトの設計書とは異なる「正解」だった。

設計書の方針 :

# 設計書で定義していた方針
stripe_integration:
  method: "Checkout Session"  # Payment Elementではなく
  implementation: "Server-side only"  # フロントエンド実装なし
  reason: "保守性を優先。5年後も理解できるシンプルさ"

なぜこの問題が起きたか :

  • Stripeエージェントはプロジェクトの設計書を読まない
  • 各エージェントは自分の「ベストプラクティス」を押し付ける
  • 人間が明示的に監査しないと、設計との乖離は発見できない

これはスキルの問題ではありません。 責任の射程 の問題です。

視点 AIへのスタンス 責任の射程
素人 AIの出してきた「目先の正解」に飛びつく 「今、動けばいい」
プロ AIが差し出す「正解」の中に潜む「長期的な負債」を見抜く 「5年後の保守性」まで

🔧 解決策:「まずい。」の後の全削除

設計書との乖離を確認した瞬間、迷わず決断しました。

まずい。一点確認させて。

確認の結果、汚染されたコードを全削除しました。

【削除したファイル】
- app/lib/stripe.ts
- app/routes/checkout.tsx
- app/routes/webhook.tsx
- app/components/checkout/CheckoutForm.tsx
- app/components/checkout/ ディレクトリ全体

多くの人はここで「もったいない」と修正を試みます。それが100時間を溶かす入り口です。

なぜ全削除なのか :
構造が違うコードを修正して使い回すのは、癌細胞を移植するのと同じです。Payment Element方式のコードを、Checkout方式に「修正」することはできません。設計思想が根本から異なるからです。

設計書という正解の座標

爆死回避の最大の要因は、 実装前に適切な粒度の設計書を作成していたこと です。

# プロジェクトの設計書(抜粋)
subscription:
  payment_method: "Stripe Checkout"
  implementation:
    location: "Remix action function"
    pattern: "Server-side redirect"
  rejected_alternatives:
    - method: "Payment Element"
      reason: "フロントエンド複雑化を避ける"
    - method: "Custom payment form"
      reason: "PCI DSS準拠コストが高すぎる"
  design_principle: "5年後も保守可能なシンプルさを優先"

この「正解の座標」があったからこそ、「SSoT違反」という概念でAIを黙らせることができました。

SSoT (Single Source of Truth) 違反とは :
設計書で定義した内容と、実装が乖離している状態を指します。ClaudeMixでは、すべての設計判断は spec.yaml に記録され、実装はそれに従うことが求められます。

設計書の「黄金の粒度」

設計書は詳しすぎても、粗すぎてもダメです。

粒度 問題点
詳しすぎる 人間が疲弊する。更新されなくなる。
粗すぎる AIが暴走する。「どっちでもいい」と解釈される。

最適な粒度 :

  • 採用する方式 : 明記する(例: Checkout方式)
  • 不採用の方式と理由 : 明記する(例: Payment Element方式は複雑化するため不採用)
  • 実装場所 : 明記する(例: Remixのaction関数)
  • 実装の詳細コード : 書かない(AIに任せる)

この粒度であれば、AIは「どのアプローチを取るか」で迷わず、かつ人間は設計書の更新に疲弊しません。

監査役としてのAI

AIにコードを書かせるのではなく、AIに「構造の不自然さ」を白状させる。これが「監査役としてのAI」の使い方です。

監査フレームワーク

【監査依頼テンプレート】
「差分のあるファイルから[技術名]関係の実装を割り出して、
 どんな実装がされているのか確認して」

【期待する回答項目】
1. 実装されたファイルのリスト
2. 採用された設計パターン
3. 設計書との整合性
4. 潜在的な問題点

この監査を、 別のAIエージェント (Claude Code)に依頼することがポイントです。実装したエージェント(Stripeエージェント)に「問題ない?」と聞いても、「問題ありません」と答えるだけです。

主担当AIによる監査フロー

1. 専門エージェント(Stripe等)に実装を依頼
2. 「実装完了」の報告を受ける
3. 主担当AI(Claude Code)に監査を依頼
4. SSoT違反を検出したら、迷わず対処

このフローにより、各エージェントの「ベストプラクティス」がプロジェクト全体の設計と衝突することを防げます。

引き算の意思決定

「もったいない」という感情を捨てる。これがプロの判断です。

全削除の判断基準

【全削除すべき場合】
- 設計思想が根本から異なる(例: Payment Element vs Checkout)
- 修正するより書き直す方が早い
- 汚染されたコードを残すと、後続の実装も汚染される

【修正で対応できる場合】
- 変数名やスタイルの不整合
- 細かなロジックの調整
- テストの追加

今回のケースでは、「Payment Element方式」と「Checkout方式」は設計思想が根本から異なります。前者はフロントエンドに決済UIを埋め込み、後者はStripeのホスト型決済ページにリダイレクトします。この違いは「修正」では埋められません。

技術詳細:Remix × Stripe Checkout実装

全削除後、設計書に従って再実装しました。

サーバーサイド完結のCheckout Session

// app/routes/subscribe.tsx
import { redirect } from "@remix-run/cloudflare";
import Stripe from "stripe";

export async function action({ request, context }: ActionFunctionArgs) {
  const stripe = new Stripe(context.env.STRIPE_SECRET_KEY);

  // Checkout Sessionを作成(サーバーサイドのみ)
  const session = await stripe.checkout.sessions.create({
    mode: "subscription",
    payment_method_types: ["card"],
    line_items: [
      {
        price: context.env.STRIPE_PRICE_ID, // 金額はenv経由(ハードコードしない)
        quantity: 1,
      },
    ],
    success_url: `${context.env.APP_URL}/subscribe/success`,
    cancel_url: `${context.env.APP_URL}/subscribe/cancel`,
  });

  // Stripeの決済ページにリダイレクト
  return redirect(session.url!);
}

ポイント :

  • フロントエンドにStripe UIを埋め込まない
  • 金額は環境変数経由(SSoT遵守)
  • Remixのaction関数でサーバーサイド完結

なぜCheckout方式を選んだか

観点 Checkout方式 Payment Element方式
フロントエンドの複雑さ なし UIコンポーネント必要
PCI DSS準拠 Stripe側で完結 追加考慮が必要
5年後の保守性 高い(シンプル) 低い(依存関係多)
カスタマイズ性 低い 高い

ClaudeMixは「5年後も保守できるシンプルさ」を設計原則としています。カスタマイズ性よりも保守性を優先し、Checkout方式を採用しました。

🎓 学んだこと:3つの武器

武器1: 設計書という正解の座標

AIを暴走させないためには、 実装前に「正解の座標」を定義する ことが必要です。採用する方式、不採用の方式とその理由、実装場所を明記します。

武器2: 監査役としてのAI

AIにコードを書かせた後、 別のAIに監査させる 。実装したAIに「問題ない?」と聞いても無意味です。独立した視点での監査が必要です。

武器3: 引き算の意思決定

構造が違うコードを発見したら、 迷わず全削除 。「もったいない」という感情が、100時間のデバッグ地獄を招きます。

結論:AIを信じるな、設計を信じろ

AI時代、誰でも「動くコード」は書ける。

しかし、「5年後も保守できる構造」を守り抜けるのは、責任の射程が違うプロだけです。

AIは動くコードを書く。それは事実です。しかし、AIは5年後の保守性に責任を負いません。

責任を負うのは、あなたです。

この全削除・再実装の後にStripe本番審査という次の壁が待っていました。設計書を守って実装しても、審査プロセスは別の課題を突きつけてきます。

あなたのリポジトリへの適用

どちらを採用しますか?(1つ選択)

SAFETY|安全性を高める

SSoT違反(spec.yaml以外へのハードコード)が現在のコードに残っていないか確認する

調査:

  1. spec.yaml以外のファイル(TypeScriptファイル・設定ファイル)に設定値が直接記述されていないか確認せよ
  2. StripeのPrice ID・Webhook Secret等のStripe固有の値がspec.yaml経由で管理されているか確認せよ
  3. AIが生成したコードで新しいSSoT違反が混入していないか確認せよ

この内容をClaude Codeに貼り付けて実行します

SEPARATION|責務を分離

エージェントへの指示範囲がSSOT設計書を「座標」として明確化されているか確認する

調査:

  1. エージェントに与える指示がspec.yaml・設計書を参照しているか確認せよ
  2. エージェントが「設計書にないこと」を勝手に実装するリスクがある指示になっていないか確認せよ
  3. CLAUDE.mdまたはルールに「設計書を座標として使う」指示が明示されているか確認せよ

この内容をClaude Codeに貼り付けて実行します

外部コードのローカル実行にはリスクがあります。ブラウザ環境での実行を推奨します。