Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions docs/workflows/ai-loop/c3-prime-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ C-1/C-2 いずれか**単独**の異常でも `AUTO_APPROVED` にならない(

## 4. stale / 受理規則(AC-7 / AC-8 / AC-9)

受理側(`bin/plangate validate` / exec preflight — PR-2)は `approval_kind` の有無で分岐する:
受理側(`bin/plangate validate` / exec preflight — PR-2)は `approval_kind` の有無で分岐する。**受理側は decision 値を無検証で信頼せず、以下の全規則を strict JSON で再検証する**(trust boundary / #887 F-4 / #889 critical)。トップレベルは必須キー allowlist(`c3_status` および未知キーは reject)+ `task_id`(`TASK-XXXX`)+ `phase`(`C-3'`)+ evidence/policy/issued の非空を含む:

| 条件 | 判定 |
|------|------|
Expand All @@ -81,11 +81,19 @@ C-1/C-2 いずれか**単独**の異常でも `AUTO_APPROVED` にならない(
| `decision == "AUTO_APPROVED"` だが reviewers の verdict に `reject` を含む | **BLOCK**(decision↔verdicts 不整合 record = 改竄兆候。#887 F-3 の受理側検証) |
| `plan_hash` ≠ 現 plan.md sha256 | FAIL(stale・legacy と同一規則) |
| `artifact_hashes` のいずれか ≠ 現ファイル sha256 | FAIL(stale。**不一致エントリ名を失敗メッセージに含む**) |
| `source_sha` ≠ 検証時点の対象 SHA | **BLOCK(警告に降格しない fail-closed 固定 / R-003)**。再 C-1/C-2/C-3' を要求 |
| `source_sha` ≠ 検証時点の対象 SHA | **BLOCK(警告に降格しない fail-closed 固定 / R-003)**。exec preflight は `git rev-parse HEAD` を `expected_sha` として受理器へ渡し厳密照合する(#889 critical)。静的 validate は `expected_sha` を渡さないため source_sha は**形式チェックのみ**(HEAD 一致照合はしない)。SHA 一致の強制点は exec |
| トップレベルに `c3_status` / 未知キー / 必須キー欠落 | **FAIL**(構造 allowlist・#889 critical。`^_` 注釈キーのみ許容) |
| 受理器(`c3prime_verify.py`)が実在しない | c3-prime は **FAIL**(検証不能。`approval_kind` キーが物理的に無い場合のみ legacy 委譲 / #889 high fallback) |
| 同一 TASK に legacy と c3-prime が併存 | **物理的に不可能**(同一パス `approvals/c3.json` のため)。上書きは `--force` 相当の明示操作のみ(EC-5 の解決) |

EH-3 hook(`check-plan-hash.sh`)は top-level `plan_hash` のみを strict JSON で読むため、c3-prime に対しても**無変更で機能**する(非退行・本契約が plan_hash を legacy と同一義で保持する理由)。

**TOCTOU の残余窓(#889 high・既知制約)**: 受理器は exec preflight で再検証するが、検証成功から `session_started` 記録までの 1 shell 文の窓で外部プロセスが artifact を書き換える理論的余地は残る(ローカル書込レースが前提)。緩和として **exec preflight が受理検証の実点**であり(validate だけでなく exec 直前に再検証)、session 開始は直後に続く。Phase 1(隔離 PoC)ではこの残余窓を許容し、将来 flock ベースの単一 snapshot 検証を V2 候補とする(handoff 記載)。

**受理側の再検証範囲(#889 R2 critical/high 反映)**: 受理器(`c3prime_verify.py`)は record の binding hash だけでなく **C-1/C-2 evidence marker を再検証**(`plan_package.check_evidence` を受理側でも実行)し、`task_id` を **task_dir 名に束縛**し、両 reviewer の `evidence_ref` **独立性**を要求し、issued_at 形式・reviewer/snapshot キーの `additionalProperties:false` 相当を強制する。exec は HEAD を解決できない環境では c3-prime を **BLOCK**(source_sha 照合を skip して受理しない・fail-closed)。

**脅威モデルの境界(V2 候補)**: 現行はローカル作業ツリーの改竄検出(承認後の drift・evidence 改竄)を対象とする。record と作業ツリーの**双方**を任意に書換できる攻撃者(同一整合な偽造一式の構築)は、`source_sha` の Git tree との照合または署名済み provenance でのみ防げる。Phase 1(eligible run 限定・boundary=clean・信頼済みローカル repo)ではこれを scope 外とし、git-tree 束縛/署名を V2 候補として handoff に記載する。

## 5. serialization 制約(R-009 / #887 F-7 是正)

- `json.dumps(indent=2, sort_keys=True)` で整形(arbiter provenance 出力と同形)
Expand Down
13 changes: 7 additions & 6 deletions docs/working/TASK-0872/current-state.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Current State — TASK-0872

- 更新: 2026-07-20 08:05
- フェーズ: exec(PR-1 merged #886 → #887 是正完了 = PR #888 C-4 待ち)
- Mode: critical / c3.json APPROVED(plan_hash 1af8d43e…・不変)
- 直近の完了: #887(PR #886 敵対的レビュー major 4)の全件是正 — evidence 判定マーカー正規化(F-1/F-5)・hash ベース stale(F-2)・decision↔verdicts 整合(F-3)・HO 先勝ちテスト(F-6)・契約 §5 是正(F-7)・schema 不在窓 FAIL 化(F-8)+ T-14 schema patch 同梱
- 次のアクション(Human): C-4 = PR #888 レビュー・マージ
- マージ後の残: T-15 bin/plangate 両受理 patch → T-16 command 入口 patch → H-3 Human 適用(schema 含む)→ T-18 E2E extras fixture → T-19/20 記録
- 更新: 2026-07-20 09:00
- フェーズ: exec(PR-2 = 非 HO 実装完了・PR 作成へ / HO patch は Human 適用待ち)
- Mode: critical
- 直近の完了: PR-2 の受理側実装 — `scripts/ai-loop/c3prime_verify.py`(非 HO・契約 §4 全数再検証)+ bin/plangate 配線 patch(sandbox 実適用テストで全 6 exit code 実測)+ command run 入口 patch + schema 完成形 + TA-55 E2E(非 HO 部分 CI 常時 PASS・HO 全鎖は適用後 SKIP→PASS)
- 次のアクション: 非 HO を commit → PR 作成 → C-4 + H-3(HO patch Human 適用)
- 既知(スコープ外): ta-42 TC-04(status 異常系 exit)はローカル macOS sh の set -e 挙動差による偽陽性。main CI(Test)は e6ccc4f で success = CI では通る。PR-2 非改変領域
- HO 適用手順: `patches/ho-apply-approval.md`
5 changes: 5 additions & 0 deletions docs/working/TASK-0872/decision-log.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@
{"ts":"2026-07-20T08:30:00Z","phase":"exec","decision":"PR #886(PR-1) Human C-4マージ確認(721edcb・diff 0照合・branch掃除)。bot quota不在のため敵対的レビュー1本実施→approve(重大0・全指摘実測再現)。minor 3: ①schema不在窓のvalidate SKIP→PR-2でschema先行着地+FAIL化 ②prod+no-pp+reject-rejectのBLOCKED→ESCALATED変化(安全側・記録のみ) ③_PATH_RE sanitize(V2候補)。R-015〜R-017としてreview-external集約","by":"agent"}
{"ts":"2026-07-20T09:00:00Z","phase":"exec","decision":"#887(別セッション敵対的レビューmajor 4)を受理しPR-2前に是正実装へ。自レーンCレビュー(approve)はF-1/F-3/F-5を見逃し=検出力差を認め是々非々で採用。是正設計: evidence判定は行頭アンカー機械マーカー(C1-VERDICT/C2-VERDICT + plan=sha256:)へ正規化しちょうど1回を要求(F-1)・stale はマーカー内plan hash照合で決定論化しmtime廃止(F-2)・build_c3_primeにdecision↔verdicts整合(AUTO_APPROVEDは両approve必須)を追加し契約§4にも受理側規則明記(F-3)・実artifact形式fixture追加(F-5)・契約§5のgrep記述是正=legacy grep流用禁止を明記(F-7)・schema_mappingはc3-prime時にis_fileスキップでschema不在をFAILへ(F-8)","by":"agent"}
{"ts":"2026-07-20T09:30:00Z","phase":"exec","decision":"複数エージェントレビュー(Codex×2+Sonnet)実施。Codex conditional/reject vs Sonnet approve の分裂を全件一次ソースで再現裁定。スコープ内 major 4+minor 1 採用(R-019〜023): decision/verdict allowlist・schema cross-field制約・evidence再読TOCTOU fail-closed・F-8回帰テスト・prefix文法外行fail-closed。R-024/025(bin/plangate受理側・schema配置)はPR-2スコープのためreject理由として却下。検証: test_plan_package 30・run-tests 406 passed","by":"agent"}
{"ts":"2026-07-20T09:00:00Z","phase":"exec","decision":"PR-2受理側実装。設計: c3-prime検証をscripts/ai-loop/c3prime_verify.py(非HO・AIコミット可)に分離しbin/plangateは_plangate_c3_dispatch配線数行(HO)のみに縮小。契約§4全数再検証(trust boundary #887 F-4)。実適用テストでset -e漏れバグ(dispatch戻り10がスクリプト中断)を捕捉し|| _c3_rc=$?で修正。sandbox 6シナリオ全exit code実測(legacy非退行0/c3-prime受理0/改竄1)。HO patch4件はho-apply-approval.mdでHuman適用。ta-42 TC-04失敗はmacOS sh set-e差の既存偽陽性(main CI success)","by":"agent"}
{"ts":"2026-07-20T10:00:00Z","phase":"exec","decision":"PR #889受理側Codex敵対レビュー(reject: critical 1/high 2/medium 1)を全件一次ソース再現裁定し是正(R-026〜030)。critical=偽造record受理→構造allowlist+必須+c3_status拒否+task_id/phase+expected_sha照合(exec HEAD強制)。high fallback=approval_kindキー存在時は値不問で1へ。high TOCTOU=exec preflight再検証+契約明記(残余窓Phase1許容/flock V2)。medium=test_c3prime_verify.py新設(手mutate 14パターン)+ta-55手偽造ケース。sandbox実適用で非退行+偽造reject実測。全非HO(bin/plangateはpatches/のみ)","by":"agent"}
{"ts":"2026-07-20T11:00:00Z","phase":"exec","decision":"PR #889再レビュー(ユーザー指示Codex+独立)。Codex R2=reject(前回是正後のより深いcritical/high)・Sonnet=conditional(HOガバナンスmajor)。全件再現裁定しR2-01〜06+08は是正: 受理側でcheck_evidence再実行(evidence改竄検出)・task_id→task_dir束縛・reviewer evidence_ref独立性・非git exec BLOCK・schema同等nested制約・sync列挙追加。R2-07(受理ロジックHO対象外)はHOファイル編集を要する承認境界ガバナンス決定→Human判断待ち(A:HOリスト追加/B:V2明記)。脅威モデル境界(record+tree双方書換=git-tree束縛V2)を契約明記","by":"agent"}
{"ts":"2026-07-20T11:15:00Z","phase":"exec","decision":"R2-07 HOガバナンスはHuman決定B(現状維持+V2明記)。known-issues.md KI-1に記録。mode-classificationのセキュリティ関連→最低中でカバー・HO化は将来判断。KI-2脅威モデル境界(git-tree束縛/署名V2)・KI-3 TOCTOU・KI-4切り戻し手順も記録。ho-apply-approval.mdに切り戻し(git apply -R)追記","by":"human+agent"}
{"ts":"2026-07-20T11:16:00Z","phase":"C-3-governance","decision":"R2-07 HOガバナンス Human決定 verbatim選択: \"B: 現状維持 + V2 明記\"(AskUserQuestion選択肢ラベル原文)。known-issues.md KI-1の\"verbatim\"表記の一次証跡","by":"human"}
25 changes: 25 additions & 0 deletions docs/working/TASK-0872/known-issues.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Known Issues / V2 候補 — TASK-0872

> WF-05 handoff 発行時にこの内容を handoff.md §V2 候補へ統合する。

## V2 候補

### KI-1: 受理検証ロジックの HO 機械強制(R2-07・Human 決定 B / 2026-07-20)

- **内容**: 受理検証ロジック(`scripts/ai-loop/c3prime_verify.py`)は HO 9 カテゴリ(`check-plan-hash.sh` L124-134 正本)の対象外。将来の非 HO PR 単独で承認ゲートを弱められる構造的余地がある。
- **Human 決定(AskUserQuestion 2026-07-20 verbatim: "B: 現状維持 + V2 明記")**: 現状維持。HO 化は将来判断。現状は `mode-classification.md`「セキュリティ関連 → 最低『中』」の判断依存保護でカバー。
- **将来の是正案(A・不採用)**: `scripts/ai-loop/*_verify.py` を HO 9 カテゴリへ追加(`check-plan-hash.sh` + `mode-classification.md` を Human patch 適用)→ 機械強制を回復。以後 verifier 編集も HO ceremony。

### KI-2: 脅威モデル境界 — record + tree 双方書換への防御(R2-01 の残余 / #889 Codex)

- **内容**: 現行受理器はローカル作業ツリーの改竄検出(承認後 drift・evidence 改竄)を対象とする。record と作業ツリーの**双方**を任意書換できる攻撃者(同一整合な偽造一式の構築)は、`source_sha` の Git tree 照合または署名済み provenance でのみ防げる。
- **Phase 1 の扱い**: scope 外(eligible run 限定・boundary=clean・信頼済みローカル repo)。契約 §4「脅威モデルの境界」に明記済み。
- **V2 案**: git-tree 束縛(artifact が `source_sha` の committed tree と一致することを照合)または署名済み provenance。

### KI-3: TOCTOU 残余窓(#889 R1 high)

- exec preflight 検証成功〜`session_started` 記録までの 1 shell 文の窓。flock ベースの単一 snapshot 検証を V2 候補(契約 §4 記載)。

### KI-4: ho-apply の切り戻し手順(R2-09 minor)

- `ho-apply-approval.md` に適用失敗時の切り戻し(`git apply -R docs/working/TASK-0872/patches/bin-plangate.patch`)を追記する(次コミット or handoff 時)。
4 changes: 4 additions & 0 deletions docs/working/TASK-0872/patches/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# 生成された unified diff 成果物。空行の context マーカー(行頭 1 空白)を含むため
# git diff --check の trailing-whitespace 検査対象から除外する(#889 Codex minor)。
# 実適用対象の完成形(*.new)は trailing whitespace ゼロを別途保証している。
*.patch -whitespace
19 changes: 19 additions & 0 deletions docs/working/TASK-0872/patches/ai-loop-workflow-claude.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
diff --git a/.claude/commands/ai-loop-workflow.md b/.claude/commands/ai-loop-workflow.md
index 625eb6e..c3e8cad 100644
--- a/.claude/commands/ai-loop-workflow.md
+++ b/.claude/commands/ai-loop-workflow.md
@@ -18,7 +18,13 @@ arbiter 裁定 → exec → rubric grader)。本コマンドは前提確認と

$ARGUMENTS に以下の形式で渡される:

-- `run <対象の説明>` — 新しい run を開始(LoopSpec 作成から)
+- `run TASK-XXXX` — **Plan-first の正式入口**(TASK ID 必須)。既存の Plan Package
+ (pbi-input / plan / todo / test-cases + C-1/C-2 evidence)を起点に production run を
+ 開始する。LoopSpec は `scripts/ai-loop/plan_package.py` の `derive_loopspec()` で
+ Plan Package から決定論派生し、`production: true` + `plan_package` ブロックを
+ arbiter へ渡す(契約正本: `docs/workflows/ai-loop/c3-prime-contract.md`)。
+ TASK ID を伴わない自由文だけの `run <説明>` は **production run を開始できない**
+ (TASK-0872 / #872。Plan Package 束縛の無い run を Wチェックへ進めない)
- `status` — 直近 run の状態・decision record・摩擦台帳の要約を表示
- (引数なし) — 前提チェックのみ実施して結果を報告

64 changes: 64 additions & 0 deletions docs/working/TASK-0872/patches/ai-loop-workflow.claude.new
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# /ai-loop-workflow

ai-loop-workflow(human-on-the-loop 裁定ループ)を明示起動する。
`/ai-dev-workflow`(PlanGate 本番フロー WF-00〜07)と**対をなす入口**であり、
本番フローの置き換えではない。恒久定義(責務・terminal state・C-3'/Human C-3 経路)の
正本は `00_concept.md`、適用制限(Phase 1 rollout eligibility)の正本は
`rollout-policy.md`(eligible run 限定。PlanGate 本番フローの C-3 は常に Human・不変)。

実行手順の正本: skill `ai-loop-cycle`(1 サイクル = LoopSpec → W チェック →
arbiter 裁定 → exec → rubric grader)。本コマンドは前提確認と起動のみを担う。

> **docs の参照先**: plugin 導入先では ai-loop ドキュメントは skill 内の
> `references/` 配下(`skills/ai-loop-cycle/references/`)に同梱される。
> 本リポジトリ(正本側)では `docs/workflows/ai-loop/` 配下。以下の参照は
> 環境に応じてどちらかで解決すること。

## 引数

$ARGUMENTS に以下の形式で渡される:

- `run TASK-XXXX` — **Plan-first の正式入口**(TASK ID 必須)。既存の Plan Package
(pbi-input / plan / todo / test-cases + C-1/C-2 evidence)を起点に production run を
開始する。LoopSpec は `scripts/ai-loop/plan_package.py` の `derive_loopspec()` で
Plan Package から決定論派生し、`production: true` + `plan_package` ブロックを
arbiter へ渡す(契約正本: `docs/workflows/ai-loop/c3-prime-contract.md`)。
TASK ID を伴わない自由文だけの `run <説明>` は **production run を開始できない**
(TASK-0872 / #872。Plan Package 束縛の無い run を Wチェックへ進めない)
- `status` — 直近 run の状態・decision record・摩擦台帳の要約を表示
- (引数なし) — 前提チェックのみ実施して結果を報告

## 実行前チェック(必須・満たさない場合は開始せず報告)

1. **HO 境界の解決**: ho-paths(導入先確定済み)が arbiter から解決できるか
— `python3 <arbiter.py の実パス> --input /dev/null` 相当の疎通でなく、
ho-paths 解決元の stderr 表示を確認する。未確定なら「全件 human escalate になる」旨を伝え、確定を促す
2. **保存先の定義**: run 記録(LoopSpec・decision record)と摩擦台帳の置き場が
プロジェクトで定義済みか(未定義なら既定案を提示して合意を取る)
3. **適用制限(Phase 1 rollout eligibility)**: 対象変更が `rollout-policy.md` の
eligible 条件を満たしうるか(boundary=clean、かつ `lite-criteria.md` §2 の
4 軸〔変更規模・新規設計の有無・既存パターン踏襲・可逆性〕。docs に限らず
実機能も含む — Human 決定 #807)。承認境界・本番承認フローに触れる場合は
本コマンドを使わず通常フローへ

## 実行

前提 3 点を満たしたら、skill `ai-loop-cycle` の手順に従って 1 サイクルを実行する。
停止規則(round 上限・escalate 条件・touches-HO 無条件 escalate)は skill と
同梱 docs(decision-table / execution-runbook / loop-safety-gates)が正本。

## Iron Law(ai-loop 版・違反したら即停止)

| ルール | 意味 |
|-------|------|
| `NO LOOP WITHOUT STOPPING RULE` | 停止できないループを回すな |
| `NO AUTO-APPROVE ON HO CONTACT` | HO 接触は無条件で人間へ |
| `NO OPTIMIZE WITHOUT RECORD` | 記録なき最適化をするな |
| `NO MERGE BY AI` | マージは常に Human |

## 関連

- skill: `ai-loop-cycle`(実行単位の正本)
- docs: 同梱 ai-loop ドキュメント(design-philosophy / decision-table / execution-runbook —
plugin 導入先は skill 内 `references/`、本リポジトリは `docs/workflows/ai-loop/` 配下)
- 対: `/ai-dev-workflow`(PlanGate 本番フロー入口)
Loading