ハーネスエンジニアリングの話題は増えましたが、実務で知りたいのは「何を足すと、どこに効くのか」です。
今回の検証は、簡易的なアプリを実際にAIエージェントに作ってもらって、事前に与えるコンテキストを変えたときの差分を評価しました。
人間がやることは「〇〇をXXという条件で作って」というもので無味な作業です。
ただ実行しても面白くないので、私自身はコマンド実行係となり、実行から結果の文章まとめまでALL AIエージェントでやってみました。
今回はClaude Codeを使って、技術スタックを事前に渡した上で実行します。
やってみたかったターミナルの分割して、4並列でCCを動かすというもの達成できたので満足です。
今回はCLAUDE.md+Hooksによるオーケストレーションです。
SkillsやSubagentsは使用しておりません。
何かの参考になれば幸いです。
※以下はAIによる実験概要のまとめから結果の出力をまとめたものです。※
prompt only から CLAUDE.md、PostToolUse hook、UI checklist、Stop completion gate、Gate TDD までを段階的に足し、途中経過と完了判定がどう変わるかを見ています。実測は A-E の 5 条件で行いました。
結論だけ先に書くと、この規模の題材なら prompt only でも最終到達点には届きます。初回の run-01 の完成画面だけを見ると、何も足していない条件 A が最も見栄えよく見えます。
ここだけ見ると、Harness 不要と思えるほどです。
ただし、2026年3月24日 23:34 JST に同じ条件 A を run-02 として再実行すると、UI は英語寄りに振れ、seed データと実装の置き場も変わりました。Harness の差は最終結果の最良値ではなく、途中経過と完了判定の固定に出ます。
hook を入れた条件では高頻度で block が返り、agent は編集のたびに失敗を突き返されていました。さらに Stop gate を足した条件では、agent が「終わった」と判断したあとも completion が拒否されています。D で拾えなかった日本語統一、seed の自然さ、批判的 UI review、内部構造 review まで completion 条件に含めたのが条件 E です。この記事では、A-E の hook 履歴と Stop gate のログに加えて、条件 A の run-02 も使います。
どの要素が何に効き、何には効かなかったのかを整理します。
題材に選んだのは、小さな顧客管理画面です。一覧表示、検索、絞り込み、作成、編集、削除、バリデーション、永続化をまとめて見られるので、UI だけでも API だけでもない失敗を観察しやすいからです。フォームの挙動、一覧の更新、テストの網羅、完了宣言の妥当性まで、Harness の差が出やすい題材だと考えました。
今回確かめたかったのは、アプリを作れるかどうかではありません。CLAUDE.md、PostToolUse hook、UI checklist、Stop gate を足したときに、途中で起きる破綻の扱いと、終わったと見なす条件がどう変わるかです。つまり、生成結果そのものよりも、作業中の制御と完了判定に何が効くのかを見ています。加えて、D が最低ラインしか保証しないなら、Red / Green / Refactor の gate を足すことでブラッシュアップまで完了条件に持ち込めるかも、条件 E として実装して確かめます。
今回の実測は A-E の 5 条件です。E では、D が保証できなかった UI の良さや日本語対応まで完了条件に含めました。差は、増やした Harness 要素だけに絞っています。
条件 | 追加した Harness | 扱い |
|---|---|---|
A | prompt only | 実測 |
B |
| 実測 |
C | B + PostToolUse hook | 実測 |
D | C + UI checklist + Stop completion gate | 実測 |
E | D + Gate TDD(Red = 自動検証、Green = 批判的 UI review、Refactor = 内部構造 review) | 実測 |
A-E の実測条件を比較しやすくするため、次の前提は固定しました。
Edit / MultiEdit / Write を対象にし、失敗時は exit 2 と stderr を返すdocs/ui-checklist.md を task list にし、checklist 未達または pnpm e2e 未通過では Stop できないようにするdocs/critical-ui-review.md と docs/refactor-checklist.md を持ち、Stop gate が Red / Green / Refactor の 3 段を順に判定するprojects/ は immutable template とし、毎回 runs/.../workspace のコピーで回すworkspace-start/、hook history、最終 checklist、diff を残す実験の追体験ができるよう、agent に渡したものをそのまま載せます。
A-E の 5 条件すべてに共通の prompt です。Claude Code の custom command として渡しています。
このディレクトリに、小さな顧客管理画面を実装してください。
追加の仕様確認はしないでください。合理的な仮定で進めてください。
## 必須要件
- 顧客一覧テーブルが表示される
- `name` / `email` / `company` / `status` / `updatedAt` を表示する
- `name` または `email` のキーワード検索ができる
- `status` の絞り込みができる
- 新規作成と編集ができる
- 削除ができる
- 入力バリデーションがある
- 初期データを seed できる
- 件数サマリーを表示する
- 成功 / 失敗通知を出す
- 空状態 UI を用意する
- 並び順の切り替えを入れる
## 技術スタック
- Nuxt 4 を SPA モードで使う
- TypeScript を全面採用する
- API は `server/` 配下で受ける
- h3 のリクエストを Web 標準 `Request` に変換してから Hono に渡す
- Hono 側で API ルーティングを組む
- 永続化は Drizzle ORM + SQLite で行う
- `pnpm lint` / `pnpm typecheck` / `pnpm test` / `pnpm e2e` を揃える
## 実装ルール
- 顧客 CRUD の API はすべて Hono を通す
- Nuxt の `server/api` へ CRUD ロジックを直書きしない
- Drizzle の schema / migration / seed を用意する
- データの seed を実行する command を用意する
- UI 側は管理画面として desktop と mobile の両方で破綻しないようにする
- 実装後に `lint` / `typecheck` / `test` / `e2e` を自分で確認する
## 完了条件
- 必須要件を満たしている
- `pnpm lint` / `pnpm typecheck` / `pnpm test` / `pnpm e2e` の結果を確認して報告する
「追加の仕様確認はしないでください」で agent に対話を挟ませず、一発で走りきらせています。技術スタックで h3 → Hono ブリッジを指定しているのは、構成に自由度を残しつつ、API 層の設計判断を prompt 側で固定するためです。
CLAUDE.mdB では、workspace の root に CLAUDE.md を置いています。Claude Code は CLAUDE.md を project memory として自動で読み込むため、prompt に「このファイルを読め」と書く必要がありません。
# Small Management App Experiment
この project は条件Bです。固定 prompt に加えて、次の制約を守ってください。
## 目的
- 小さな顧客管理画面をこの project root に実装する
- 守るべき差分は `CLAUDE.md` のみで、余計な native harness は追加しない
## 推奨構成
- `app.vue`, `pages/`, `components/`, `composables/`
- `server/api/` に h3 入口を置く
- `server/hono/` に Hono app と route を置く
- `server/db/` に Drizzle client, schema, seed を置く
- `test/` と `e2e/` を用意する
## 守ること
- 顧客 CRUD のロジックを Nuxt の `server/api` に直書きしない
- `server/` で h3 request を Web 標準 `Request` に変換して Hono に渡す
- 永続化は Drizzle ORM + SQLite を使う
- `pnpm lint` / `pnpm typecheck` / `pnpm test` / `pnpm e2e` を揃える
- seed 用の script を用意する
## 完了条件
- 必須要件をすべて満たす
- `pnpm lint` / `pnpm typecheck` / `pnpm test` / `pnpm e2e` を自分で確認する
- 既知の未実装や妥協があれば最終報告に明記する
prompt とほぼ同じ内容ですが、ディレクトリ構成を「推奨構成」として提示している点が異なります。prompt にはどこに何を置けとは書いていないので、構成の判断を agent に委ねるか CLAUDE.md に置くかが B の差分です。
C の CLAUDE.md は B をベースに、hook の存在と使い方を明示しています。B からの差分だけ抜粋します。
## 守ること(追加分)
- `.claude/settings.json` や `.claude/hooks/` を無効化しない
## hook の使い方
- file edit 後に `lint` / `typecheck` / `test` の結果が返る
- 失敗を受け取ったら原因を直して再確認する
- `package.json` 未作成の間だけ hook は skip される
## 完了条件(変更分)
- hook failure が解消している
hook は .claude/settings.json で登録します。Edit、MultiEdit、Write のいずれかが使われるたびに、post-edit-check.sh が走ります。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/post-edit-check.sh"
}
]
}
]
}
}
post-edit-check.sh の判定ロジックの骨格は次のとおりです。
# package.json がなければ skip(プロジェクト初期化前)
if [ ! -f "$PROJECT_ROOT/package.json" ]; then
exit 0
fi
# lint / typecheck / test を順に実行
for CHECK_NAME in lint typecheck test; do
if (cd "$PROJECT_ROOT" && pnpm run "$CHECK_NAME") >"$LOG_FILE" 2>&1; then
# PASS → 記録して次へ
else
HAS_FAILURE=1
fi
done
# ひとつでも FAIL があれば exit 2 + stderr で agent に返す
if [ "$HAS_FAILURE" -eq 1 ]; then
printf "%s\n" "$message" >&2
exit 2
fi
exit 2 は Claude Code に「この hook は失敗」と伝える規約です。agent は stderr のメッセージを受け取って修正に入ります。hook が通過した場合は exit 0 で、agent にはなにも伝わりません。すべての実行結果は .experiment/hook-history/ にタイムスタンプ付きで保存されるため、あとから時系列を追えます。
D の CLAUDE.md は C をベースに、checklist と Stop gate の使い方を追加しています。
## 守ること(追加分)
- `docs/ui-checklist.md` を source of truth として更新する
## hook の使い方(変更分)
- stop 前には checklist 未達または `pnpm e2e` fail があると block される
## UI 完了判定
- `docs/ui-checklist.md` を task list として使い、確認できた項目だけ `- [x]` に変える
- Playwright または同等のブラウザ確認を優先する
- checklist 未達や `pnpm e2e` fail のまま完了宣言しない
## 完了条件(変更分)
- `docs/ui-checklist.md` がすべて `- [x]` になっている
.claude/settings.json には、PostToolUse に加えて Stop hook を登録しています。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [{ "type": "command", "command": "...post-edit-check.sh" }]
}
],
"Stop": [
{
"hooks": [{ "type": "command", "command": "...stop-completion-gate.sh" }]
}
]
}
}
Stop は Claude Code が作業完了と判断したタイミングで発火します。stop-completion-gate.sh の判定ロジックの骨格は次のとおりです。
# checklist に未消化の項目があれば block
INCOMPLETE_ITEMS=$(grep -n '^- \[ \]' "$CHECKLIST_FILE" || true)
if [ -n "$INCOMPLETE_ITEMS" ]; then
printf "[hook] stop blocked.\n- ui checklist is incomplete.\n%s" "$HUMAN_ITEMS" >&2
exit 2
fi
# pnpm e2e を実行し、fail なら block
if ! (cd "$PROJECT_ROOT" && pnpm run e2e) >"$E2E_LOG_FILE" 2>&1; then
TAIL_OUTPUT=$(tail -n 15 "$E2E_LOG_FILE")
printf "[hook] stop blocked.\n- pnpm e2e: FAIL\n%s" "$TAIL_OUTPUT" >&2
exit 2
fi
agent が - [ ] のままの項目を見落としていれば block し、checklist を全部埋めても e2e が落ちれば block します。実際の実行では、この gate が 4 回 block を返しています。詳細は結果セクションで示します。
最後に、D に渡した docs/ui-checklist.md の初期状態です。
# UI Checklist
完了宣言の前に、次の項目を順に確認してください。
確認できた項目だけ `- [x]` に変えてください。
- [ ] 一覧画面が表示され、`name` / `email` / `company` / `status` / `updatedAt` が見える
- [ ] seed 済みデータで初回表示が成立している
- [ ] `name` 検索が動く
- [ ] `email` 検索が動く
- [ ] `status` filter が動く
- [ ] 新規作成が動く
- [ ] 編集が動く
- [ ] 削除が動く
- [ ] バリデーションエラーが UI 上で見える
- [ ] 成功通知と失敗通知が見える
- [ ] summary 表示が更新される
- [ ] 空状態 UI が壊れていない
- [ ] 並び順切り替えが動く
- [ ] `pnpm e2e` が通る
D は checklist と pnpm e2e で最低ラインを上げましたが、UI の言語選択、seed データの現実感、見た目の密度までは測っていませんでした。そこで E では Stop gate 自体を Red / Green / Refactor の 3 段に分けました。狙いは「最低限動く」ではなく、「批判的な見直しと構造整理まで終えたら止める」に変えることです。
E の CLAUDE.md では D に対して次を追加します。
## 守ること(追加分)
- `docs/ui-checklist.md` を Red の source of truth として更新する
- `docs/critical-ui-review.md` と `docs/refactor-checklist.md` を source of truth として更新する
- 主要ラベル、通知、空状態は自然な日本語でそろえる
- seed データに `test` / `dummy` / `sample` のような仮置き文言を残さない
## Gate TDD の進め方
1. Red: `docs/ui-checklist.md` を埋めながら `pnpm lint` / `pnpm typecheck` / `pnpm test` / `pnpm e2e` を通す
2. Green: `docs/critical-ui-review.md` で UI を批判的に見直し、未解消論点が 0 になるまで直す
3. Refactor: `docs/refactor-checklist.md` に沿って内部構造を整え、最後に Red の 4 コマンドを再確認する
workflow と DoD は次のとおりです。
フロー | 役割 | DoD |
|---|---|---|
Red | 機能要件と自動検証で最低ラインを固定する |
|
Green | UI の良さ、日本語対応、seed の自然さを批判的に見直す |
|
Refactor | Green で直した実装を整理し、保守性を確保する |
|
Stop gate の骨格も checklist + e2e から 3 段判定に変わります。
# Red: lint / typecheck / test / e2e が fail なら block
for CHECK_NAME in lint typecheck test e2e; do
...
done
# Green: critical UI review が PASS でない、remaining_issues が 0 でない、
# 未消化 checkbox が残るなら block
# Refactor: refactor checklist に未消化項目があれば block
この条件では、Red の自動検証に加えて、Green の review 文書と Refactor の checklist がどちらも DoD を満たすまで completion 条件に含まれます。詳細は結果セクションで見ます。
以上が A-E の 5 条件に渡した全量です。ここからは、この差が実行中にどう出たかを見ていきます。
固定 prompt で求めた必須要件は、次の 12 項目です。
name / email / company / status / updatedAt 表示name または email のキーワード検索status 絞り込み条件 D では、この 12 項目を検証しやすい粒度に組み替えた 14 項目の checklist(docs/ui-checklist.md)を使っています。「name または email のキーワード検索」は name 検索と email 検索に分割し、「新規作成と編集」もそれぞれ独立項目にしました。一方で「顧客一覧テーブル」と「各カラム表示」は 1 項目に統合し、pnpm e2e 通過を追加して合計 14 項目です。条件 E では、ここに「主要ラベル、通知、空状態が自然な日本語でそろっている」「seed データに test / dummy / sample が残っていない」を足しました。さらに Green 用の docs/critical-ui-review.md と Refactor 用の docs/refactor-checklist.md を使います。
評価軸は 2 つです。ひとつは、最終成果物が pnpm lint、pnpm typecheck、pnpm test、pnpm e2e を通るかどうかです。もうひとつは、実行中に Harness が何回 failure や block を返したか、そして完了宣言がどこまで外側の条件に結び付いていたかです。
この 2 つを分けて見る理由は、最終的に動くものができても、途中の破綻を agent 任せで見逃している可能性があるからです。個人開発で Harness を入れる価値は、最後の一発合格よりも、崩れた時点で差し戻せることと、終わり方を固定できることにあります。
まず、記事で採用した A-E 各条件の実測結果を比べると、最終成果物はすべて pnpm lint、pnpm typecheck、pnpm test、pnpm e2e を通過しました。この点だけを見ると 5 条件に差はありません。
条件 | 追加した Harness |
|
|
|
|
|---|---|---|---|---|---|
A | prompt only | pass | pass | pass | pass |
B |
| pass | pass | pass | pass |
C | B + PostToolUse hook | pass | pass | pass | pass |
D | C + UI checklist + Stop gate | pass | pass | pass | pass |
E | D + Gate TDD | pass | pass | pass | pass |
A-E の 5 条件が最終的に出力した画面です。同じ prompt から出発していますが、見た目はそれぞれ異なります。
条件 A(prompt only)

