From ec6f40cda1630cff67ea1f5dbfd6a4992b083a60 Mon Sep 17 00:00:00 2001 From: aloekun Date: Mon, 10 Aug 2026 18:32:58 +0900 Subject: [PATCH] =?UTF-8?q?docs(adr):=20bot=20=E4=BD=9C=E6=88=90=20PR=20?= =?UTF-8?q?=E3=81=8C=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E3=81=95=E3=82=8C?= =?UTF-8?q?=E3=81=AA=E3=81=84=E5=88=B6=E7=B4=84=E3=81=A8=20identity=20?= =?UTF-8?q?=E5=88=86=E9=9B=A2=E3=81=AB=E3=82=88=E3=82=8B=E8=A7=A3=E6=B1=BA?= =?UTF-8?q?=E3=82=92=E8=A8=98=E9=8C=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2026-08-10 の実測で、夜間 PR にレビューが付かない原因が判明した。ADR-072 決定 15 は 「draft をやめれば auto_review に乗る」を前提にしていたが、これは誤りで、実際の ブロック要因は PR の author が bot であることだった。draft 廃止後も #379 は draft=false のまま 10 時間 26 分 無反応だった。 ## ADR-019: CodeRabbit の挙動の真実源を置く 「CodeRabbit がいつレビューするか」の真実源を ADR-019 に集約した。CodeRabbit は bot 作成 PR を自動スキップする組み込み挙動を持ち (公式 "Auto Review Skipped — Bot user detected")、設定では制御できない。6 経路すべての実測表を残した: - bot 作成 PR の auto_review → skip - bot が @coderabbitai review を投稿 → 無視 - 人間が投稿 → 動く (4〜5 秒) - CodeRabbit を reviewer に要求 → HTTP 422 (App は collaborator でない) - PR を reopen → 無効 - 設定で bot を許可 → スキーマに該当キーが無い (全数確認) ignore_usernames は除外専用で allowlist 方向は無く、本リポジトリでは未設定なので 原因ではない。skip 通知の有無は判断材料にならない (本リポジトリでは通知すら出ず、 プラン差か実装差かは未解明) ことも明記した。 ## ADR-072: 決定 15 の前提訂正と決定 16 の新設 決定 15 は維持する。レビューが付かない理由の説明は誤っていたが、commitment 点を マージ 1 点へ集約する判断は ADR-052 原則 2 の改訂として独立に成立している。 教訓として、症状と目に付いた差分 (draft) を因果で結んだこと、drafts: false という もっともらしい説明が実在したことが誤診を後押ししたこと、対処後に同じ症状が続くかを 確かめる前に「解決した」と記録したことを残した。 決定 16 (新設): レビュー要求だけを人間 identity で出す。PR の作成者は bot のまま 維持し、変えるのは「誰がレビューを頼むか」だけ。PAT は Pull requests: write のみで push もマージもできないため、決定 8 が却下した「push に使う PAT」には当たらない。 nightly-todo.yml の中に置かない理由を信頼境界として記録した。あの job は未信頼 agent が 実装を書き cargo test がそれを実行する job で、スモーク未解決の「cargo サブプロセスへの トークン露出」の対象でもある。そこに人間資格情報を置かない。決定 8 § 帰結の 「資格情報を足すと、その step で何が実行されうるかを洗い直す」の 2 例目にあたる。 pull_request_target の攻撃面 (fork PR から secrets へ到達) と封じ方、kill-switch を 2 面とも見る実装、投稿しただけで成功としない検証も記録した。決定 11 の失敗の本質は 助言層を fail-open にしたことではなく、効果の観測を用意しなかったことである。 実走検証 (2026-08-10): PR 作成から CodeRabbit 反応まで 15 秒、完全自動。検証 step は 実際に働いた (1 回目は反応なし、2 回目で検出)。 ## スモーク未確定 (a)(b) の位置づけが変わった Phase B 本体の到達と coderabbitai[bot] allowlist の要否は、いずれも「CodeRabbit が 夜間 PR にコメントすること」を起動契機とするため、レビューが付かない間は観測機会 そのものが無かった。決定 16 でレビューが毎回付くようになり、未確定の理由が 「機構が無い」から「事象待ち」へ変わった。 ## 採用率測定の開始起点が確定 2026-08-10。1 件目は #381。中間確認 2026-08-24、判定期限 2026-11-06。 CODERABBIT_TRIGGER_PAT の実体 (権限・対象・期限・失効時の倒れ方) を ADR-072 § 外部設定の実体へ記録した (ADR-051 決定 1)。秘密値そのものは記録しない。 --- ...adr-019-coderabbit-review-hybrid-policy.md | 31 ++++++- docs/adr/adr-072-nightly-todo-loop.md | 84 +++++++++++++++++-- docs/harness-improvement-plan.md | 6 +- 3 files changed, 105 insertions(+), 16 deletions(-) diff --git a/docs/adr/adr-019-coderabbit-review-hybrid-policy.md b/docs/adr/adr-019-coderabbit-review-hybrid-policy.md index d000368a..570583cf 100644 --- a/docs/adr/adr-019-coderabbit-review-hybrid-policy.md +++ b/docs/adr/adr-019-coderabbit-review-hybrid-policy.md @@ -150,13 +150,36 @@ WP-03 は 2026-04-19 で却下した「rate-limit 耐性 (超過後の auto-retr - **従来**: 初回レビュー 1 + fix push ごとの自動増分レビュー N = `1 + N` 回。 - **WP-03**: 初回レビュー 1 + fix 束ねごとの明示レビュー 1 = `1 + (iteration 数)` 回。push 毎ではなく「レビューしてほしい確定タイミング」のみ消費し、中間 push (rebase / cleanup 等) が誤ってレビューを消費しない。 -#### 夜間ループ PR の消費 (2026-08-09 追記、ADR-072 決定 15) +#### CodeRabbit は bot 作成 PR を自動レビューしない (2026-08-10 実測で確定) -夜間ループ ([ADR-072](adr-072-nightly-todo-loop.md)) が停止点を draft PR から**通常 PR**へ移したため、**夜間 PR 1 件につき初回自動レビュー 1 回**を消費するようになった。従来は `auto_review.drafts: false` により夜間 PR が丸ごとレビュー対象外で、**quota を一切消費しない代わりに一度もレビューされなかった**。 +**本節が本リポジトリにおける「CodeRabbit がいつレビューするか」の真実源である。** ADR-072 の夜間ループがこの制約に真正面から当たったため、経路を全て実測して確定させた。 -**消費量そのものは増えていない。** ADR-072 決定 11 (撤回済み) が投げようとしていた明示トリガー 1 回と同量で、起動経路が「明示トリガー」から `auto_review` に変わるだけである。ただし**クォータ設計の前提は変わる** — 上の消費モデルは人間が開く PR を数の母数にしていたが、そこへ毎晩最大 1 件が加わる。背圧 ([ADR-071](adr-071-draft-pr-backpressure.md)) の閾値が、この母数の実効上限になる。 +CodeRabbit には **PR の author が bot なら自動レビューをスキップする組み込み挙動**がある (公式メッセージ "Auto Review Skipped — Bot user detected")。設定ではなくプラットフォーム側の判定で、`.coderabbit.yaml` からは制御できない。 -`reviews.auto_review.drafts` は `false` のまま変えない。夜間 PR が draft でなくなったので設定を触る必要がなく、人間が意図的に draft で開く PR を対象外に保つ意味は残る。 +| 経路 | 結果 | 根拠 | +|---|---|---| +| bot 作成 PR の `auto_review` | **skip** | [#379](https://github.com/aloekun/claude-code-hook-test/pull/379) が `draft=false` で 10 時間 26 分 無反応。人間作成の #376 / #377 は 33 秒 / 18 秒で反応 | +| bot が `@coderabbitai review` を投稿 | **無視** | [#373](https://github.com/aloekun/claude-code-hook-test/pull/373) で App 投稿が 10 時間無反応 → 同一 PR・同一文言で人間が投稿すると 4 秒で応答 | +| 人間が `@coderabbitai review` を投稿 | **動く** | 上記 / #378 は 5 秒で応答 | +| CodeRabbit を reviewer に要求 | **API が拒否** | HTTP 422 `Reviews may only be requested from collaborators` (CodeRabbit は App であり collaborator ではない) | +| PR を reopen | **無効** | 状態遷移では skip が解除されない (2026-08-10 実測) | +| 設定で bot を許可 | **キーが存在しない** | [設定スキーマ](https://coderabbit.ai/integrations/schema.v2.json) を全数確認。username 系は `ignore_usernames` (除外専用) のみで allowlist 方向は無い。`chat.allow_non_org_members` は説明文に "This does not affect automatic PR review eligibility" と明記 | + +**`ignore_usernames` は原因ではない。** 本リポジトリの `.coderabbit.yaml` は同キーを設定しておらず (既定 `[]`)、`ignore_title_keywords` にも該当しない。設定側に原因は無く、**bot 判定そのもの**である。 + +**skip 通知の有無は判断材料にならない。** 公開事例では skip 時に "Auto Review Skipped" コメントが出るが、本リポジトリの #365 / #379 では**通知すら投稿されなかった**。`reviews.review_status` で抑制できるとされるが本リポジトリは未設定で、プラン差か実装差かは**未解明**。**通知が無いことは bot 判定が無い証拠にはならない**。 + +##### 唯一の経路 = 人間 identity のコメント投稿 + +上表のとおり、**人間 identity で `@coderabbitai review` を投稿する以外に自動化できる経路が無い**。これは消去法ではなく全経路の実測による。実装は [`review-request.yml`](../../.github/workflows/review-request.yml) が担い、設計判断は [ADR-072](adr-072-nightly-todo-loop.md) 決定 16 に記録した。 + +##### quota への影響 + +夜間 PR は **1 件につき明示トリガー 1 回**を消費する。`auto_review` には乗らないため、上の消費モデル (`1 + iteration 数`) の母数へ毎晩最大 1 件が加わる形になる。背圧 ([ADR-071](adr-071-draft-pr-backpressure.md)) の閾値がこの母数の実効上限である。 + +消費量は ADR-072 決定 11 (撤回済み) が意図していた量と同じで、**変わったのは投稿者の identity だけ**である。 + +`reviews.auto_review.drafts` は `false` のまま変えない。夜間 PR が draft でなくなったので触る必要がなく、人間が意図的に draft で開く PR を対象外に保つ意味は残る。 #### 既知の制約 diff --git a/docs/adr/adr-072-nightly-todo-loop.md b/docs/adr/adr-072-nightly-todo-loop.md index 13c8d274..c57e310a 100644 --- a/docs/adr/adr-072-nightly-todo-loop.md +++ b/docs/adr/adr-072-nightly-todo-loop.md @@ -2,7 +2,7 @@ ## ステータス -試験運用 (2026-08-06、2026-08-09 に停止点を draft PR から通常 PR へ変更) +試験運用 (2026-08-06、2026-08-09 に停止点を draft PR から通常 PR へ変更、2026-08-10 にレビュー要求経路を確立) > [ADR-052](adr-052-autonomy-execution-boundary-classes.md) の自動実行可クラスのうち **PR 作成 (autonomous-pr クラス)** を、[ADR-066](adr-066-autonomy-global-kill-switch.md) の kill-switch と [ADR-071](adr-071-draft-pr-backpressure.md) の背圧の上に実装する。無人 fix push ([ADR-067](adr-067-phase-b-unattended-fix-push.md)) の次の段で、**自律 actor が初めて「新しい成果物」を作る**経路になる。 > @@ -241,7 +241,9 @@ pre-push simplicity review はここを「他の停止点と同様に graceful d > > 下記「未検証」が挙げていた仮説 (bot 同士のループを避けるため他 bot のコメントを無視する実装) が、そのまま実証された形である。**明示トリガーという方式自体は無効ではない** — [ADR-019](adr-019-coderabbit-review-hybrid-policy.md) の fix push 後トリガーは現在も機能している。効かないのは投稿者が bot の場合だけで、ADR-019 側は `cli-pr-monitor` がローカルの `gh` = **ユーザー資格情報**で投稿しているために成立していた。本決定は「ADR-019 と同型」と判断したが、**同型だったのはコマンド文字列だけで、投稿者の種別が違っていた**。 > -> **代替解は順位 394 の draft 廃止**である。夜間ループが通常 PR を作れば `.coderabbit.yaml` の `auto_review.enabled: true` による初回レビューに自然に乗り、明示トリガーという回避策そのものが不要になる。「draft で止める」という制約は、トリガーの別 (ユーザー指示 / 自動採択) で扱いを区別せず commitment 点をマージ 1 点へ集約する判断 (2026-08-09 ユーザー決定) により外した — 下記の「ready 化は ADR-052 の commitment 点を侵す」という前提はこの決定で失効している。 +> **撤回したのは「投稿者が bot である」ことであって、明示トリガーという方式ではない (2026-08-10 追記)。** 当初はこの区別が曖昧なまま「代替解は draft 廃止」と書いたが、それは誤りだった (決定 15 § 前提の訂正)。方式は決定 16 が**投稿者を人間 identity にして復活させ**、実走で成立を確認している。 +> +> ~~**代替解は順位 394 の draft 廃止**である。夜間ループが通常 PR を作れば `.coderabbit.yaml` の `auto_review.enabled: true` による初回レビューに自然に乗り、明示トリガーという回避策そのものが不要になる。~~「draft で止める」という制約は、トリガーの別 (ユーザー指示 / 自動採択) で扱いを区別せず commitment 点をマージ 1 点へ集約する判断 (2026-08-09 ユーザー決定) により外した — 下記の「ready 化は ADR-052 の commitment 点を侵す」という前提はこの決定で失効している。 > > **教訓**: 未検証事項として自分で書き出した仮説を、その検証前に本番経路へ載せた。決定 10 の例外として `continue-on-error` を付けたため run は green のままで、**失敗が 10 時間気づかれなかった**。「投稿が成功したか」は観測できても「相手が反応したか」は観測していない — 助言層の fail-open は、効果の観測を別に用意して初めて成立する。 > @@ -317,6 +319,12 @@ pre-push simplicity review はここを「他の停止点と同様に graceful d ### 15. 停止点を draft PR から通常 PR へ移す (2026-08-09) +> **前提の訂正 (2026-08-10)**: 本決定は「draft をやめれば `auto_review` の初回レビューに自然に乗る」を根拠にしていたが、**この因果は誤りだった**。実際のブロック要因は draft ではなく **PR の author が bot であること**で、draft を廃止しても夜間 PR にレビューは付かなかった ([#379](https://github.com/aloekun/claude-code-hook-test/pull/379) が `draft=false` で 10 時間 26 分 無反応)。制約の全体像は [ADR-019](adr-019-coderabbit-review-hybrid-policy.md) § CodeRabbit は bot 作成 PR を自動レビューしない、解決は決定 16 を見よ。 +> +> **決定そのものは維持する。** レビューが付かない理由の説明は誤っていたが、「commitment 点をマージ 1 点に集約する」という判断は [ADR-052](adr-052-autonomy-execution-boundary-classes.md) 原則 2 の改訂として独立に成立しており、draft へ戻す理由は無い。 +> +> **教訓**: 症状 (レビューが付かない) と、目に付いた差分 (draft である) を因果で結んでしまった。`.coderabbit.yaml` に `drafts: false` という**もっともらしい説明が実在した**ことが誤診を後押ししている。draft を外した後に**同じ症状が続くか**を確かめる前に「解決した」と記録したのが誤りで、**対処の効果は対処後の観測で確かめる**しかない (決定 16 の検証 step はこの教訓の実装でもある)。 + **決定 11 の撤回を受けた構造側の是正である。** 明示トリガーが不成立と分かった時点で残る選択肢は「レビューされない PR を毎晩作り続ける」か「draft をやめる」かの 2 つで、後者を採った。 **commitment 点はマージ 1 点に集約する (ユーザー判断)。** 起票時は「ready 化 = レビューに commit する意思表示」も commitment 点と見なしていたが、**発生トリガーがユーザー指示か自動採択かで扱いを区別する必要はない** — 有効な修正 PR ならプロジェクトに取り入れてよい。したがって自律 actor が「ready = レビュー求む」を出すことは許容し、後戻り不可な操作 (マージ) だけを人間に残す。[ADR-052](adr-052-autonomy-execution-boundary-classes.md) 原則 2 の分類表を本体改訂し、ゲート必須クラスから「PR の ready 化」「非 draft PR の作成」を削除した。 @@ -338,9 +346,60 @@ pre-push simplicity review はここを「他の停止点と同様に graceful d **旧名は黙って通さない。** `Operation::parse("draft-pr")` は `None` を返して引数不正 (exit 2) になり、旧キー `max_open_draft_prs` だけの config は閾値未接続 (deny) になる。呼び手の更新漏れが「別名として通る」形で fail-open しないよう unit test で固定した ([ADR-071](adr-071-draft-pr-backpressure.md) § unit test)。 -**決定 11 の step は撤去し、跡地にコメントを残す。** 通常 PR は `.coderabbit.yaml` の `auto_review.enabled: true` が拾うため、明示トリガーは不要になった。`Report outcome` からも `request_review` の outcome と `[NIGHTLY_WARN]` 分岐を除いた。 +**決定 11 の step は撤去し、跡地にコメントを残す。** ~~通常 PR は `.coderabbit.yaml` の `auto_review.enabled: true` が拾うため、明示トリガーは不要になった。~~ → **この見込みは外れた** (上記「前提の訂正」)。明示トリガーは依然として必要で、決定 16 が**投稿者を人間 identity にして**復活させる。`Report outcome` から `request_review` の outcome と `[NIGHTLY_WARN]` 分岐を除いた点は維持する — 投稿はもはやこの workflow の責務ではないため。 + +**CodeRabbit の quota は夜間 PR 1 件あたり 1 レビュー増える。** 決定 11 が意図していた消費量と同じで ([ADR-019](adr-019-coderabbit-review-hybrid-policy.md) § CodeRabbit は bot 作成 PR を自動レビューしない に注記)、`auto_review.drafts: false` の設定自体は変えていない — 人間が意図的に draft で開く PR を対象外に保つ意味は残る。 + +### 16. レビュー要求だけを人間 identity で出す — 別 workflow へ分離する (2026-08-10) + +**決定 11 の撤回理由は「明示トリガーという方式が悪い」ではなく「投稿者が bot だった」である。** identity を変えれば方式は生きる。制約の全体像は [ADR-019](adr-019-coderabbit-review-hybrid-policy.md) § CodeRabbit は bot 作成 PR を自動レビューしない が持つ。 + +**PR の作成者は bot のまま維持する。** author を人間資格情報へ変える案もあったが、決定 8 が App token を選んだ理由 (PAT はオーナー権限で [ADR-067](adr-067-phase-b-unattended-fix-push.md) の ruleset backstop を bypass する) は今も有効である。**変えるのは「誰が PR を作るか」ではなく「誰がレビューを頼むか」**だけでよい。 + +**PAT は権限を絞れば決定 8 の懸念に当たらない。** `CODERABBIT_TRIGGER_PAT` は fine-grained PAT で **Pull requests: write のみ** (対象リポジトリ 1 つ、期限付き)。**push もマージもできない** (どちらも `Contents: write` が必要) ため、ruleset backstop を迂回する経路が構造的に存在しない。決定 8 の却下は「PAT 一般」ではなく「push に使う PAT」に対するものだった。 + +#### nightly-todo.yml の中に置かない — 資格情報を agent の job から隔離する + +これが本決定で最も重要な設計判断である。分離の理由は責務分離ではなく**信頼境界**にある。 + +nightly-todo の job は**未信頼の agent が実装を書き、その成果物を `cargo test` が実行する** job である。決定 5 は agent に Bash を与えず、決定 8 § 副次効果は agent が触れる `GITHUB_TOKEN` を read-only にした。さらに § 実走スモークで**唯一未解決なのが「`cargo` サブプロセスへのトークン露出」**である。 + +その job に人間資格情報を置くと、**未解決の露出リスクの対象に人間 PAT が加わる**。[`review-request.yml`](../../.github/workflows/review-request.yml) は agent を一切動かさないため、PAT はそこにしか存在しない。 + +一般化すると、**新しい資格情報を足すときは「その job で何が実行されうるか」を先に問う**。決定 8 § 帰結が「資格情報を足すと、その step で何が実行されうるかを洗い直す必要がある」と書いた一般則の 2 例目にあたる。 + +#### pull_request_target の攻撃面を閉じる -**CodeRabbit の quota は夜間 PR 1 件あたり 1 レビュー増える。** 決定 11 が意図していた消費量と同じで ([ADR-019](adr-019-coderabbit-review-hybrid-policy.md) § 夜間ループ PR の消費 に注記)、`auto_review.drafts: false` の設定自体は変えていない — 人間が意図的に draft で開く PR を対象外に保つ意味は残る。 +public リポジトリでは **fork からの PR でも起動し、その時点で secrets へ到達できる**。checkout しなくても、PR のタイトル・本文・ブランチ名を `run:` へ展開すれば script injection から secret 窃取に至る。[ADR-031](adr-031-weekly-review-pipeline.md) § 残存ブランチ検出 で塞いだのと同じクラスである。 + +- PR ブランチを **checkout しない** (コードを一切実行しない) +- `run:` へ展開するのは **PR 番号 (整数) だけ**。文字列フィールドはシェルに渡さない +- fork PR を条件で除外する + +起動条件は 4 つの AND で fail-closed にした: author が Bot / fork でない / base が本リポジトリ / kill-switch が有効。**author は `user.type == 'Bot'` で判定する** — `nightly-todo-aloekun[bot]` を直書きすると App 改名で黙って発火しなくなる。 + +**kill-switch は 2 面とも見る。** workflow 式からはリポジトリ内ファイルを読めないため、variable 面は `if:` で、config 面は job 内の step が既定ブランチの `autonomy-config.toml` を API で読んで判定する。PR ブランチ側ではなく既定ブランチから読むのは決定 3 と同じ信頼境界 (自律 actor が自分の停止フラグを書き換えて自己解除する経路を作らない)。**「意図した停止」は green、「読めなかった」は red** と分ける (決定 10 と同じ分類)。 + +#### 投稿しただけで成功としない + +**決定 11 の失敗の本質は、投稿の成否しか観測せず「相手が反応したか」を見ていなかったことにある。** 助言層を fail-open にしたこと自体は [ADR-043](adr-043-security-gates-fail-closed.md) に沿って正しかったが、fail-open は**効果の観測を別に用意して初めて成立する**。 + +本 workflow は投稿後に CodeRabbit の反応を待ち、無ければ red で落とす。判定は要求コメントの id を起点に**それより新しい** CodeRabbit コメントだけを数える — PR 上の総数を見ると過去の skip 通知や別要求への反応で誤って成功と判定する。照会の一時失敗は「反応なし」と読み替えず、判定は deadline 到達時のみ行う。 + +投稿は冪等にする。`opened` は PR ごとに 1 回だが run の手動 re-run で二重投稿になり、[ADR-019](adr-019-coderabbit-review-hybrid-policy.md) § 再トリガー抑止ガードのとおり同一 HEAD への再投稿は**レート枠を消費するだけ**である。 + +#### 実走検証 (2026-08-10) + +`workflow_dispatch` で経路全体を 1 回で確認した。**PR 作成から CodeRabbit の反応まで 15 秒、完全自動**。 + +| 段 | 時刻 (UTC) | 結果 | +|---|---|---| +| `nightly-todo` 完走 | 09:23:02 | 全 step success (順位 163 を選択) | +| bot PR 作成 | 09:23:02 | [#381](https://github.com/aloekun/claude-code-hook-test/pull/381) `draft=false` / author `nightly-todo-aloekun[bot]` | +| `review-request` 自動起動 | 09:23:05 | kill-switch 2 面を通過し投稿 (comment id=5238298985) | +| **CodeRabbit の反応** | 09:23:17 | **反応あり**。検証 step が「要求後のコメント 2 件」を確認 | + +**検証 step は実際に働いた** — 1 回目の確認では反応が無く 2 回目で検出している。決定 11 のように投稿の成否だけを見ていれば、この待機は存在しなかった。 ## 試験運用判断基準 (ADR-039) @@ -433,15 +492,17 @@ pre-push review を 12 サイクル通す過程で、blocking な欠陥 10 件 | 決定 7 の照合が実 runner 上でも通ること (誤検知で毎晩止まらないこと) | 本 ADR § integrity 機構の drill | **充足 (1 run)** — 誤検知せず publish へ到達。毎晩の安定性は継続観測 | | `publish/` の clone + rsync が実 runner で成立し、`work/` の変更が過不足なく運ばれること | 決定 9 (`--delete` による削除の反映を含む) | **充足** — commit は 1 ファイル 18 行追加・削除ゼロで、順位 203 の指定範囲と完全に一致 | | WP-17 残課題: Phase B の自動起動経路が成立するか | [ADR-067](adr-067-phase-b-unattended-fix-push.md) § 検証記録 | **経路は生存 (2026-08-09 訂正)** — 2026-08-08 時点では「不成立」と記帳したが誤り。起動契機のコメントが無かっただけで、CodeRabbit がコメントした時点で `issue_comment` 経路は発火した (#373 で 04:12:15 に **Phase A が夜間 PR 上で自動起動**)。**Phase B 本体 (無人 fix push) の到達はなお未観測** — docs 指摘が出る PR に当たっていない | -| WP-17 残課題: `coderabbitai[bot]` allowlist の要否 | 同上 | **未判定 (2026-08-09 に条件を再設定)** — 上記のとおりイベントは発生しうると分かった。判定条件は「決定 11 の明示トリガーが効いてから」ではなく (決定 11 は撤回)、**順位 394 の draft 廃止後、CodeRabbit の自動レビューが付いた夜間 PR で Phase A/B の起動可否を見る**こと | +| WP-17 残課題: `coderabbitai[bot]` allowlist の要否 | 同上 | **未判定 (2026-08-10 に前提が整った)** — 決定 16 で夜間 PR に CodeRabbit のレビューが付くようになり、判定に必要な起動契機が毎回供給されるようになった。次に docs 指摘の出る夜間 PR で Phase A/B の起動可否と併せて見る | | **`cargo` サブプロセスから `CLAUDE_CODE_OAUTH_TOKEN` / `GITHUB_TOKEN` が見えるか** | pre-push security review の warning | **未観測 (意図的に保留)** — 観測には使い捨ての `build.rs` を仕込む専用 run が要り、初版の probe は public CI ログへ広く env 名を出す設計欠陥で撤去した (§ 残課題)。決定 5 で agent に Bash を与えない判断は**保守側**のため、未観測でも安全側に倒れている。確実に 1 つずつ可観測性を積む方針 (2026-08-08 ユーザー確認) に従い、安全な probe を設計できるまで保留する | | **停止側: `AUTONOMY_ENABLED` が `'false'` / 未設定で何も作られないこと** | ADR-066 の 3 状態。#364 で受け入れ基準へ追加 | **充足** (2026-08-08、ユーザー実測) — `'false'` と未設定の 2 状態で `workflow_dispatch` (`dry_run` オフ = push / PR 作成をする設定) を実行し、**2 回とも job が skip**。ブランチ・draft PR・App token のいずれも作られなかった。確認後 `'true'` へ復旧済み | | **tool scope の deny が効くこと (agent が `master-ref/` へ書けない)** | 決定 12 (順位 379) | **充足** (2026-08-08、ローカル CLI 実測) — 同じ `--allowedTools` / `--disallowedTools` フラグで `master-ref/PROBE.txt` への Write を試させると `File is in a directory that is denied by your permission settings.` で拒否され、ファイルは作られず config も無傷。対照で `work/` への Write は成功。あわせて実 dispatch run で agent が対象 1 ファイルのみ編集し `guard=success` = allow 側も成立 | **停止側は `dry_run` をオフにして検証した。** `AUTONOMY_ENABLED` が `'true'` でなければ job の `if:` で止まるため `dry_run` の値は判定に関与しないが、**あえて「push も PR 作成もする設定」で実行**することで「dry_run だから作られなかったのでは」という解釈の余地を消している。 -**10 件中 7 件が充足、残る 3 件が未確定。** 未確定は (a) Phase B の自動起動 (経路の生存は #373 で確認したが、**Phase B 本体 = 無人 fix push への到達は未観測**)、(b) `coderabbitai[bot]` allowlist の要否、(c) トークン露出 (安全な probe を設計できるまで保留)。**(a) と (b) は順位 394 の draft 廃止後に同じ run で判定できる**。 +**10 件中 7 件が充足、残る 3 件が未確定。** 未確定は (a) Phase B 本体 (無人 fix push) への到達、(b) `coderabbitai[bot]` allowlist の要否、(c) トークン露出 (安全な probe を設計できるまで保留)。 +> **(a)(b) の前提は 2026-08-10 に整った。** 両者は「CodeRabbit が夜間 PR にコメントすること」を起動契機とするため、レビューが一度も付かない間は**観測機会そのものが無かった**。決定 16 でレビューが毎回付くようになり、あとは docs 指摘の出る夜間 PR に当たれば判定できる。**未確定の理由が「機構が無い」から「事象待ち」へ変わった**点が進捗である。 +> > **集計の訂正 (2026-08-09)**: 従前は「8 件が充足、1 件が不成立、残る未確定は 2 件」と書いていたが、合計が 11 件で母数の 10 件と合っておらず、充足数も表と 1 件ずれていた (表の充足は 7 行)。**表が正**であり、上記へ改めた。 **トークン露出の観測は意図的に保留する。** 初版の probe は (1) `build.rs` が draft PR の git 履歴に残り、(2) 名指しの 4 変数を超えて `TOKEN`/`SECRET`/`KEY` に一致する全 env 名 (`ACTIONS_RUNTIME_TOKEN` 等) を public CI ログへ出す設計欠陥があり、pre-push security review が REJECT して撤去した。安全に観測するには最低限 (a) `build.rs` を Guard の deny 配下パスに置いて commit 混入を防ぐ、(b) 出力を名指しの変数のみに絞る、(c) `if: github.event_name == 'workflow_dispatch'` で dispatch 限定にする、の 3 点が要る。決定 5 の Bash 非付与が保守側に倒れているため未観測でも安全側であり、不確実な追加 dispatch を急がず、設計を固めてから 1 回で観測する (2026-08-08 ユーザー方針)。 @@ -459,6 +520,11 @@ pre-push review を 12 サイクル通す過程で、blocking な欠陥 10 件 | `NIGHTLY_APP_ID` | repository **variable** (Actions → Variables) | | `NIGHTLY_APP_PRIVATE_KEY` | repository **secret** (Actions → Secrets) | | `AUTONOMY_ENABLED` | repository **variable** (Actions → Variables)。現在値 `'true'` | +| `CODERABBIT_TRIGGER_PAT` | repository **secret** (Actions → Secrets)。2026-08-10 登録。**fine-grained PAT / 対象リポジトリ 1 つ (`claude-code-hook-test`) / `Pull requests: Read and write` のみ / 期限あり**。用途は [`review-request.yml`](../../.github/workflows/review-request.yml) からのレビュー要求コメント投稿だけ (決定 16) | + +**PAT は push もマージもできない。** どちらも `Contents: write` が必要で、本 PAT には付与していない。決定 8 が PAT を却下した理由 ([ADR-067](adr-067-phase-b-unattended-fix-push.md) の ruleset backstop 迂回) は、**push に使う PAT** に対するものであって権限を絞った PAT には当たらない。この非対称が決定 16 を成立させている。 + +**期限切れは沈黙しない。** PAT が失効すると `review-request.yml` の投稿 step が失敗し、workflow が red になる。投稿できても CodeRabbit が反応しなければ検証 step が red になる (決定 16)。どちらの経路でも run 一覧から気づける。 **付与権限は決定 8 の設計意図と完全に一致していた。** 同決定は「Contents: write / Pull requests: write / Metadata: read のみ。**Workflows は付けない**」と書いており、実体もそのとおりだった。Workflows が No access であることは、`.github/workflows/**` を含む push が権限層でも通らないことを意味し、決定 6 の禁止リストと二重の防御になっている。 @@ -509,11 +575,11 @@ pre-push review を 12 サイクル通す過程で、blocking な欠陥 10 件 ### 残課題 -- **実走スモークの残り 3 項目** (§ 実走スモーク)。allow 経路・停止側・tool scope deny は 2026-08-08 に充足した。残るのは (a) Phase B 本体の到達、(b) `coderabbitai[bot]` allowlist の要否 (いずれも順位 394 後の run で判定)、(c) **`cargo` サブプロセスへのトークン露出**。(c) は初版 probe の設計欠陥 (commit 混入 + env 名の広域露出) を解消した安全な probe を設計してから 1 回で観測する。決定 5 の Bash 非付与が保守側のため未観測でも安全側であり、急がない。この観測は決定 5 の「Bash 再付与を再検討してよいか」の判断材料でもある。 +- **実走スモークの残り 3 項目** (§ 実走スモーク)。allow 経路・停止側・tool scope deny は 2026-08-08 に充足した。残るのは (a) Phase B 本体の到達、(b) `coderabbitai[bot]` allowlist の要否 (**決定 16 で観測機会は供給されるようになった。あとは docs 指摘の出る夜間 PR に当たるのを待つ**)、(c) **`cargo` サブプロセスへのトークン露出**。(c) は初版 probe の設計欠陥 (commit 混入 + env 名の広域露出) を解消した安全な probe を設計してから 1 回で観測する。決定 5 の Bash 非付与が保守側のため未観測でも安全側であり、急がない。この観測は決定 5 の「Bash 再付与を再検討してよいか」の判断材料でもある。 - **外部設定の実体は記録したが、作成日と資格情報欠落時の run の色は未確定** (§ 外部設定の実体)。前者は GitHub の Audit log から引ける。後者は資格情報を意図的に壊す run が要り、復旧を伴うため実施していない。 - **`AUTONOMY_ENABLED` を立てると schedule も同時に有効になる**。スモークを「まず dry_run で」と計画していたのに、変数を立てた時点で本番の夜間 run が先に走った (§ 実走スモーク)。**観測装置の準備前に無人 run が始まる**構造なので、次に同種の自律機能を足すときは「有効化の粒度」を dispatch 限定と schedule 込みで分けられるか検討する。 -- ~~**CodeRabbit が bot 投稿の `@coderabbitai review` に反応するか** (決定 11)~~ → **解決 (2026-08-09)**。無反応と実測で確定し、決定 11 を撤回した (§ 決定 11 の撤回ブロック)。代替解は順位 394 の draft 廃止。 -- **Phase B 本体 (無人 fix push) が夜間 PR で到達するか**。#373 で `issue_comment` 経路の生存と Phase A の自動起動までは確認したが、docs 指摘が出る PR に当たっていないため Phase B 自身は未観測。`coderabbitai[bot]` allowlist の要否も同じ run で判定する (§ 実走スモーク)。 +- ~~**CodeRabbit が bot 投稿の `@coderabbitai review` に反応するか** (決定 11)~~ → **解決 (2026-08-09〜10)**。無反応と実測で確定して決定 11 を撤回し、**投稿者を人間 identity に変えて方式ごと復活させた** (決定 16、2026-08-10 に実走で成立を確認)。当初「代替解は draft 廃止」と書いたのは誤りだった (決定 15 § 前提の訂正)。 +- **Phase B 本体 (無人 fix push) が夜間 PR で到達するか**。#373 で `issue_comment` 経路の生存と Phase A の自動起動までは確認したが、docs 指摘が出る PR に当たっていないため Phase B 自身は未観測。`coderabbitai[bot]` allowlist の要否も同じ run で判定する (§ 実走スモーク)。**決定 16 で夜間 PR に毎回レビューが付くようになったため、観測機会は供給され続ける。** - **`master-ref/` を agent のファイルシステムから外すか (順位 377 の判断材料)**。決定 12 の tool scope で**agent が直接書く経路は予防側で塞いだ**ため、当初の「検知どまり」状態は解消した。残るのは build script 経由の経路で、完全に外すには別 job + artifact 受け渡しへの構造変更が要る。**決定 12 のスコープが実走で効いていることを確認できるまでは、構造変更の要否を判断しない** — 効いていなければ前提が変わる。 - **authority gate の直前で自律 PR 数を再計数するか**。現状は job 冒頭のスナップショットを使い回す (§ 決定 4)。閾値を 1 件超えて push される事象が実運用で観測されたら入れる。**再計数を入れない現状の根拠**: 超過は最大でも 1 件で、背圧は「積み過ぎを止める」ためのものであって厳密な上限ではない。同一 workflow の並行 run は `concurrency` で直列化済みなので、増分の出所は別経路 (人手 / Phase B) に限られる。CodeRabbit の PR [#376](https://github.com/aloekun/claude-code-hook-test/pull/376) レビューが同じ点を指摘したが、この保留は意図であり指摘を受けての新規判断ではない。 - **ガードレール禁止リストの allowlist 化**。台帳の「対象ファイル」列を機械可読にする (別列に正規化パスを持つ等) のが前提。 diff --git a/docs/harness-improvement-plan.md b/docs/harness-improvement-plan.md index 84d897ba..6bcb1477 100644 --- a/docs/harness-improvement-plan.md +++ b/docs/harness-improvement-plan.md @@ -168,10 +168,10 @@ Anthropic 公式のハーネスエンジニアリング指針(決定論的基 | 内容 | 管理先 | 期限 / 条件 | |---|---|---| -| **順位 393 / 394 は実装完了(2026-08-09)**。決定 11 の撤回記録は [ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 11 の撤回ブロック、停止点の draft → 通常 PR 変更は同 決定 15、背圧の指標改訂は [ADR-071](adr/adr-071-draft-pr-backpressure.md)、分類表の本体改訂は [ADR-052](adr/adr-052-autonomy-execution-boundary-classes.md) 原則 2 が正。**この 2 件として残るのは実走確認 1 点** = 夜間 PR に CodeRabbit の初回自動レビューが付くこと(背圧の閾値 deny は exe drill + unit test で確認済み)。**WP-18 全体のスモーク未確定は下 2 行の 3 件**で、本行はそのうち (a)(b) の前提を作る | ADR-072 § 実走スモーク | 次回の夜間 run | -| **スモーク未確定 3 件のうち (a) Phase B 本体の到達 と (b) `coderabbitai[bot]` allowlist の要否** — どちらも上段の実走確認と**同じ run で判定できる**(レビューが付けば起動契機が供給される) | ADR-072 § 実走スモーク | 上段と同じ、次回の夜間 run | +| ~~順位 393 / 394 の実走確認~~ → **充足(2026-08-10)**。夜間 PR に CodeRabbit のレビューが付くことを実走で確認した。ただし**原因は draft ではなく author が bot であること**で、決定 15 の前提は誤りだった。解決は [ADR-072](adr/adr-072-nightly-todo-loop.md) 決定 16(レビュー要求だけを人間 identity で出す別 workflow)。制約の全体像は [ADR-019](adr/adr-019-coderabbit-review-hybrid-policy.md) § CodeRabbit は bot 作成 PR を自動レビューしない が正 | ADR-072 決定 16 | 完了 | +| **スモーク未確定 (a) Phase B 本体の到達 と (b) `coderabbitai[bot]` allowlist の要否** — 決定 16 で**観測機会は供給されるようになった**(夜間 PR に毎回レビューが付く)。あとは **docs 指摘の出る夜間 PR に当たるのを待つ**だけで、未確定の理由が「機構が無い」から「事象待ち」へ変わった | ADR-072 § 実走スモーク | 事象待ち(機構は整備済み) | | **スモーク未確定 3 件のうち (c) `cargo` サブプロセスへのトークン露出**(順位 374 の残り。**意図的保留** — 初版 probe の設計欠陥を解消した安全な probe を設計してから 1 回で観測。ADR-072 決定 5 の Bash 再付与判断の材料でもある) | ADR-072 § 残課題 | 急がない(Bash 非付与が保守側)。**完走条件には含めない** | -| **採用率 2 週間測定**(WP 全体の受け入れ基準。人間がマージした割合 50% 超で継続・拡大 — 参考値であり統計的意味は無い、ADR-072 § 欠点)。測定は weekly-review の自律アクション棚卸し(WP-19 ステップ 3)へ載せて仕組み化。**開始起点 = スモーク完走後(2026-08-09 ユーザー決定)**。完走の定義を順位 394 の実走確認(PR に CodeRabbit の初回自動レビューが付くこと)までとし、意図的保留のトークン露出は完走条件に含めない | ADR-072 § 試験運用判断基準 | 2026-11-06 までに判定 | +| **採用率 2 週間測定**(WP 全体の受け入れ基準。人間がマージした割合 50% 超で継続・拡大 — 参考値であり統計的意味は無い、ADR-072 § 欠点)。測定は weekly-review の自律アクション棚卸し(WP-19 ステップ 3)へ載せて仕組み化。**開始起点 = 2026-08-10 に確定**(PR に CodeRabbit のレビューが付く実走確認をもって完走とする定義。意図的保留のトークン露出は完走条件に含めない)。1 件目は [#381](https://github.com/aloekun/claude-code-hook-test/pull/381) | ADR-072 § 試験運用判断基準 | 2026-08-24 に中間確認、2026-11-06 までに判定 | | 稼働後 1 週間の run 頻度・Max 枠消費を観測して schedule 頻度を調整 | 運用ノート(本表のみ) | 稼働中 | | ~~順位 395: 週次レビューで浮きブランチを検出し削除を提案~~ → **実装完了(2026-08-09)**。`cli-stale-branch-scan` / `pnpm stale-branch-scan`。設計と判定規則は [ADR-031](adr/adr-031-weekly-review-pipeline.md) § 残存ブランチ検出 が正。自動削除はしない(提案のみ) | [ADR-031](adr/adr-031-weekly-review-pipeline.md) | 完了。WP-19 ステップ 3 の一部を先取り済み | | 順位 382(injection payload regression test。依存先の順位 380 完了で unblock)/ 順位 383(`is_separator_row` のパイプ検証欠落) | [todo-summary2.md](todo-summary2.md) | 🔧 Tier 2、任意 |