diff --git a/docs/adr/adr-066-autonomy-global-kill-switch.md b/docs/adr/adr-066-autonomy-global-kill-switch.md index df1a6151..1e83067e 100644 --- a/docs/adr/adr-066-autonomy-global-kill-switch.md +++ b/docs/adr/adr-066-autonomy-global-kill-switch.md @@ -199,6 +199,16 @@ Phase B の稼働により bounded lifetime の decision trigger 観測が始ま § 欠点の 1 点目に挙げた master ref 契約も実走で確認できた — gate 呼び出しの `--config master-ref/autonomy-config.toml` が run log に出ており、PR ブランチ側の同名ファイルは判定に使われていない。 +### 実走観測 2 — 停止側の variable 3 状態が埋まった(2026-08-08、WP-18 停止側スモーク) + +WP-18 夜間ループ([ADR-072](adr-072-nightly-todo-loop.md) § 実走スモーク)の停止側検証として、`AUTONOMY_ENABLED` の残る 2 状態を `workflow_dispatch` で実測した(ユーザー実測): + +- **明示的 `'false'`** と **未設定**の 2 状態で、いずれも **`dry_run` をオフ(= push / PR 作成をする設定)**にして dispatch → **2 回とも job が skip** し、ブランチ・draft PR・App token のいずれも作られなかった。確認後 `'true'` へ復旧済み。 +- これで trigger (b) の **variable 側は 3 状態(`'true'` / `'false'` / 未設定)すべてが実走で確認済み**になった(1 run 目に確認したのは「削除 = 未設定」のみ)。**残るのは config 側(master ref の `autonomy-config.toml` で `enabled = false`)の実走のみ**(exe 単体は drill #2 で固定済み)。 +- あわせて draft-pr クラスでも (a) 有効時の allow 経路が 1 run 成立した(schedule の初回実走で draft PR [#365](https://github.com/aloekun/claude-code-hook-test/pull/365) = `claude/nightly-203` を作成。経緯は ADR-072 § 実走スモーク)。 + +なお本観測は自律 fix push の発生した run ではないため、decision trigger の run 数(3〜5 run)には数えない — 埋めたのは (b) の状態網羅である。 + ## 帰結 ### 利点 diff --git a/docs/adr/adr-072-nightly-todo-loop.md b/docs/adr/adr-072-nightly-todo-loop.md index 40f15422..0ec7b03e 100644 --- a/docs/adr/adr-072-nightly-todo-loop.md +++ b/docs/adr/adr-072-nightly-todo-loop.md @@ -463,7 +463,6 @@ pre-push review を 12 サイクル通す過程で、blocking な欠陥 10 件 - **外部設定の実体は記録したが、作成日と資格情報欠落時の run の色は未確定** (§ 外部設定の実体)。前者は GitHub の Audit log から引ける。後者は資格情報を意図的に壊す run が要り、復旧を伴うため実施していない。 - **`AUTONOMY_ENABLED` を立てると schedule も同時に有効になる**。スモークを「まず dry_run で」と計画していたのに、変数を立てた時点で本番の夜間 run が先に走った (§ 実走スモーク)。**観測装置の準備前に無人 run が始まる**構造なので、次に同種の自律機能を足すときは「有効化の粒度」を dispatch 限定と schedule 込みで分けられるか検討する。 - **CodeRabbit が bot 投稿の `@coderabbitai review` に反応するか** (決定 11)。無反応なら明示トリガーの設計自体が成立しないため、次回の夜間 run で最優先に確認する。 -- **外部設定 (GitHub App / repository variables・secrets) の実体が未記録**。決定 8 は「なぜ App token か」を厚く残す一方、App 名・インストール範囲・付与権限の実際・`NIGHTLY_APP_ID` (variable) / `NIGHTLY_APP_PRIVATE_KEY` (secret) / `AUTONOMY_ENABLED` (variable) の登録先と欠落時の倒れ方を 1 行も書いていない。[ADR-051](adr-051-cross-system-config-coupling.md) が内部設定と外部 SaaS 設定の論理結合に課す 3 点 (相互参照コメント / 期待値の組み合わせ表 / 両側同一 PR) が未実施の状態にあたる。実走スモークで GitHub UI を触る際に**設定メタデータ** (名前・登録先の別・付与権限のスコープ・所有者・ローテーション方針・欠落時の挙動) を確認し、§ 外部設定の実体 として本 ADR へ追記する。**秘密値そのもの (`NIGHTLY_APP_PRIVATE_KEY` の鍵本文や発行済み token) は ADR にも git 履歴にも残さない** — ADR-051 が記録を課すのは「結合の存在」と「期待値の組み合わせ」であって、秘密の実値ではない。 - **`master-ref/` を agent のファイルシステムから外すか (順位 377 の判断材料)**。決定 12 の tool scope で**agent が直接書く経路は予防側で塞いだ**ため、当初の「検知どまり」状態は解消した。残るのは build script 経由の経路で、完全に外すには別 job + artifact 受け渡しへの構造変更が要る。**決定 12 のスコープが実走で効いていることを確認できるまでは、構造変更の要否を判断しない** — 効いていなければ前提が変わる。 - **authority gate の直前で draft 数を再計数するか**。現状は job 冒頭のスナップショットを使い回す (§ 決定 4)。閾値を 1 件超えて push される事象が実運用で観測されたら入れる。 - **ガードレール禁止リストの allowlist 化**。台帳の「対象ファイル」列を機械可読にする (別列に正規化パスを持つ等) のが前提。 diff --git a/docs/harness-improvement-plan.md b/docs/harness-improvement-plan.md index 7d03b5aa..5d580fd8 100644 --- a/docs/harness-improvement-plan.md +++ b/docs/harness-improvement-plan.md @@ -3,6 +3,8 @@ > **位置付け**: ephemeral 計画書。本ファイルの最終目標は、記載された全 WP(作業パッケージ)を完了し、知識を永続成果物(ADR / todo / rules)へ移管したうえで、**本ファイル自身を削除すること**である。永続成果物(ADR 等)から本ファイルへリンクを張ってはならない(Cross-File Reference Lifecycle: 参照は permanent → ephemeral の方向のみ禁止対象)。削除条件と手順は末尾「完了条件と退役手順」を参照。 > > **2026-08-01 スリム化**: 完了・見送り WP の詳細記録は永続成果物へ移管済みのため本ファイルから削除した(WP-15 本体 → [ADR-063](adr/adr-063-linux-portability-release-binaries.md)、WP-15 追補 → [ADR-064](adr/adr-064-monitor-success-positive-evidence.md) を新規起票。WP-14 は新規 ADR 不要判断のため各 crate doc + commit message が永続記録。その他は「全体像」表の移管先参照を見よ)。本ファイルには残作業のみを記載する。 +> +> **2026-08-09 スリム化**: WP-18 の完了記録(着手前決定 / PR 構成 / PR chain 宣言 / 受け入れ基準の達成)を削除した。設計・決定・検証記録は [ADR-072](adr/adr-072-nightly-todo-loop.md)(背圧は [ADR-071](adr/adr-071-draft-pr-backpressure.md))が正。2026-08-08 の停止側実測は [ADR-066](adr/adr-066-autonomy-global-kill-switch.md) § 実走観測 2 へ追記済み。経緯は git log と #361〜#370 の PR 本文を参照。 ## 0. この文書の扱い方(実行セッション向け) @@ -79,8 +81,8 @@ Anthropic 公式のハーネスエンジニアリング指針(決定論的基 | WP-14 | 3 | PowerShell 3 本の Rust 化 | S-M ×2 | なし | 完了(新規 ADR 不要判断 = 決定は各 crate doc + commit message に記録。実走確認済) | | WP-15 | 3 | Linux バイナリビルド + クラウド setup script | M | WP-13, 14 | 完了([ADR-063](adr/adr-063-linux-portability-release-binaries.md)。クラウド実測は [ADR-060](adr/adr-060-cloud-harness-sessionstart-dispatcher.md) dogfood で達成、以降は ADR-060 の bounded lifetime で管理。追補の陽性証拠設計は [ADR-064](adr/adr-064-monitor-success-positive-evidence.md) → park 実観測は § 残作業) | | WP-16 | 3 | CI matrix(移植退行防止) | S | WP-13, 14 | 観測中([ADR-065](adr/adr-065-ci-matrix-cross-os-regression.md)。2 OS matrix は PR #342 でマージ済・master 稼働中、初回観測期間に実バグ 1 件捕捉(PR #344 で修正)。観測継続と required check 化は → § 残作業) | -| WP-17 | 4 | イベント駆動バックボーン完成(Phase B + routines 移行 + 全体 kill-switch 前倒し) | M-L | WP-09, 10, 11 | **観測中(実装は 2026-08-04 に全 land)** — #347 / #350 / #351 / #352 / #353 / #354、実走バグ修正 #356 / #357 / #358、記帳 #359。実走スモーク段 0〜2 まで完走。**観測待ち**: 停止側の実走 2 点 / 自動起動経路 / 週末またぎ / ADR-066 bounded lifetime(1 of 3〜5 run)→ § WP-17。派生 ADR: [ADR-068](adr/adr-068-fix-step-authority-boundary.md) #348 / [ADR-069](adr/adr-069-pr-chain-declaration.md) #349 | -| WP-18 | 4 | 夜間 todo 消化ループ | M-L | WP-15, 17 | **3 PR すべてマージ済(2026-08-07)** — PR 1 = 背圧 + [ADR-071](adr/adr-071-draft-pr-backpressure.md)(#361)/ PR 2 = タスク台帳(#362)/ PR 3 = 夜間 workflow + [ADR-072](adr/adr-072-nightly-todo-loop.md)(#363)。**未完**: 実走スモーク(順位 374、外部設定の実体記録 384 を同時実施)→ 採用率 2 週間測定。**定常運用開始前に必須**: prompt injection 対策 4 件(順位 378-381)→ § WP-18 | +| WP-17 | 4 | イベント駆動バックボーン完成(Phase B + routines 移行 + 全体 kill-switch 前倒し) | M-L | WP-09, 10, 11 | **観測中(実装は 2026-08-04 に全 land)** — #347 / #350 / #351 / #352 / #353 / #354、実走バグ修正 #356 / #357 / #358、記帳 #359。実走スモーク段 0〜2 まで完走。**観測待ち**: config 側 kill-switch の実走(variable 側 3 状態は 2026-08-08 実測済 = [ADR-066](adr/adr-066-autonomy-global-kill-switch.md) § 実走観測 2)/ Phase B 起動([ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 11 の実測待ち)/ 週末またぎ / ADR-066 bounded lifetime(1 of 3〜5 run)→ § WP-17。派生 ADR: [ADR-068](adr/adr-068-fix-step-authority-boundary.md) #348 / [ADR-069](adr/adr-069-pr-chain-declaration.md) #349 | +| WP-18 | 4 | 夜間 todo 消化ループ | M-L | WP-15, 17 | **観測中(実装・スモークは 2026-08-08 までにほぼ完了、本番稼働中)** — 3 PR(#361 / #362 / #363)+ 追補 5 PR(#366〜#370)マージ済。injection 対策 4 件(順位 378-381)と外部設定記録(384)完了、スモーク 10 項目中 8 充足([ADR-072](adr/adr-072-nightly-todo-loop.md) § 実走スモークが正)。**残**: トークン露出 probe(保留)/ 決定 11 実測 / 採用率 2 週間測定 → § WP-18 | | WP-19 | 4 | 常時性ガード(自主減速 / 監査ループ。全体 kill-switch は WP-17 PR 1、背圧は WP-18 PR 1 へ前倒し) | S-M | WP-18 | 未着手(残りは監査ループのみ。背圧は WP-18 PR 1 で land 済み) | ## 5. 残作業(観測継続) @@ -150,85 +152,28 @@ Anthropic 公式のハーネスエンジニアリング指針(決定論的基 #### 後続へ引き継ぐ残課題 -- **停止側の実走が未完**: 実走で確認したのは `AUTONOMY_ENABLED` を**削除した(= 未設定)**場合のみ。明示的な `AUTONOMY_ENABLED=false` と config 側(master ref の `autonomy-config.toml` で `enabled = false`)の deny は実走未観測で、gate exe 単体の drill でのみ固定されている。ADR-066 bounded lifetime の観測(3〜5 run、期限 2026-11-02)で埋める。 -- **Phase B の自動起動経路が未検証**: 段 1 で `coderabbitai[bot]` の permission が `none` と実測されたため `pull_request_review` 経路は恒久 deny で、起動は `issue_comment`(walkthrough)経路だけになる。この経路は初回 1 回きりで、その時点では CodeRabbit の実レビューがまだ無いことが多い。「findings がある状態で Phase B が自動起動する窓」が実質的に無い可能性がある(段 2 は手動 dispatch で成立させたため未検証)。bot allowlist の要否と併せて **WP-18 着手時に実測する**(ADR-067 § 検証記録)。 +- **停止側の実走は config 側のみ残る**: variable 側 3 状態(`'true'` / `'false'` / 未設定)は 2026-08-08 の WP-18 停止側スモークですべて実測済([ADR-066](adr/adr-066-autonomy-global-kill-switch.md) § 実走観測 2)。**残るのは config 側(master ref の `autonomy-config.toml` で `enabled = false`)の実走のみ**(exe 単体 drill で固定済み)。ADR-066 bounded lifetime の観測(3〜5 run、期限 2026-11-02)で埋める。 +- **Phase B の自動起動経路は「不成立」と実測で判明**: CodeRabbit は draft を自動レビューしないため(`.coderabbit.yaml` の `drafts: false`)、起動契機のコメント自体が夜間 draft PR では発生しない。[ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 11(draft PR 作成後の `@coderabbitai review` 明示トリガー)で対処済みで、**CodeRabbit が bot 投稿へ反応するかを次回夜間 run で実測**する(`coderabbitai[bot]` allowlist の要否も同経路のため、決定 11 が効いてから再判定)。夜間ループの稼働開始(PR #365〜)で `claude/` ブランチ PR の供給は始まっており、これが通れば ADR-067 § 欠点の発火機会問題も解消する。 - **routine 出力の受け渡し手段が未決**: 分析結果が transcript にしか残らずユーザーが読まなければ消える。実行主体を含む 3 択(routine / GitHub Actions schedule / ローカル維持 = 断念)で、**断念も正規の出口**。判定は ADR-070 bounded lifetime (b) の観測後([ADR-070](adr/adr-070-weekly-review-cloud-routine.md) § 残課題)。 -- **Phase B の実効価値は WP-18 に依存**: 対象が docs 指摘に限られるため、WP-18 の夜間ループが `claude/` ブランチ PR を作り始めるまで発火機会が小さい(ADR-067 § 欠点)。 - -### WP-18: 夜間 todo 消化ループ — 実装 land 済 + allow 経路の実走成立(2026-08-08) - -> 夜間に 1 タスクを無人実装し **draft PR 作成で停止**する(マージ判断は人間)ループを、WP-17 のバックボーン上に組む。 -**進捗**: PR 1(背圧、[#361](https://github.com/aloekun/claude-code-hook-test/pull/361))/ PR 2(タスク台帳、[#362](https://github.com/aloekun/claude-code-hook-test/pull/362))/ PR 3(夜間 workflow、[#363](https://github.com/aloekun/claude-code-hook-test/pull/363))すべて **master へマージ済み**(2026-08-07)。 +### WP-18: 夜間 todo 消化ループ — 観測中(実装・スモークは 2026-08-08 までにほぼ完了、本番稼働中) -**2026-08-08 に夜間ループが初めて実走し、draft PR [#365](https://github.com/aloekun/claude-code-hook-test/pull/365)(`claude/nightly-203`)の作成まで完走した。** ただし **WP としては未完**で、残作業は 2 系統ある(→ § 残作業): +> 夜間に 1 タスクを無人実装し **draft PR 作成で停止**する(マージ判断は人間)ループ。**設計・決定・検証記録は [ADR-072](adr/adr-072-nightly-todo-loop.md) が正**(背圧は [ADR-071](adr/adr-071-draft-pr-backpressure.md)、外部設定の実体は ADR-072 § 外部設定の実体)。本節は残作業の索引だけを残す。着手前決定・PR 構成・PR chain 宣言・受け入れ基準の達成記録は役目を終えたため削除した(経緯は git log と #361〜#370 の PR 本文を参照)。 -1. **実走スモークの残り**(順位 374。**外部設定の実体記録 384 を同時実施**)— allow 経路は上記で成立したが、**停止側(`AUTONOMY_ENABLED` の 3 状態)とトークン露出の 2 項目が未観測**。どちらも本番 schedule では観測できず `workflow_dispatch` の専用 run が要る -2. **prompt injection 対策 4 件**(順位 378-381)— #363 の post-merge-feedback が Tier 1 として挙げたもの。定常運用開始前に必須 - -**なお allow 経路は `workflow_dispatch` ではなく schedule の本番 run が先に消化した** — `AUTONOMY_ENABLED` を立てると schedule も同時に有効になるため。結果は成功だったが、観測装置の準備前に無人 run が始まる構造だった点は [ADR-072](adr/adr-072-nightly-todo-loop.md) § 残課題 に記帳した。 +**達成したこと**: 台帳([claude-code-web-tasks.md](claude-code-web-tasks.md))から Rust 分類関数が選んだ 1 タスクを、kill-switch(ADR-066)と背圧(ADR-071)の上で無人実装し draft PR 作成で止めるループが本番稼働に入った(2026-08-08 に schedule 初回実走で draft PR [#365](https://github.com/aloekun/claude-code-hook-test/pull/365) = `claude/nightly-203` を作成)。定常運用開始前に必須とした prompt injection 対策 4 件(順位 378-381 → ADR-072 決定 12-14 + [ADR-035](adr/adr-035-doc-evaluation-policy.md) / `lib-docs-policy` の同期)と外部設定の実体記録(順位 384 → ADR-072 § 外部設定の実体)も完了。実走スモーク 10 項目は **8 充足 / 1 不成立(Phase B 自動起動 → 決定 11 で対処)/ 1 保留(トークン露出)**で、一覧は ADR-072 § 実走スモークが正。停止側実測は WP-17 の残課題([ADR-066](adr/adr-066-autonomy-global-kill-switch.md) bounded lifetime の variable 側 3 状態)も同時に埋めた(ADR-066 § 実走観測 2)。 #### 残作業 -| 順位 | 内容 | Tier | 期限 | -|---|---|---|---| -| 374 | 実走スモーク(**allow 経路・停止側・tool scope deny とも 2026-08-08 に充足**。残りは**トークン露出 1 項目のみ・意図的に保留**。初版 probe の設計欠陥を解消した安全な probe を設計してから 1 回で観測する) | 🚀 1 | 残り 1 項目(保留) | -| 384 | 外部設定(GitHub App / repository variables・secrets)の実体を [ADR-072](adr/adr-072-nightly-todo-loop.md) へ記録([ADR-051](adr/adr-051-cross-system-config-coupling.md) 違反の解消) | 🚀 1 | **完了**(2026-08-08、ADR-072 § 外部設定の実体。todo エントリの削除は docs バッチで行う) | -| 378 | 台帳を [ADR-035](adr/adr-035-doc-evaluation-policy.md) の docs-only 除外パス表へ追加 | 🚀 1 | **完了**(2026-08-08)。**穴の本体は決定論層 `lib-docs-policy` にあった** — 台帳は `docs/` 配下なので `is_docs_only_path` が docs-only と判定していた。ADR + facet 2 件 + 同 crate の 4 箇所を同期し unit test 4 件で固定 | -| 379 | agent の tool scope を `work/**` へ限定 | 🚀 1 | **実装済・両側実測済**([ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 12)。deny(`master-ref/` へ書けない)と allow(`work/` は編集できる)をローカル CLI で確認。実装で `Write(path)` 指定子が no-op と判明し `Edit(path)` へ統一 | -| 380 | 台帳フィールドを agent prompt へ untrusted data として明示 framing | 🚀 1 | **実装済**(同 決定 13)。prompt の framing + parse 側での枠偽装拒否の 2 層。回帰テストは marker / 自然文許可 / ゼロ幅・tag・soft hyphen・bidi・制御文字の拒否を good/bad 対で固定 | -| 381 | 台帳由来 SUMMARY の draft PR 本文出力に screening を追加 | 🚀 1 | **実装済**(同 決定 14)。公開面の棚卸し済み(台帳由来で外部可視なのは PR 本文の `内容` のみ)。回帰テストは code span 脱出・mention 保持・切り詰め・空入力・不可視文字除去を固定 | -| 382 | 台帳 prompt injection payload の regression test(順位 380 に依存) | 🔧 2 | 380 の後 | -| 383 | `is_separator_row` のパイプ検証欠落を塞ぐ(2026-08-07 実コード確認済み) | 🔧 2 | 任意 | -| 375-377 | レビュー対応チェックリスト / push-runner bookmark 前進 / 防御の格上げ判断 | 🔧 2〜💎 3 | WP-18 完了後 | - -**378-381 は 1 本の根から出ている** — 台帳の自由記述フィールドが無検証で無人 agent のプロンプトへ流入し、agent は workspace 全体に書き込め、その出力が公開面(draft PR 本文)に出る。[ADR-054](adr/adr-054-prompt-injection-trust-boundary-defense.md) の信頼境界そのもので、詳細は [todo20.md](todo20.md) § #363 post-merge feedback 採用分。 - -現時点の実効リスクは低い(悪意ある台帳行を master へマージするのはユーザー自身)が、**draft PR の流量が増えると前提が変わる**ため無期限に積んではならない。スモークは `dry_run` で PR を作らないため、**378-381 を待たずに着手してよい**。 - -**384 はスモークに相乗りする記録作業** — workflow が参照する GitHub App / `NIGHTLY_APP_ID` / `NIGHTLY_APP_PRIVATE_KEY` / `AUTONOMY_ENABLED` の実体(App 名・インストール範囲・付与権限・登録先・欠落時の倒れ方)がリポジトリ内に 1 行も無く、[ADR-051](adr/adr-051-cross-system-config-coupling.md) が定める 3 点(相互参照コメント / 期待値の組み合わせ表 / 両側同一 PR)が未実施のまま。スモークで GitHub UI を触る過程で実値が揃うため、先行させると値が確定せず二度手間になる。 - -**未 push の改善 3 点**(`wp18/unpushed-improvements` = `fc22403c` に保持): 改ざん検知の `continue-on-error` 除去(red 化)、[ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 10 の色分け表、決定 6 の列挙基準。#363 の最終 push が security REJECT で止まったため master に載っていない。いずれも可観測性・文書の改善で、fail-closed 自体は master 版でも成立している。 - -- **着手前決定(2026-08-05、ユーザー確認済み)**: - 1. **実行主体 = GitHub Actions schedule workflow**(cloud routine ではない)。根拠: [ADR-070](adr/adr-070-weekly-review-cloud-routine.md) § 実現可能性の未検証点の実測 — routine の `jj git push` はローカル hook(`jj-push-guard`)に阻まれ、例外新設は「自律 push 経路の新設」= 採用バー超え。Actions は workflow step が push する Phase B([ADR-067](adr/adr-067-phase-b-unattended-fix-push.md))と同構造でこの問題が発生せず、`claude/` prefix ブランチは ruleset 除外とも整合する。 - 2. **WP-19 ステップ 2(背圧)を本 WP の PR 1 へ前倒し統合**。根拠: [ADR-052](adr/adr-052-autonomy-execution-boundary-classes.md) 原則 5 は背圧なしの draft-pr クラス有効化をアンチパターンとして明示的に禁止し、着手時点の `lib-autonomy-policy` は `backpressure_connected()` が `DraftPr => false` 固定で**構造的に deny していた**。WP-17 の kill-switch 前倒しと同じ判断。→ PR 1 で解消済み(設計は [ADR-071](adr/adr-071-draft-pr-backpressure.md))。 - 3. **タスク台帳 = [claude-code-web-tasks.md](claude-code-web-tasks.md)**(旧案「todo-summary へ自律実行可列を追加」は置き換え)。同ファイルは既に「Web 実行可の判定基準 + curated なタスク表 + 着手フロー」を持ち、夜間ループの選択元に転用できる。ただし現状は ephemeral(全タスク land で retire)なので、**「定期更新される管理台帳」へ lifecycle を改訂**し、自律実行可の判断は **weekly-review と同じタイミングで定期更新**する(WP-19 ステップ 3 の監査ループと接続)。 - -- **PR 構成(新規 3 本)**: - 1. **PR 1: 背圧実装 + ADR 起票(M)— 実装済み(2026-08-06、[ADR-071](adr/adr-071-draft-pr-backpressure.md))**。閾値判定の層は実装時判断で **(a) gate 内**を採った(`GateInputs` に実測値と閾値を渡す)。`Operation::backpressure_connected()` は廃し、`requires_draft_backpressure()`(指標の要求のみ・状態を持たない)と `GateInputs::{open_draft_prs, max_open_draft_prs}`(状態)へ分けて二重管理を避けた。閾値は `autonomy-config.toml` の `[autonomy] max_open_draft_prs = 3`。実 exe による drill 12 シナリオと unit test 40 件で実測を固定済み。SaaS 課金・上限事実(§ 2)の最新値再確認と永続化も同 ADR で完了。 - 2. **PR 2: タスク台帳のブラッシュアップ(docs、S)— 実装済み(2026-08-06、[#362](https://github.com/aloekun/claude-code-hook-test/pull/362))**。stale 行 2 件(順位 120 / 134、どちらも land 済み)を削除し棚卸し履歴 section を新設。無人可の 2 段階分類を導入して 14 件中 7 件をユーザー承認のうえマーク(見送り 7 件も理由を表で明示)。lifecycle は「空になっても retire しない」定期更新台帳へ改訂。weekly-review への接続は新 step を足さず既存の観点⑤(`review-todo-whole` facet)に Criterion 3 として相乗りさせた。 - 3. **PR 3: 夜間 workflow(schedule、M-L)— マージ済み(2026-08-07、[#363](https://github.com/aloekun/claude-code-hook-test/pull/363)、[ADR-072](adr/adr-072-nightly-todo-loop.md))。2026-08-08 の schedule で初回実走し allow 経路が成立**。タスク選択は新規 exe `cli-nightly-task-select`(実装時判断で shell ではなく Rust を採用 — markdown table の境界に回帰テストを書く場が要るため)。`.github/workflows/nightly-todo.yml` が 18 step で選択 → 実装 → コストフィルタ(`cargo test` + `cargo clippy`)→ **clean publish tree の用意** → ガードレール禁止リスト → **ゲート資産の改ざん検知** → gate → **App token 発行** → draft PR 作成を回す。schedule は毎日 03:00 JST(2026-08-06 ユーザー確認)。**push / PR 作成は workflow step が gate 経由で実行し、agent は push の主体にしない**(ADR-067 と同型)。 - - 改ざん検知と clean publish tree はいずれも pre-push security review の REJECT を受けて追加した([ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 7 / 決定 9)。後者は「agent が `work/.git` を書き換えると App token を持つ step で任意コマンドが走る」経路への対処で、危険な設定キーの列挙(deny-list)で 2 回連続レビュー漏れを指摘されたため、**Implement 終了後に新規 clone した作業ツリーで git 操作を行う**構造へ切り替えた。**App token は Windows CI を draft PR へ紐づけるために導入した**(同 決定 8)— `GITHUB_TOKEN` で作成した PR は `pull_request` run が承認待ちになり、人間が Approve するまで `ci.yml` が動かない。Windows を主開発環境とする本プロジェクトで、2 OS 検証を人間の操作待ちにする設計は採れないため(2026-08-07 ユーザー判断)。PAT ではなく App を使うのは、オーナーの PAT が Repository admin として ADR-067 の ruleset backstop を bypass してしまうため。 - - これに伴い workflow 内の検証は**コストフィルタ**(ubuntu 単独、無駄な draft PR を作らないための足切り)と位置づけ直し、**品質の保証は PR に紐づく `ci.yml`(2 OS)**が担う形にした。 - -- **PR chain 宣言([ADR-069](adr/adr-069-pr-chain-declaration.md) 決定 1)— 充足済み**: PR 1 が導入した以下は PR 3 が消費する。PR 3 は PR 1 のブランチ(`feat/draft-pr-backpressure`)にスタックしているため、両者は同一チェーン内で対応が閉じている。 - - | PR 1 が導入するもの | PR 3 の消費側(`.github/workflows/nightly-todo.yml`) | - |---|---| - | `cli-autonomy-gate` の `--open-draft-prs ` フラグ | `Pre-flight gate` / `Gate draft PR creation` の 2 step が、`Count open claude/ drafts and in-flight ranks` step の `gh pr list` 結果(`isDraft` かつ `claude/` prefix の件数)を渡す | - | `autonomy-config.toml` の `[autonomy] max_open_draft_prs` | 同 2 step が `--config master-ref/autonomy-config.toml` を渡し、master ref の写しから読ませる(kill-switch の `enabled` と同じ経路・同じファイル) | - | `lib_autonomy_policy::Operation::DraftPr` の許可経路 | 同 2 step が `--operation draft-pr` で呼び、`Gate draft PR creation` が exit 0 のときだけ `Push branch and open draft PR` へ進む | - - この順序は逆にできない。[ADR-052](adr/adr-052-autonomy-execution-boundary-classes.md) 原則 5 が背圧の接続を draft-pr クラス有効化の**前提条件**としているため、背圧が先に land する必要がある(WP-17 の kill-switch 先行と同じ構造)。 - - **PR 2 → PR 3 の実行時依存**: PR 3 の workflow は台帳の「無人可」列を読む。PR 2 が未マージのままだと `cli-nightly-task-select` は exit 2(無人可 列を持つ表が無い)で止まる。**これは設計どおりの fail-closed** で、静かな no-op にはならない([ADR-072](adr/adr-072-nightly-todo-loop.md) § 検証記録の実データ確認)。PR 3 のコードは PR 2 に依存しないため、CI は独立に green になる。 - -- **運用ノート**: クラウドは使い捨てクローンのため jj workspace 分離は不要。ローカルで同ループを回す場合のみ [ADR-045](adr/adr-045-jj-workspace-parallel-sessions.md) の workspace を使う。稼働後 1 週間は run 頻度と Max 枠消費を観測して頻度調整。 -- **受け入れ基準**: - - | 基準 | 状態 | - |---|---| - | 背圧の決定論層 drill(12 シナリオ、実 exe) | **充足**(PR 1、[ADR-071](adr/adr-071-draft-pr-backpressure.md) § 検証記録) | - | タスク選択の境界固定(unit test 25 件 + 実データ選択) | **充足**(PR 3、[ADR-072](adr/adr-072-nightly-todo-loop.md) § 検証記録) | - | **実走スモーク — 有効時のみ `claude/nightly-*` の draft PR が作られること** | **充足**(2026-08-08、[PR #365](https://github.com/aloekun/claude-code-hook-test/pull/365) = `claude/nightly-203`)。ただし **`workflow_dispatch` ではなく schedule の本番 run が先に消化した** — `AUTONOMY_ENABLED` を立てた時点で schedule も有効になるため。結果は成功だったが、観測装置の準備前に無人 run が走る構造だった点は [ADR-072](adr/adr-072-nightly-todo-loop.md) § 残課題 に記帳 | - | **停止側の実走 — 無効時に何も作られないこと**(`AUTONOMY_ENABLED` の 3 状態 = `'true'` / `'false'` / 未設定 で dispatch し、`false` と未設定では job 起動・ブランチ作成・draft PR・App token のいずれも発生しないことを確認) | **充足**(2026-08-08、ユーザー実測)。`'false'` と未設定の 2 状態で **`dry_run` をオフ(= push / PR 作成をする設定)**にして dispatch し、2 回とも job が skip。確認後 `'true'` へ復旧済み。**これで WP-17 の残課題(明示的 `false` と未設定の実走未観測、[ADR-066](adr/adr-066-autonomy-global-kill-switch.md) bounded lifetime)も同時に埋まった** | - | スモークの同梱観測 **10 項目**(起票時の 8 件 + #364 で追加した停止側 1 件 + 順位 379 で追加した tool scope deny 1 件。内訳は [ADR-072](adr/adr-072-nightly-todo-loop.md) § 実走スモークの表が正) | **8 充足 / 1 不成立 / 1 保留**。**充足** = `AUTONOMY_ENABLED` の完全一致起動・`claude/nightly-*` の ref 作成・**App token 作成 PR に `ci.yml` の 2 OS run が紐づくこと**(決定 8 の核心)・決定 7 の照合が誤検知しないこと(1 run)・`publish/` の rsync が過不足なく運ぶこと・**停止側 2 状態**・**tool scope deny**・allowlist 判定不能を除く。**不成立** = WP-17 残課題の Phase B 自動起動(CodeRabbit が draft を自動レビューしないため契機が発生しない → [ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 11 で対処。`coderabbitai[bot]` allowlist の要否も同経路のため判定不能で、決定 11 が効いてから再判定)。**保留** = トークン露出(初版 probe の設計欠陥を解消してから 1 回で観測) | - | **WP 全体**: 2 週間の試験運用で無人 draft PR の採用率(人間がマージした割合)を測定。**50% 超で継続・拡大、未満なら対象クラスを絞って再試行** | **未着手**(スモーク完走後に開始)。測定は weekly-review の自律アクション棚卸し(WP-19 ステップ 3)に載せて仕組み化する | - - なお採用率 50% は根拠のある閾値ではなく、2 週間・最大 14 件(背圧により実際はより少ない)では統計的な意味を持たない([ADR-072](adr/adr-072-nightly-todo-loop.md) § 欠点)。判断材料の 1 つとして扱う。 +| 内容 | 管理先 | 期限 / 条件 | +|---|---|---| +| スモーク残 1 項目: `cargo` サブプロセスへのトークン露出(順位 374 の残り。**意図的保留** — 初版 probe の設計欠陥を解消した安全な probe を設計してから 1 回で観測。ADR-072 決定 5 の Bash 再付与判断の材料でもある) | ADR-072 § 残課題 | 急がない(Bash 非付与が保守側) | +| 決定 11 の実測: CodeRabbit が bot(App)投稿の `@coderabbitai review` に反応するか。無反応なら 3 択で再判断。`coderabbitai[bot]` allowlist の要否も同時に再判定(WP-17 残課題と共通) | ADR-072 § 残課題 | 次回夜間 run で最優先 | +| **採用率 2 週間測定**(WP 全体の受け入れ基準。人間がマージした割合 50% 超で継続・拡大 — 参考値であり統計的意味は無い、ADR-072 § 欠点)。測定は weekly-review の自律アクション棚卸し(WP-19 ステップ 3)へ載せて仕組み化。**開始起点 = スモーク完走後(2026-08-09 ユーザー決定)**。完走の定義は決定 11 の実測完了までとし、意図的保留のトークン露出は完走条件に含めない | ADR-072 § 試験運用判断基準 | 2026-11-06 までに判定 | +| 稼働後 1 週間の run 頻度・Max 枠消費を観測して schedule 頻度を調整 | 運用ノート(本表のみ) | 稼働中 | +| 順位 382(injection payload regression test。依存先の順位 380 完了で unblock)/ 順位 383(`is_separator_row` のパイプ検証欠落) | [todo-summary2.md](todo-summary2.md) | 🔧 Tier 2、任意 | +| 順位 375-377(レビュー対応チェックリスト / push-runner bookmark 前進 / 防御の格上げ判断) | [todo-summary2.md](todo-summary2.md) | 🔧 2〜💎 3、WP-18 完了後 | + +ローカルで同ループを回す場合のみ [ADR-045](adr/adr-045-jj-workspace-parallel-sessions.md) の workspace を使う(クラウドは使い捨てクローンのため分離不要)。 ### WP-19: 常時性ガード diff --git a/docs/todo-summary2.md b/docs/todo-summary2.md index 0d0bd9a2..9888a348 100644 --- a/docs/todo-summary2.md +++ b/docs/todo-summary2.md @@ -133,11 +133,7 @@ | 375 | 🔧 Tier 2 | **レビュー指摘への対応時チェックリスト (fix 後の文書整合 / finding スコープ / 意図的 stale 表 / 技術的前提の検証)** | todo20.md | S | なし (WP-18 の 3 PR で同型の失敗が 4 件。いずれも変更の影響範囲を指摘された 1 点だけで見積もったこと、または前提を検証せず動いたことが共通項) | | 376 | 🔧 Tier 2 | **push-runner の bookmark 自動前進がスタック境界を壊す** | todo20.md | S | なし (2026-08-06 実観測。@ の祖先にあたる非 trunk bookmark を前進させ、レビュー済み PR #361 の bookmark が #363 の tip へ移動した。size gate が先に止めたため remote 影響は無し) | | 377 | 💎 Tier 3 | **夜間ループの防御を検知から防止へ格上げする判断** | todo20.md | M-L | 順位 374 + 2 週間の試験運用 (ADR-072 残課題 3 件。実運用の観測が判断材料で、観測前の着手は過剰設計。「不要」判断も正規の出口) | -| 378 | 🚀 Tier 1 | **台帳を ADR-035 の docs-only 除外パス表へ追加し code-equivalent として扱う (#363 Tier1 #1)** | todo20.md | XS | なし (順位 379-381 の前提。台帳だけを変える PR が緩い評価経路に乗るのを塞ぐ) | -| 379 | 🚀 Tier 1 | **夜間ループ agent の tool scope を `work/**` へ限定する (#363 Tier1 #2)** | todo20.md | S | 順位 378 (現行は `$GITHUB_WORKSPACE` 全体。決定 7 の改ざん検知が必要になっている根本原因) | -| 380 | 🚀 Tier 1 | **台帳フィールドを agent prompt へ untrusted data として明示 framing する (#363 Tier1 #3)** | todo20.md | M | 順位 378 (ADR-054 の 3 層防御の第 1 層) | -| 381 | 🚀 Tier 1 | **台帳由来 SUMMARY の draft PR 本文出力に screening を追加 (#363 Tier1 #4)** | todo20.md | S | 順位 378 (public repo では draft PR 本文も第三者に可視 = 攻撃者制御文字列の公開面) | -| 382 | 🔧 Tier 2 | **台帳 prompt injection payload の regression test (#363 Tier2 #1)** | todo20.md | M | 順位 380 (framing が入ってから、その framing が効くことを固定する) | +| 382 | 🔧 Tier 2 | **台帳 prompt injection payload の regression test (#363 Tier2 #1)** | todo20.md | M | なし (依存だった順位 380 の framing は 2026-08-08 実装済み = ADR-072 決定 13。順位 378-381 は完了・削除済み) | | 383 | 🔧 Tier 2 | **`is_separator_row` のパイプ検証欠落を塞ぐ + 回帰テスト (#363 Tier2 #2)** | todo20.md | S | なし (2026-08-07 実コード確認済み。bare `---` がセパレータ行として通る) | | 385 | 🔧 Tier 3 | **cli-pr-monitor の lock に liveness check が無く、プロセス死後も最大 30 分監視が skip される** | todo21.md | S | なし (2026-08-08 実測。stale 判定は経過時間 1800s のみで pid 生存を見ない。module doc に既知トレードオフとして明記済みのため「不要」判断も正規の出口) | | 386 | 🔧 Tier 2 | **監視・自動 fix 経路が積む空コミットで bookmark がずれ `pnpm merge-pr` / `pnpm push` が失敗する** | todo21.md | M | なし (2026-08-08 セッションで 7 回観測。`BOOKMARK_SEARCH_REVSETS` は @/@-/@-- の 3 段のみ。生成元は監視・自動 fix 経路と確定。深さ非依存 revset へ変える案が本命) | @@ -146,6 +142,7 @@ | 389 | 🚀 Tier 1 | **`Write(path)` tool-scope 指定子の no-op を検出する settings validator (#369 T1 採用)** | todo21.md | M | なし (CLI 2.1.218 で Write() は no-op = deny の silent 無効化。Edit() のみ機能。ADR-072 決定 12 に事実記録済み) | | 390 | 🔧 Tier 2 | **台帳 framing 区切りの定数と workflow リテラルの cross-file 一致を CI 検証 (#369 T2 採用)** | todo21.md | M | なし (LEDGER_DATA_FRAME_MARKER と ===BEGIN/END_LEDGER_DATA=== が対。片側変更で ADR-072 決定 13 の framing が破れる) | | 391 | 🔧 Tier 3 | **jj の落とし穴 (squash 方向・空コミットでの bookmark ずれ) を dev-conventions へ (#369 T3 採用)** | todo21.md | S | なし (本セッションで複数回踏んだ。コミット確定は describe+bookmark set、new は新作業時のみ、を明文化) | +| 392 | 🔧 Tier 3 | **push パイプラインの terminal outcome を telemetry へ記録し失敗回数・原因を機械集計可能にする** | todo21.md | M | なし (2026-08-09 WP-18 失敗頻度分析で構造化記録の欠落が判明。stage + reason code を ADR-055 系へ fail-open で追記し ADR-062 月次で集計。順位 386/387/376 の効果測定ベースラインにもなる) | **戦略**: Tier 1 を 2〜3 セッションで片付け → Tier 2 で ADR-032 の前提 + rate-limit + convergence cost 削減を進める → Tier 3 で ADR-032 を land + ドキュメント整備。Tier 4-5 は cleanup / 外部展開で daily efficiency への直接効果は小さい。 diff --git a/docs/todo20.md b/docs/todo20.md index b9ec7183..3caea2f2 100644 --- a/docs/todo20.md +++ b/docs/todo20.md @@ -290,12 +290,12 @@ #### 作業計画 -- [ ] #363 マージ後、`workflow_dispatch` (dry_run=true) でゲート通過までを確認 -- [ ] dry_run=false で draft PR 作成まで完走させる -- [ ] **停止側を実走で確認する** — `AUTONOMY_ENABLED` を `'false'` と未設定の 2 状態で dispatch し、job 起動・`claude/nightly-*` ブランチ作成・draft PR・App token 発行のいずれも発生しないことを確認する (成功経路だけの確認では kill-switch が効く証拠にならない) -- [ ] `ADR-072` の実走スモーク節にある 8 項目を観測し結果を同 ADR の検証記録節へ記帳 -- [ ] GitHub UI を触る過程で **順位 384 (外部設定の実体記録) を同時に実施する** — 実値はこの機会にしか揃わない -- [ ] 完走後、2 週間の採用率測定を開始する +- [x] draft PR 作成までの完走 (2026-08-08、schedule 初回実走 = PR #365。dispatch でなく本番 run が先に消化した経緯は [ADR-072](adr/adr-072-nightly-todo-loop.md) § 残課題) +- [x] **停止側の実走確認** (2026-08-08、`'false'` / 未設定 × dry_run オフで 2 回とも job skip。[ADR-066](adr/adr-066-autonomy-global-kill-switch.md) § 実走観測 2) +- [x] スモーク観測項目の記帳 (10 項目中 8 充足 / 1 不成立 = 決定 11 で対処 / 1 保留 = トークン露出。ADR-072 § 実走スモーク) +- [x] 順位 384 (外部設定の実体記録) の同時実施 (2026-08-08 完了、ADR-072 § 外部設定の実体) +- [ ] **残り: トークン露出 probe** — 初版 probe の設計欠陥を解消した安全な probe を設計してから 1 回で観測 (意図的保留、ADR-072 § 残課題) +- [ ] 決定 11 の実測 (CodeRabbit が bot 投稿の `@coderabbitai review` に反応するか) 完了後、2 週間の採用率測定を開始する (2026-08-09 ユーザー決定: トークン露出の保留は測定開始をブロックしない) - [ ] 本エントリ削除 + todo-summary2.md 行削除 #### 完了基準 @@ -399,80 +399,9 @@ ## #363 post-merge feedback 採用分 (2026-08-07 一括登録) -> WP-18 の最終 PR (#363、ADR-072) マージ後の post-merge-feedback が Tier 1 に 4 件・Tier 2 に 2 件を採用候補として挙げたもの。**うち 5 件 (378-382) が台帳 (`docs/claude-code-web-tasks.md`) 経由の prompt injection という 1 本の根から出ている。** 残る 383 は `is_separator_row` の markdown パース欠陥で根が異なり、同じ post-merge feedback で挙がったため同バッチに乗せただけである (§ 順序 も参照)。 +> WP-18 の最終 PR (#363、ADR-072) マージ後の post-merge-feedback 採用分。**うち順位 378-381 (台帳経由 prompt injection 対策の Tier 1 群 4 件) は 2026-08-08 に実装完了したため本ファイルから削除した** — 記録先: [ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 12 (tool scope 限定) / 決定 13 (untrusted framing) / 決定 14 (公開面 screening)、[ADR-035](adr/adr-035-doc-evaluation-policy.md) + `lib-docs-policy` (台帳の docs-only 除外、#368)。残るのは 382 (regression test) と 383 (`is_separator_row`、根が異なる独立の markdown パース欠陥) の 2 件。 > -> 発生源: 夜間ループは台帳の `内容` / `対象ファイル` / `注意` を**自由記述のまま無人 agent のプロンプトへ埋め込む**。agent は `$GITHUB_WORKSPACE` 全体に `Read/Edit/Write/Glob/Grep` を持ち、Guard step はパス名しか検査しない。台帳由来の文字列は draft PR 本文にもそのまま出る。 -> -> **実効リスクは現時点では低い** — 悪意ある台帳行を master へマージするのはユーザー自身であり、単独運用では外部からの注入経路が無い。しかし [ADR-054](adr/adr-054-prompt-injection-trust-boundary-defense.md) が扱う信頼境界の類型そのものであり、**夜間ループが定常運用に入り draft PR の流量が増えると前提が変わる**。 -> -> **期限**: 順位 374 (実走スモーク) の完了後、**定常運用開始前**。無期限に積んではならない。スモーク自体は `dry_run` で PR を作らないため本件の実害は無く、スモークを待たせる理由も無い。 -> -> **順序**: 378 → 379/381 (独立) → 380 → 382。378 は他 3 件の前提 (台帳変更が緩い評価経路に乗ると、対策そのものを迂回する台帳 PR が通りうる)。382 は 380 の framing が入ってからでないと固定する対象が無い。383 は独立。 - -### 台帳を ADR-035 の docs-only 除外パス表へ追加し code-equivalent として扱う - -> **動機**: [ADR-035](adr/adr-035-doc-evaluation-policy.md) の除外パス一覧に台帳が含まれておらず、**台帳だけを変える PR が docs-only の緩い評価経路に乗る**。台帳は「次に何を実装するか」を決める実行入力であり、拡張子が `.md` であることと危険度は無関係。 -> -> [ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 6 は同じ理由で台帳を Guard step の禁止リストへ入れているが、**PR 評価ポリシー側には同じ手当てが無い**という非対称が残っている。 -> -> **対処案**: ADR-035 の除外パス表へ 1 行追加し、参照している facet instructions 側の記述も同期する。 -> -> **実行優先度**: 🚀 Tier 1 — Severity High / Frequency Medium / Effort XS / Adoption Risk None。既存機構への 1 行追加で閉じられる。 - -#### 作業計画 - -- [ ] ADR-035 の除外パス表へ `docs/claude-code-web-tasks.md` を追加し、code-equivalent とする根拠を記す -- [ ] 除外パス表を参照している facet instructions を grep し、記述を同期する -- [ ] 台帳のみを変える PR が docs-only 判定にならないことを確認する - -### 夜間ループ agent の tool scope を `work/**` へ限定する - -> **動機**: 現行の `--allowedTools "Read,Edit,Write,Glob,Grep"` は**スコープ引数を持たない**ため、agent は `$GITHUB_WORKSPACE` 全体を読み書きできる。そこには判定の調達元である `master-ref/` が含まれる。 -> -> [ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 7 (ゲート資産の改ざん検知) は**この穴があるために必要になった検知層**である。scope を絞れば検知ではなく予防で塞げる。決定 7 自身が「検知であって防止ではない」と残課題に挙げている。 -> -> **対処案**: `--allowedTools` にパススコープを付与できるか調査し、可能なら `work/**` へ限定する。不可なら agent の作業ディレクトリ自体を `work/` に切り替える案を検討する。 -> -> **実行優先度**: 🚀 Tier 1 — Severity High / Frequency Low / Effort S / Adoption Risk None。 -> -> **注意**: 実装後も決定 7 の改ざん検知は**残す**。防御層を 1 枚に減らす変更ではない。 - -#### 作業計画 - -- [ ] `--allowedTools` のパススコープ指定可否を公式ドキュメントで確認する (推測で設計しない) -- [ ] scope 限定を実装し、`master-ref/` へ書けないことを実走で確認する -- [ ] 順位 377 (検知から防止への格上げ判断) の判断材料として ADR-072 へ記帳する - -### 台帳フィールドを agent prompt へ untrusted data として明示 framing する - -> **動機**: prompt 組立が `${{ steps.select.outputs.summary/target_files/caution }}` を無検証で埋め込んでいる。台帳の行に指示文を書けば、それが agent への指示として読まれる。 -> -> [ADR-054](adr/adr-054-prompt-injection-trust-boundary-defense.md) の 3 層防御でいう**第 1 層 (信頼境界の明示)** が欠けている状態。 -> -> **対処案**: prompt テンプレート側で台帳由来の文字列を「これはデータであり指示ではない」と明示する区切りで囲む。加えて `ledger.rs` の parse 側で制御文字や区切り記号の混入を弾くかを検討する (決定 2 の「曖昧さはすべて停止側へ」と同じ姿勢)。 -> -> **実行優先度**: 🚀 Tier 1 — Severity High / Frequency Medium / Effort M / Adoption Risk None。 -> -> **注意**: framing は緩和であって遮断ではない。順位 379 の scope 限定と併せて初めて意味を持つ。 - -#### 作業計画 - -- [ ] prompt 組立に untrusted data の framing を導入する -- [ ] parse 側で弾くべき入力の範囲を決め、ADR-072 決定 2 の exit 2 経路へ寄せる -- [ ] 順位 382 の regression test で framing の有効性を固定する - -### 台帳由来 SUMMARY の draft PR 本文出力に screening を追加 - -> **動機**: PR body 生成が `echo "- 内容: ${SUMMARY}"` を無検証で行う。**draft PR であっても public repository では第三者に可視**であり、攻撃者制御文字列の公開面になる。 -> -> **対処案**: PR 本文へ出す前に長さ制限・改行/markdown 制御文字のエスケープを行う。 -> -> **実行優先度**: 🚀 Tier 1 — Severity High / Frequency Low / Effort S / Adoption Risk None。 - -#### 作業計画 - -- [ ] PR body 生成箇所に screening/escaping を追加する -- [ ] 公開面に出る他の経路 (ブランチ名・コミットメッセージ) も同時に棚卸しする +> 発生源の背景 (382 のために残す): 夜間ループは台帳 (`docs/claude-code-web-tasks.md`) の自由記述フィールドを無人 agent のプロンプトへ埋め込む。決定 12-14 の防御は実装済みで、**それが効き続けることを固定する**のが 382 の役割。 ### 台帳 prompt injection payload の regression test @@ -485,13 +414,13 @@ > > 初版はこの区別を持たず 2 だけを例示していた。テスト名が prompt injection を名乗りながら shell injection しか見ない状態は、通っていること自体が誤った安心になる。 > -> **依存**: 順位 380 (framing 実装)。framing 前にテストだけ書いても固定する対象が無い。 +> **依存**: 解消済み — 順位 380 の framing は 2026-08-08 実装済み ([ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 13)。着手可能。決定 13 の unit test (marker / 不可視文字の拒否) は parse 層のみを固定しており、**prompt 組立と自然言語 adversarial payload の系統は未固定**なので本エントリの価値は残る。 > > **実行優先度**: 🔧 Tier 2 — Severity Medium / Frequency Medium / Effort M / Adoption Risk None。 #### 作業計画 -- [ ] 順位 380 の実装後、injection payload fixture を追加する +- [ ] injection payload fixture を追加する (順位 380 の framing は実装済みのため着手可能) - [ ] **自然言語 adversarial payload** と **shell / パース形式 payload** を別 fixture に分ける (前者が prompt injection の本命、後者はパース堅牢性) - [ ] fixture は **good / bad の対**で用意し、**1 fixture = 1 条件**に保つ (assert は最小限、payload の由来をコメントで辿れるようにする) @@ -513,8 +442,3 @@ - [ ] bare `---` がセパレータ行として通らないことの回帰テストを追加する - [ ] 表の直前に水平線がある台帳で選択が壊れないことを確認する ---- - -## 夜間ループの外部設定の実体記録 (2026-08-07 登録 → 2026-08-08 完了・削除) - -> **順位 384 は完了したため本エントリを削除した (2026-08-08)。** 外部設定の実体は [ADR-072](adr/adr-072-nightly-todo-loop.md) § 外部設定の実体 に記録済み (App 名 `nightly-todo-aloekun` / インストール範囲 `claude-code-hook-test` のみ / 付与権限 Contents・PR write, Metadata read, **Workflows なし** / variable・secret の登録先 / 欠落時の倒れ方の表 / 再構築手順、秘密値そのものは非記録)。ADR-051 の 3 点 (相互参照コメントを workflow へ・期待値の組み合わせ表を ADR へ・両側同一 PR) も #369/#370 で充足。summary2 の順位 384 行も削除済み。 diff --git a/docs/todo21.md b/docs/todo21.md index 1b65e837..415913db 100644 --- a/docs/todo21.md +++ b/docs/todo21.md @@ -179,3 +179,32 @@ #### 完了基準 - コミット確定・squash 方向・bookmark ずれ復旧の 3 点が、**再現可能な初期状態つきで**根拠を添えて dev-conventions に存在すること。 + +--- + +## WP-18 失敗頻度分析の follow-up (2026-08-09 登録) + +### push パイプラインの terminal outcome を telemetry へ記録し、失敗回数・原因を機械集計可能にする + +> **動機**: 2026-08-09 の WP-18 失敗頻度分析で、**パイプライン失敗の回数・原因に構造化記録が無い**ことが判明した。定量は `.takt/runs/` のディレクトリ数からの推定に頼り (pre-push run 数 ÷ マージ PR 数 = 08-07 は 18 run/1 PR でベースライン 1.9 の約 9 倍)、失敗の内訳 (レビュー REJECT / quality gate / jj push 段の bookmark 解決失敗など) は trace.md と todo エントリの突き合わせでしか復元できなかった。[ADR-055](adr/adr-055-firing-telemetry-collection.md) の telemetry は rule/preset/hook の**発火**のみを記録し、パイプラインの**結末**は対象外。 +> +> **対処案**: push-runner の terminal outcome (成功 / 失敗した stage + reason code) を telemetry へ 1 行追記する。reason は自由文ではなく **stage + 機械可読 code** (例: `review-reject` / `quality-gate` / `jj-push-bookmark-resolution` / `regate`) にする。集計は `cli-telemetry-report` (ADR-062 月次レビューの決定論 exe) へ載せ、月次で「失敗率と内訳の推移」を読める形にする。順位 386/387/376 の対処が入った後の**効果測定**と、未知の失敗モードの早期発見が主目的。merge-pipeline / pr-monitor への同型展開は push-runner で型が固まってから検討する。 +> +> **設計上の注意**: (a) telemetry は助言層なので **fail-open** — 記録の失敗がパイプライン本体の exit code を変えてはならない ([ADR-043](adr/adr-043-security-gates-fail-closed.md))。(b) ADR-055 の firing event schema に outcome event を混ぜるか別ファイルにするかは、既存 `firings-*.jsonl` の後方互換 (cli-telemetry-report のパーサ) を確認して決める。 +> +> **参照**: [ADR-055](adr/adr-055-firing-telemetry-collection.md)、[ADR-062](adr/adr-062-monthly-harness-roi-review.md)、[ADR-015](adr/adr-015-push-runner-takt-migration.md) (push-runner)、順位 386/387/376 (効果測定の対象となる再発防止策)。 +> +> **実行優先度**: 🔧 Tier 3 — Severity Low (観測の欠落であり機能障害ではない) / Frequency Medium (push のたびに記録機会) / Effort M / Adoption Risk Low (fail-open を守る限り本体に影響しない)。順位 386/387 の対処より先に入れると効果測定のベースラインが取れる点は考慮に値する。 + +#### 作業計画 + +- [ ] push-runner の terminal 出口 (成功 / 各失敗段) を洗い出し、stage + reason code の一覧を定義する +- [ ] ADR-055 の firing event と同居させるか別ファイルにするかを、`cli-telemetry-report` パーサの後方互換を確認して決める +- [ ] outcome 記録を実装し、記録失敗がパイプラインの exit code を変えないことをテストで固定する +- [ ] `cli-telemetry-report` に期間指定の失敗集計 (回数・stage 別内訳) を追加する + +#### 完了基準 + +- `pnpm push` の各試行が terminal outcome (成功 / 失敗 stage + reason code) を機械可読で残すこと。 +- `cli-telemetry-report` で月次レビューが失敗率・内訳を読めること。 +- telemetry 書き込み失敗時もパイプライン本体の挙動・exit code が変わらないこと (fail-open のテストで固定)。