PlanGate

Hook Enforcement — runtime で強制すべき不変条件

Status: v5(Implementation: 10/10 hooks Done — #169 完走 — #157 で 3 hook、#169 セッション A で 2 / B で 3 / C で 2 = 計 10 hook、3 mode 設計) Hook 数の現状(v8.7.0 以降): 本書は v8.5.0 時点の 10/10 hooks スナップショット。 v8.6.0 で EH-8check-metrics-privacy.sh、metrics privacy 強制)、 v8.7.0 で EH-9check-delegation-commit-boundary.sh、TASK-0073 F2)を追加し、 現状は EH-1〜EH-9 + EHS-1〜EHS-3 = 12/12。本書本文の表は v8.5.0 構成のまま 維持し、追加分の詳細はそれぞれの実装 PR / CHANGELOG / bin/plangate doctor 出力を参照。

EH-12(追加・配線は Human apply 待ち): protected branch 上の破壊的 git 操作 block(check-git-destructive.sh)。hook 本体(非 HO の scripts/ 直下)は 実装・テスト済みだが、PreToolUse 配線は scripts/apply-eh-git-destructive-guard.sh --applyHuman-owned)の実行後に 有効化される。番号は EH-10 / EH-11 が既に予約済み(#760 PostToolUse 軽量品質 チェック / #762 Stop 軽量 verify の「候補」名として .claude/settings.example.json のコメントで使用、 かつ EH-10 は docs/rfc/ai-self-set-gate-hook-enforcement.md の RFC Draft が保持)のため、衝突しない最小の空き番号として EH-12 を採番した。

実装と物理配線の区別(2026-06-10 棚卸し / 2026-06-27 更新): 12/12 は 「スクリプト実装 + 単体テスト済み」を指す。発火経路(settings.json / .codex/hooks.json / CI / bin/plangate)への物理配線は 11/12(PreToolUse/CI 配線 6

発火条件の供給(EPIC #527 follow-up・配線済み): EHS-1/2/3 の発火条件 PLANGATE_VALIDATION_BIAS=strict は、bin/plangate verify / handoff --verify--profile <key> を受理し model-profiles.yamlvalidation_bias を解決して内部 export する(TASK-0147 / #644 で配線・適用済み)。env で明示注入済みなら尊重し、 normal/lenient profile・無指定では非発火(既存挙動不変)。未知 key / yaml 欠落時は normal fallback + stderr 警告(scripts/_resolve_validation_bias.py)。

配線状態 Hook 発火経路
✅ 配線済み(6) EH-1 / EH-2 / EH-3 / EH-6 / EH-9 Claude PreToolUse + Codex hooks.json
  EH-8 CI(metrics-privacy.yml)+ doctor + codex-guarded
✅ CLI 配線(5、apply 後) EH-4 / EH-5 bin/plangate verify —EH-4: V-1 前 strict / EH-5: V-1 後 warn(TASK-0143)
  EHS-1 bin/plangate verify —V-3 不合格時に validation_bias=strict で block(TASK-0145 増分1)
  EHS-3 bin/plangate verify —V-1 FAIL 時に fix-loop increment + validation_bias=strict で上限超過 block(TASK-0146 増分2)
  EHS-2 bin/plangate handoff --verify —handoff.md 6 要素不足を validation_bias=strict で block(TASK-0146 増分3)
⏳ doctor 可視化のみ(1) EH-7 bin/plangate doctor CLI Hook Wiring セクション + 手動推奨(#500 後続)

関連: responsibility-boundary.md / tool-policy.md / model-profiles.md 実装: scripts/hooks/check-plan-exists.sh / check-c3-approval.sh / check-plan-hash.sh / check-test-cases.sh / check-verification-evidence.sh / check-forbidden-files.sh / check-merge-approvals.sh / check-v3-review.sh / check-handoff-elements.sh / check-fix-loop.sh 設定例: .claude/settings.example.json / 単体テスト: tests/hooks/run-tests.sh

0. 運用モード別の強制実態(CLI 依存度 / 2026-06-28 現状把握)

各強制は「いつ発火するか」が経路ごとに異なる。とくに CLI(bin/plangate)を 通さない運用では、CLI 層の強制(EH-4 / EH-5 / EHS-1/2/3)は一度も発火しない

「ローカル強制」の前提に注意: 層 A(Claude PreToolUse)/ 層 E(Codex hooks)は Claude Code / Codex などの AI ツールを介して編集・コミットしたときのみローカル発火する。 エディタで直接ファイルを編集して git で直接コミットする完全手動運用では層 A/E も 発火しない(その場合の最終防壁は層 B の CI = PR/push トリガー)。以下の「手動 / AI 任せ」は 主に「AI ツールは使うが bin/plangate CLI は回さない」運用を指す。

発火層の分類

強制 発火契機 CLI を使わない運用での実態
A. Claude PreToolUse(自動・bypass 不能) EH-1 / EH-2 / EH-3 / EH-6 / EH-9 + 承認トークン直書き block(TASK-0123)+ EH-12(apply 後) Edit / Write / Bash のたび ✅ 常時発火
B. CI(自動・bypass 不能) EH-8(metrics privacy)/ settings drift / schema-validate / skip-ack / pr-issue-link PR / push ✅ 常時発火
C. CLIbin/plangate 実行時のみ) EH-4 / EH-5 / EHS-1 / EHS-2 / EHS-3 verify / handoff --verify実行したときだけ 🔴 休眠(CLI 未実行なら不発)
D. 外部設定 EH-7(マージ 2 段階レビュー) main へのマージ 🔶 GitHub branch protection 設定に依存(Human-owned admin)
E. Codex hooks EH-3 / check-script-basename Codex セッション中の apply_patch / Bash 等 (Claude Code 運用では非該当)

含意

休眠ゲートを CLI 非依存で常時強制したい場合の選択肢(PR トリガーの CI 移植など)は 別途設計判断(新規 PBI / EPIC #527 の後続)とする。本節は現状把握であり方針は未確定。

1. 目的

PlanGate の Iron Law のうち runtime 強制可能な不変条件(現状 #1〜#7 相当)を、プロンプトに頼らず runtime で決定論的にブロック する。プロンプト薄型化(PBI-116-01 で達成)と両立して、強制力を維持する。なお Iron Law #8(出典照合)は決定論的 hook 化が困難なため、プロンプト + diff-audit(旧 self-review、ソフト面)で担保し runtime hook の対象外とする。

2. 強制すべき不変条件(一覧)

responsibility-boundary.md § 5 と整合。最低 6 件:

EH-1: plan.md なし production code 編集ブロック

EH-2: C-3 承認なし exec ブロック

EH-3: plan_hash 改竄検知

EH-4: test-cases.md なし V-1 ブロック

EH-5: 検証ログなし PR 作成ブロック

EH-6: scope 外ファイル編集検知

EH-7: 2 段階レビューなしマージブロック(推奨)

EH-9: 委譲 commit/push 境界検知(F2 / TASK-0073)

EH-12: protected branch 上の破壊的 git 操作ブロック

3. validation_bias: strict 時の追加条件(EHS)

設計ステータス: 配線・適用済み(TASK-0145 / 0146 / 0147)。スクリプト実装に 加え、発火条件 validation_bias: strictbin/plangate に配線済み。発火条件の供給は --profile <key>model-profiles.yamlvalidation_bias 解決 → PLANGATE_VALIDATION_BIAS 内部 export(TASK-0147 / #644)。 CLI 依存度の注意: これらは CLI 層(§0 の層 C)であり、bin/plangate verify / handoff --verify を実行したときのみ発火する(手動 / AI 任せ運用では休眠。CI 移植は TASK-0148 で検討)。

Model Profile の validation_bias: strict プロファイル(gpt-5_5_pro 等)では、 上記 EH-1〜EH-7 に加えて以下 3 件を追加で強制:

EHS-1: V-3 外部レビュー必須化

EHS-2: handoff.md 必須 6 要素チェック

EHS-3: V-1 fix loop 上限超過 escalation

EHS 発火条件の供給(配線済み)

validation_bias: strictdocs/ai/model-profiles.yaml で定義され、実行時の供給は 配線済み(TASK-0147 / #644): bin/plangate verify / handoff --verify--profile=<key> (等号形式)を受理し、model-profiles.yamlvalidation_biasscripts/_resolve_validation_bias.py で解決して PLANGATE_VALIDATION_BIAS を内部 export する。env で明示注入済みなら尊重し、 normal/lenient・無指定では非発火(既存挙動不変)。未知 key / yaml 欠落時は normal fallback + stderr 警告。

残課題: 上記は CLI 層(§0 層 C)のため、CLI を回さない運用では休眠する。PR トリガーの CI へ EHS-1 / EHS-2 を移植して CLI 非依存で常時強制する案は TASK-0148 で検討(EHS-3 は CLI プロセス計数のため CLI 維持)。

4. 実装(#157 で 3 hook + #169 で 7 hook = 計 10 hook、すべて完了)

Hook 種別 実装 由来
EH-1(plan.md なし production code 編集 block) PreToolUse hook scripts/hooks/check-plan-exists.sh #169 セッション A / TASK-0056
EH-2(C-3 未承認 exec block) PreToolUse hook scripts/hooks/check-c3-approval.sh #157 / TASK-0048
EH-3(plan_hash 改竄検知) PreToolUse hook + CLI scripts/hooks/check-plan-hash.sh #169 セッション A / TASK-0056
EH-4(test-cases.md なし V-1 block) CLI(V-1 前で呼び出し) scripts/hooks/check-test-cases.sh #169 セッション B / TASK-0057
EH-5(検証ログなし PR 作成 block) CLI(PR 作成前で呼び出し) scripts/hooks/check-verification-evidence.sh #169 セッション B / TASK-0057
EH-6(scope 外ファイル編集検知) PreToolUse hook + CLI scripts/hooks/check-forbidden-files.sh #169 セッション B / TASK-0057
EH-7(2 段階レビューなしマージ block) CLI(マージ前で呼び出し) scripts/hooks/check-merge-approvals.sh #169 セッション C / TASK-0058
EHS-1(V-3 外部レビュー必須化) CLI(mode 連携) scripts/hooks/check-v3-review.sh #169 セッション C / TASK-0058
EHS-2(handoff 必須 6 要素) CLI(手動 / WF-05 で呼び出し) scripts/hooks/check-handoff-elements.sh #157 / TASK-0048
EHS-3(fix loop 上限超過) CLI(V-1 fix loop 内で increment / check) scripts/hooks/check-fix-loop.sh #157 / TASK-0048
EH-9(委譲 commit/push 境界検知) PreToolUse hook(Bash 前) scripts/hooks/check-delegation-commit-boundary.sh #239 問題2 / TASK-0073
auth-preflight(exec 前 認証三点検証) CLI(exec 前で呼び出し) scripts/hooks/check-auth-preflight.sh #239 問題3 / TASK-0073
EH-12(protected branch 上の破壊的 git 操作 block) PreToolUse hook(Bash 前・Human apply 後に有効 scripts/check-git-destructive.sh(HO 外・単一ソース)+ 配線 scripts/apply-eh-git-destructive-guard.sh 2026-08-02 main 上 reset --hard 実害

残未実装: なし(10/10 完了)。EH-7 の GitHub branch protection 自動連携は別 PBI 候補。

4.1 3 モード設計

モード 環境変数 挙動
default(推奨初期値) なし 違反検出時は warning のみ、continue:true(block しない)。誤検出時の作業妨害を最小化
strict PLANGATE_HOOK_STRICT=1 違反検出時に block / exit 1。本番運用 / CI 等で有効化
bypass PLANGATE_BYPASS_HOOK=1 常時 pass。緊急対応 / 既知の例外時のみ使用、監査 log に必ず記録

4.2 監査ログ

すべての判定は docs/working/_audit/hook-events.log に append-only で記録される(タブ区切り):

<ISO8601 UTC>\t<level>\t<hook-name>\t<task-id>\t<message>

level: PASS / VIOLATION / BYPASS / SKIP / INCREMENT

4.3 設定方法(opt-in)

.claude/settings.example.json.claude/settings.json にコピーすると PreToolUse hook(EH-1 + EH-2 + EH-3 + EH-6)+ SessionStart(gh-pin-account)が有効化される。

CLI 配線(TASK-0143 / apply-script 適用後): EH-4 は plangate verify V-1 前(strict=1)、EH-5 は V-1 後(warn)で発火。EH-7 / EHS-1 / EHS-2 / EHS-3 は引き続き手動呼び出し。

4.4 テスト

4.5 全 10 hook 完了(#169 完走)

Issue #169 完了。10/10 hooks 実装済(CLI / PreToolUse 構成)。残課題は GitHub branch protection 自動連携(EH-7 の上位拡張、外部 GitHub API 操作を伴うため別 PBI)。

5. 既存 .claude/settings.json hooks との関係

本ファイルが定義する不変条件は、既存 hooks(もしあれば)と:

6. 「block 通知」の文言ガイド

Hook が block する際の通知文言:

[Hook EH-1] plan.md がないため production code を編集できません。
docs/working/TASK-XXXX/plan.md を作成してください。

形式:

関連