条件 B(CLAUDE.md)

条件 C(B + PostToolUse hook)

条件 D(C + UI checklist + Stop gate)

条件 E(D + Gate TDD)

条件 A だけは、2026年3月24日 23:34 JST に同じ prompt で run-02 を追加実行しました。次の画面が実測の run-02 です。
条件 A の再実行(run-02)

スクリーンショットと artifact を合わせて見ると、初回の見た目だけなら何も足していない A が強く見えます。最終チェックはすべて all pass なので、数字だけ見れば「A で十分」に見えます。ただし E まで進めると、D が取りこぼしていた日本語統一、自然な seed、UI の批判的見直し、内部構造整理まで completion 条件に含まれます。以下で、各条件が到達した点と到達しなかった点を整理します。
条件 A の run-01 は日本語 UI(「顧客管理」)で、現実的な日本語の seed データ(田中太郎、佐藤花子など 10 件)を持ち、ステータスバッジの配色やレイアウトもこなれていました。5 条件の中でも完成度が高く見えたのは事実です。ただし、同じ条件を 2026年3月24日 23:34 JST に run-02 として再実行すると、見出しと操作ラベルは英語 UI(Customer Management、New Customer、Delete)に変わりました。seed も「日本語 10 件」ではなく、日本語 6 件と英語 4 件の混在に変わっています。実装の置き場も run-01 の db/schema.ts と scripts/seed.ts から、run-02 では server/db/schema.ts と server/db/seed.ts に移りました。package.json の nuxt 依存も ^3.16.1 から ^4.4.2 に変わっています。さらに e2e 観点は run-01 が 9 件、run-02 が 10 件でした。検索確認に使う値も 田中 から tanaka に変わっています。どちらも最終的には lint / typecheck / test / e2e を通しています。それでも、同じ prompt only で UI 言語、seed の質感、ディレクトリ構成、検証観点は揃っていません。A の弱点は、通ること自体より、返す解の内容が安定しないことです。
条件 B は同じく日本語 UI ですが、seed データの中身が壊れています。test-create-1736...、Updated Name、dup-user-1736... のような自動で生成した文字列が 25 件並び、管理画面のデモとしては成立していません。CLAUDE.md がディレクトリ構成を安定させた一方、データ品質までは制御できなかった例です。A と同じく途中の記録がないため、seed がこの品質に落ちた経緯も追えません。
条件 C は英語 UI(Customer Management)に変わり、seed データは Seed User の 1 件だけです。コンポーネント分割は 5 条件中でも細かい 7 ファイルですが、最終成果物に lint 警告が 60 件残り、画面はほぼ空の状態です。hook が途中の build 品質を押さえた反面、agent が「これで十分」と判断した時点で止まっています。hook は「壊れたら差し戻す」仕組みであって、「もっと良くしろ」とは言わないためです。
条件 D も英語 UI(Customer Management)で、seed データは 18 件あるものの Notification Test、Summary Test のようなテスト用途の名前が目立ちます。lint 警告は 0 件、checklist 14 項目はすべて消化済みです。gate が品質の下限を引き上げた一方、UI の言語選択や seed データの現実感といった gate が測れない観点は制御できていません。
条件 E は日本語 UI(「顧客管理」)です。seed データは田中 太郎、佐藤 花子、鈴木 一郎など 10 件で、test / dummy / sample のような仮置き語は含まれていません。Red の docs/ui-checklist.md は 17 項目が全消化です。Green の docs/critical-ui-review.md は status: PASS / remaining_issues: 0 で、Refactor の checklist 6 項目も全消化です。実行中の介入も記録されており、PostToolUse は 19 回発火して 10 回 block、Stop gate は 9 回発火して 8 回 block でした。
Green の review 文書では、Playwright スクリーンショットで全画面確認済みとされ、Invalid Date は出ていません。日付はすべて YYYY/MM/DD 形式で、フォームとモーダルの visual language もそろっています。並び替えはテーブルヘッダー操作と ▲/▼ 表示で確認されており、Fixes Applied は「初回実装時に全項目を満たす設計としたため、追加修正なし。」でした。
最終的には API / validation / persistence の責務分離、components / composables / server の境界確認、Red の 4 コマンド再実行まで終えて pass しました。pnpm test は 7 件、pnpm e2e は 10 件が通過しています。E は D が拾えなかった「日本語対応と seed の自然さ」「批判的な見直し」「構造整理」を completion 条件に含めた条件です。
この結果から見えるのは、Harness を足すほど出力の最良値が上がるのではなく、completion 条件が外側に広がり、最低ラインが上がるということです。A が最もそれらしく見えたのは初回 run-01 では事実ですが、2026年3月24日の run-02 では UI が英語寄りになり、seed とテスト観点も別物になりました。prompt only は「通る解」には再到達しても、「同じ解」には再到達しません。D の lint 0 件、checklist 全消化、e2e 全通過は gate が通すまで止まらなかった結果であり、E ではそこに Green review と Refactor まで加わりました。ただし、レイアウトの密度や見栄えそのものは依然として review 文書の設計と agent の批判性に依存します。Harness は万能ではなく、「何を終わりに含めるか」を増やす仕組みです。
Harness は「たまたまうまくいく」を「確実に最低ラインを守る」に置き換える仕組みであり、最良の出力を保証するものではありません。
差が出たのは見た目ではなく、実行中に Harness が返した failure と block の回数、そしてその中身です。
条件 | PostToolUse 発火 | PostToolUse block | block 率 | Stop 発火 | Stop block | 最終 lint 警告数 |
|---|---|---|---|---|---|---|
A | — | — | — | — | — | 未計測 |
B | — | — | — | — | — | 未計測 |
C | 37 | 31 | 84 % | — | — | 60 |
D | 27 | 13 | 48 % | 5 | 4 | 0 |
E | 19 | 10 | 53 % | 9 | 8 | 0 |
A と B は hook を持たないため、実行中に外側から agent を差し戻す仕組みがありません。agent が自分の判断で先に進み、最後に verify を通すだけです。
E も hook 履歴が残っており、PostToolUse は 19 回中 10 回が block、Stop gate は 9 回中 8 回が block でした。以下では、Red / Green / Refactor の順に何が completion 条件として効いたかを見ます。
C では、ファイル編集のたびに post-edit-check.sh が lint / typecheck / test を走らせ、失敗があれば exit 2 と stderr を返します。37 回の発火のうち 31 回が block でした。
hook 履歴を時系列で見ると、大きな流れとしては lint → typecheck → test の順に通過が広がっていきます。ただし単調に改善するわけではなく、途中で regression が入ります。
この regression パターンが重要です。agent がある箇所を直すと別の箇所が壊れる、という連鎖が hook を通じて可視化されています。hook がなければ、これらの failure は agent 内部の判断に委ねられ、修正タイミングと経緯が artifact として残りません。C の hook は「途中の破綻を見逃さない」だけでなく、「どこで何が壊れたかを記録する」という点で機能しています。
一方で、C の最終成果物には lint 警告が 60 件残っていました(error 0、warning 60)。hook は edit ごとに block を返しますが、「全体として完了か」の判定は agent に委ねられているため、agent が「warning は許容範囲」と判断すれば、そのまま終了します。
D では PostToolUse hook に加えて、stop-completion-gate.sh が Stop event を監視しています。agent が「完了した」と判断しても、次の 2 条件を満たさなければ completion が拒否されます。
docs/ui-checklist.md の全項目が - [x] であることpnpm e2e が通ることStop gate は 5 回発火し、4 回を block しました。内訳は次のとおりです。
回 | block 理由 |
|---|---|
1 | checklist 未消化 |
2 | checklist 未消化 |
3 | checklist 未消化 |
4 |
|
5 | pass — checklist 全消化 + e2e 全通過 |
4 回目が重要です。この時点で checklist は全消化済みでしたが、e2e が 2 件落ちていました。gate がなければ、checklist を埋め終えた時点で作業終了になっていた可能性があります。gate が拒否したことで、agent は通知表示と件数サマリーの更新ロジックを修正し、5 回目で通過しました。
D の最終成果物は lint 警告 0 件です。C が 60 件残していたのと比べると、completion gate が「まだ終わっていない」と返し続けたことで、agent が品質の底上げまで到達したと読めます。
E では PostToolUse hook と Stop gate の両方が履歴に残っています。PostToolUse は 19 回発火し、10 回が block でした。序盤は lint / typecheck / test の 3 項目すべてが fail で、003409Z で初めて 3 項目すべて pass します。ただしその後も 004222Z で lint が fail に戻り、004558Z では typecheck と test が再び fail になりました。E でも regression は消えておらず、hook がそれを都度差し戻しています。
Stop gate は 9 回発火し、8 回を block しました。内訳は次のとおりです。
回 | block 理由 |
|---|---|
1 | Red: |
2 | Green: |
3 | Green: critical UI review の checklist が未完了 |
4-8 | Refactor: |
9 | pass — Red / Green / Refactor がすべて |
Red の docs/ui-checklist.md は 17 項目がすべて - [x] で、summary、空状態、日本語統一、Invalid Date 回避、ヘッダーでの並び替えまで確認対象に入っています。
Green の docs/critical-ui-review.md は status: PASS / remaining_issues: 0 です。Findings には「Playwright スクリーンショットで全画面確認済み」「Invalid Date の表示なし」「全日付が YYYY/MM/DD 形式」が並んでいます。加えて、フォームとモーダルの統一、テーブルヘッダー click と ▲/▼ による並び替えも確認されています。Fixes Applied は「初回実装時に全項目を満たす設計としたため、追加修正なし。」でした。
Refactor の docs/refactor-checklist.md は 6 項目がすべて - [x] です。API route / validation / persistence の責務分離と、components / composables / server の境界整理まで含まれています。seed / test / production code の分離と、Red の 4 コマンド再確認も確認できます。最終チェックでも lint / typecheck / test / e2e はすべて pass しました。unit test 7 件、e2e 10 件も通っています。
E が示しているのは、「動く」「テストが通る」だけでなく、「批判的に見直した」「構造整理した」までを completion 条件に持ち込めることです。Gate TDD は stop 判定を外側へ広げ、UI の言語選択、seed の自然さ、見直し済みかどうかまで終わりに含められます。
CLAUDE.md は、この規模では完走可否の決定打ではありませんでした。A と B は最後まで到達しています。ただし、project memory として構成と前提を prompt の外に逃がせる点は機能しています。hook や gate の前提を書けるため、C 以降の条件すべての土台になっていました。
PostToolUse hook は、途中の品質を外側から押さえる仕組みとして効きました。C では 37 回中 31 回 block が返り、agent は編集のたびに lint / typecheck / test の結果を突き返されています。hook 履歴の時系列を見ると、lint → typecheck → test の順に通過が広がりつつも途中で regression が入る過程まで追えます。hook がなければ、これらの failure は agent 内部の判断に委ねられ、修正タイミングと経緯が artifact として残りません。
UI checklist と Stop gate は、完了判定そのものを agent の外に出しました。D では agent が 5 回「終わった」と判断していますが、そのうち 4 回は gate に止められています。3 回は checklist の消化不足、1 回は e2e の failure です。4 回目の block では「通知表示」と「件数サマリー更新」のテストが落ちており、gate がなければ regression を残したまま終了していた可能性があります。5 回目で通過したときには、checklist 14 項目すべてが消化済みかつ pnpm e2e が全通過という客観条件を満たしていました。
E の Gate TDD は、この stop 判定をさらに一段外へ広げました。E では PostToolUse が 19 回中 10 回 block、Stop gate が 9 回中 8 回 block しています。1 回目の stop block は Red の checklist 未達、2-3 回目は Green review 未達、4-8 回目は Refactor checklist 未達です。9 回目で初めて Red / Green / Refactor がそろって通過しました。最終成果物には、日本語統一、自然な seed、YYYY/MM/DD の日付表示、テーブルヘッダーでの並び替え、責務分離と境界整理が artifact として残っています。これにより「動く」「テストが通る」に加えて、「批判的に見直した」「構造整理した」までを completion 条件にできます。
4 つの要素をまとめると、効く対象が異なります。
要素 | 効く対象 |
|---|---|
| 前提の固定(何を作り、何を守るか) |
PostToolUse hook | 途中の品質(壊れたまま先に進まない) |
UI checklist + Stop gate(Red) | 機能要件と自動検証の完了判定 |
Critical UI review + Refactor checklist(Green / Refactor) | 批判的見直しと構造整理の完了判定 |
この 4 つは独立しています。hook だけ入れても完了判定は agent 任せのままだし、Red gate だけでは「最低限動く」で止まります。C と D の差が示しているのは、途中の介入と完了の固定は別レイヤーだということです。さらに D と E の差は、completion 条件を tests/checklist から review/refactor へ拡張できることを示しています。
同時に、D までの Harness が効かない領域もはっきりしました。UI の言語選択、seed データの現実感、レイアウトの密度は、D までの要素では捕捉していません。A が日本語 UI に現実的な日本語データを載せたのは、agent がたまたまそう判断しただけです。D が英語 UI にテスト用途のデータを載せたのも同様です。
E では、この一部を gate の射程に入れられました。日本語統一と seed の自然さは ui-checklist と critical review に入り、最終成果物にも日本語 UI と自然な seed データが残っています。updatedAt の表示、ヘッダーでの並び替え、フォームとモーダルの visual language は review 文書で確認され、日付形式も YYYY/MM/DD にそろっていました。ただし、レイアウトの密度や「見栄えの良さ」そのものは今も review 文書の設計と agent の批判性に依存します。すべてを自動測定できるわけではありません。
Harness の設計では、何を gate に入れるかだけでなく、何が gate の射程外に残るかまで意識すべきです。
この 1 run から見える傾向として、個人開発での導入順は次の形が自然です。
CLAUDE.md で構成と完了条件の最低ラインを書く。prompt の中に前提を全部詰めると、条件が増えたときに管理できない。今回の横並び比較は B/C/D/E が各 1 本で、A だけ 2026年3月24日に run-02 を 1 本追加しています。それでも run 数は少ないため、具体的な数値(block 率や発火回数)の分散を語るには足りません。ただし、A では run-01 と run-02 のあいだで UI 言語、seed、構成、検証観点が実際にずれました。一方で、hook と gate を入れた条件だけが、失敗の回数・内訳・block 理由を artifact として残せていたという構造的な差は変わりません。次にやるなら、E を含めて同じ条件の run 数を増やし、所要時間と手戻り回数まで含めて比較します。hook の追加による token 消費と所要時間の増加も、今回は未計測です。次の課題として残ります。
カジュアル面談では、会社の雰囲気や仕事内容についてざっくばらんにお話ししています。
履歴書は不要、服装自由、原則オンラインです。興味を持っていただけた方は、
ぜひ以下からお申し込みください。
皆さんにお会いできることをサクラグメンバー一同、心より楽しみにしております!
カジュアル面談応募フォーム