AIが量産するコードの品質をどう担保するか — 200コンポーネントで運用する4層の品質ゲート
このトピックを深掘りする
Claude Code活用
Claude Codeを使った大規模リファクタリング・CLAUDE.md設計・セッション管理の実践知
全4本中 4 本目。
次に読む記事
Claude Codeで200コンポーネントを一括修正した実録 — バグ分類・修正・検証の全工程
203個のインタラクティブコンポーネントに潜むバグを、Claude Codeで6コミット・100+ファイル一括修正した実践記録。分類・テンプレート化・検証の全工程を公開。
CLAUDE.mdを育てる — AIコラボレーション設定ファイルの3ヶ月の変遷
323コミットのプロジェクトでCLAUDE.mdを3ヶ月間更新し続けた記録。効いたルール、効かなかったルール、そして「助言的」設定の限界。
1セッション1タスク — Claude Codeのコンテキスト管理で学んだ原則
Claude Codeで203コンポーネントを開発する中で、「1セッション1タスク」が最も生産性に効いた原則だった。コンテキスト枯渇の実例と対策。
シリーズ全体の流れを見ながら、次に読む記事へ進めます。 初めての方はホームへ →
この記事で答える質問
AIにコードを量産させたとき、品質は何で担保すればいいか。このサイトは約200個(カタログ登録197個)のインタラクティブコンポーネントをAI駆動で開発・運用していて、その全部が同じ品質ゲートを通っている。この記事では、実際に運用している仕組みを構成ファイル名のレベルで公開する。
先に全体像を示す。ゲートは4層で、後の層ほど「人間の目」から遠い。
| 層 | ゲート | 止めるもの |
|---|---|---|
| 1 | pre-commitフック×4 | 機密漏洩・境界違反・生成物の手編集・AI臭文体 |
| 2 | データ不変条件テスト | 参照切れ・構造の破れ |
| 3 | ブラウザ実機スモーク | 「ビルドは通るが描画されない」 |
| 4 | 品質スコア+PR提案 | 生成コンテンツの直接公開 |
ポイントは、どの層もLLMに「ちゃんとやって」と頼む方式ではないことだ。全部が決定論的なコードで、同じ入力には同じ判定を返す。
前提: 人間が全行レビューできない量をAIが書く
コンポーネント約200個のうち、人間が全行を読んだものはごく一部だ。AI駆動開発のスループットは人間のレビュー帯域を必ず超える。そこで「レビューを増やす」のではなく、「レビューしなくても壊れない構造」に投資した。
具体的には、品質の定義を機械が判定できる形に分解する。機密が漏れていないか、参照が切れていないか、実際に描画されるか、文体がAI臭くないか——これらは全部、コードで検査できる。
層1: コミットを止める4つのフック
.githooks/pre-commit は4つの検査を直列に実行し、どれか1つでも落ちればコミット自体が失敗する。
bun run scripts/repo-guard.ts
bun run scripts/check-llm-client-boundary.ts
bun run scripts/check-generated-files.ts
bun run scripts/humanizer-check.ts --stagedそれぞれの役割は明確に分かれている。
repo-guard.ts— ステージされた差分に、私的メモのパスやop://(シークレット参照)が混ざっていないかを走査する。AIは作業中に参照した文脈を成果物へ写しがちで、公開リポジトリでは漏洩事故に直結するcheck-llm-client-boundary.ts— LLM SDKと機密ファイルローダーを同じファイルでimportしたら無条件で拒否する。「機密データがLLM APIに流れうる経路」を静的に遮断する不変条件check-generated-files.ts— sitemap・feed・llms.txtなどの生成物が、再生成コマンド以外の経路で変更されていたら止める。生成物の手編集は次の再生成で消える「時限バグ」になるhumanizer-check.ts— 後述
文体までゲートする — humanizer-check
一番変わっているのは4つ目だろう。humanizer-check.ts は日本語テキストの「AI特有の文体」を正規表現で検出する。実際のパターンの一部:
- 「実現・構築・推進」系の漢語に「しており」が続く接続(AIが多用する構文)
- 「今後の展開が注目され──」で締める定型文
- 「非常に」「極めて」を「重要・高い」に重ねる過剰修飾
- **見出し:** 説明形式の3連続(AIが好む箇条書きの癖)- 全段落が同じ書き出しで始まる均質構造
ブログ記事もAIが書くこのサイトでは、文体品質も「レビューで気づく」ではなく「機械が落とす」対象だ。ちなみにこの記事自体、このチェックを通過しないと公開できない。
層2: データの不変条件をテストとして固定する
コンテンツはすべて静的TypeScriptデータなので、構造の約束事をvitestの不変条件テストにしてある。例を挙げる。
- 全ブログ記事はちょうど1つのトピッククラスタに属する(
pillars.test.ts)— 0個でも2個でもテストが落ちる - 記事が参照するデモID・関連記事は、実在するカタログエントリに解決できなければならない(参照切れの検出)
dateModifiedはdateより過去であってはならない
AIに記事やコンポーネントを追加させると、登録漏れ・参照ミス・二重登録が一定確率で起きる。不変条件テストがあれば、それは「レビューで見つける間違い」ではなく「CIが赤くなる間違い」になる。間違いの発見コストが、人間の注意力から切り離される。
層3: 「描画された」をブラウザの実機で確認する
Canvasコンポーネントには特有の落とし穴がある。型が通り、ビルドが通り、Reactのレンダリングも成功して、画面が真っ黒というケースだ。ユニットテストでは捕まらない。
そこでPlaywrightのスモークテスト(tests/e2e/site-smoke.spec.ts)は、Canvasのピクセルを実際に読む。
const { data } = context.getImageData(0, 0, node.width, node.height)
// アルファ>0 かつ 輝度>0 のピクセルが一定数あるか数える「Canvas要素が存在する」ではなく「何かが実際に描かれた」を検証する。あわせて、ページ読み込み中のconsole errorをすべて捕捉してゼロ件であることを要求し、横スクロールが発生していないこともチェックする。CIはlint→テスト→ビルド→このブラウザスモークの順で流れ、mainマージ後のデプロイまで自動化されている。
層4: 生成コンテンツは点数とPRで二段に止める
記事の自動生成パイプライン(scripts/engine/)には、コード用とは別の公開ゲートがある。
- 品質スコア: 生成記事は評価を受け、
qualityScore >= 70を満たさないものは公開対象にならない(AUTO_PUBLISH_MIN_SCORE = 70) - PR提案モード: 閾値を超えた記事も、mainへ直接pushされることはない。日次パイプラインはPRを作るところまでで止まり、公開は人間のマージ操作で初めて起きる
つまり「作成」と「公開」を分離してある。自動化が壊れたときの最悪ケースが「変なPRが1本立つ」に閉じ込められていて、本番には何も起きない。実際、この分離に助けられたことがある。生成パイプラインの登録ファイル出力に欠陥が見つかったときも、壊れた変更はPRの中に留まっていて、本番は無傷だった。
設計思想: ルールはプロンプトではなくフックに置く
4層に共通する原則は1つで、静的に検査できるルールをプロンプトに書かないことだ。
「機密パスを含めないで」「参照を切らさないで」「AIっぽい文体を避けて」とCLAUDE.mdに書いても、LLMは確率的にしか従わない。しかも指示が増えるほど1つあたりの遵守率は下がる。同じルールをフック・テスト・CIに置けば、遵守率は100%で、プロンプトは「機械で判定できない判断」だけに使える。
AIへの指示を増やすことと、AIの出力を検査する機械を増やすこと。量産体制で効くのは後者だった。
まとめ
- AI量産コードの品質は、レビュー強化ではなく決定論的ゲートの多層化で担保する
- 層1: pre-commitで機密・境界・生成物・文体を止める
- 層2: データ構造の約束事は不変条件テストに固定する
- 層3: 「描画された」はブラウザ実機のピクセルで確認する
- 層4: 生成コンテンツは品質スコア+PR提案で「作成」と「公開」を分離する
- 原則: 静的検査できるルールはプロンプトでなくコードに置く
量産の実録はピラー記事: Claude Codeで200コンポーネントを一括修正した実録に、セッション運用の規律は1セッション1タスクの原則にまとめている。
よくある質問
- Q. AIが書いたコードは全部人間がレビューすべきですか?
- 量産体制では現実的ではありません。AI駆動開発のスループットは人間のレビュー帯域を超えるため、「レビューしなくても壊れない構造」への投資が必要です。機密漏洩・参照切れ・描画失敗・文体品質など、機械が判定できる性質に品質を分解し、フック・テスト・CIの決定論的ゲートに固定するのが現実解です。
- Q. プロンプト(CLAUDE.md)に品質ルールを書くのではだめですか?
- 静的に検査できるルールをプロンプトに書くのは非効率です。LLMは指示に確率的にしか従わず、指示が増えるほど1つあたりの遵守率は下がります。同じルールをpre-commitフックやテストに置けば遵守率は100%になり、プロンプトは機械で判定できない判断だけに使えます。
- Q. AIが書いた文章の「AI臭さ」も機械で検出できますか?
- 一定のパターンは正規表現で検出できます。定型の締め文・過剰修飾・特定の接続構文・箇条書きの癖・段落書き出しの均質さなど、AIが多用する文体には規則性があるためです。このサイトではhumanizer-checkというpre-commitフックが日本語テキストを走査し、検出されるとコミット自体が失敗します。
- Q. Canvasコンポーネントの「画面が真っ黒」問題はどう検出しますか?
- ブラウザ実機のスモークテストでCanvasのピクセルデータを実際に読み、アルファ値と輝度が0より大きいピクセルが一定数あるかを検証します。型チェック・ビルド・Reactのレンダリング成功だけでは「実際に描画されたか」は保証できないため、getImageDataによるピクセル検証が最後の砦になります。
- Q. AIが自動生成した記事はそのまま公開されますか?
- されません。生成記事は品質スコアの閾値(70点)を超えないと公開対象にならず、超えた場合もPull Requestの作成で止まります。本番への公開は人間のマージ操作で初めて起きる二段構えで、「作成」と「公開」を分離しています。