feat(autonomy): 未マージ draft PR 数による背圧を実装し draft-pr クラスの構造的 deny を解除 (ADR-071) - #361
Conversation
WP-18 PR 1 (1/5)。ADR-052 原則 5 が自動実行可クラスの前提条件とする背圧を、
判定コア `lib-autonomy-policy` が入力として受け取れるようにする。
## 変更の要点
`Operation::backpressure_connected()` の `DraftPr => false` 固定を廃し、背圧の
**指標の要求**と**指標の実測値**を別の層へ分けた:
- `Operation::requires_draft_backpressure()` — 操作クラスが「未マージ draft 数」を
要求するかだけを持つ静的分類。状態は持たない
- `GateInputs::open_draft_prs` / `max_open_draft_prs` — 実測値と閾値。どちらか一方でも
`None` なら `backpressure-unavailable` で deny (fail-closed)
背圧の状態を enum 側にも持たせると `GateInputs` と二重管理になり判定経路が分岐するため、
状態の保持先は `GateInputs` 1 箇所に限定した (計画書 WP-18 PR 1 の明示要件)。
`FixPush` が draft 数を要求しないのは背圧が無いからではなく、その背圧が cli-pr-monitor の
有界 retry (`max_retries`) で、呼び出しごとに gate へ渡す状態を持たないため。この非対称を
doc コメントとテスト (`fix_push_is_unaffected_by_draft_backpressure_inputs`) の両方で固定した。
## 追加した deny 理由
`DenyReason::BackpressureSaturated { open, limit }` (code = `backpressure-saturated`)。
飽和判定は `>=`。閾値は「これ以上は積まない」上限であり、`limit = 0` は「draft を 1 件も
作らない」= 実質停止を意味する。
`describe_sources` の背圧表記は `structural` / `ok(N/M)` / `saturated(N/M)` / `unavailable`
の 4 状態で、実数を必ず併記する。run log 1 行で「数え損ねて止まった」と「積み過ぎて
止まった」を切り分けられるようにするため。
## テスト
判定コアのテストを 16 → 22 件へ。網羅走査テストは背圧 4 パターンを軸に加えて 54 → 216
組合せになり、許可される組合せ数も式で固定した (truthy 表記数 × (fix-push 4 + draft-pr 1))。
境界 (`open == limit` で止まる)、`limit = 0`、kill-switch が背圧より先に効くこと、
背圧入力の欠落 3 パターンをそれぞれ独立に pin している。
## 本コミットの範囲
呼び手 2 件 (`cli-autonomy-gate` / `cli-fix-push-gate`) は本コミットでは `None` を渡す。
`draft-pr` は従来どおり deny のままで、運用挙動は変わらない。config からの閾値読み取りは
2/5、実測 draft 数の受け口は 3/5 で接続する。
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…で取り込む WP-18 PR 1 (2/5)。背圧の閾値を `autonomy-config.toml` の `[autonomy] max_open_draft_prs` に置き、kill-switch フラグと同じ信頼境界 (master ref の写し) と 同じ「欠損 → 停止」極性に乗せる。 ## read を 1 回に集約した理由 `read_repo_config_enabled(path) -> Option<bool>` を `read_repo_config(path) -> RepoConfig` へ置き換えた。キーごとに読み取り関数を生やすとファイルを 2 回読むことになり、2 回の read の 間に config が差し替わると「kill-switch は旧世代・閾値は新世代」という混成状態で判定しうる。 1 回の read から派生した値だけを使う。 ## 半壊 config は全フィールドが停止側へ倒れる toml の parse はファイル単位なので、`max_open_draft_prs` が型違い (文字列 / 負値 / 小数) だと `enabled` も含めて全フィールドが `None` になる。これは意図した挙動で、config の一部が壊れた 状態を「kill-switch だけ有効」で運転させない (ADR-043 fail-closed)。テストで明示的に固定した。 閾値キー欠落時に既定値 (3 など) へ倒さないのも同じ理由。書き忘れが「勝手に 3 件まで作る」 という fail-open にならないよう、欠落は背圧未接続 = draft PR deny とする。 一方で未知キーは無視する (`unknown_keys_are_ignored`)。config に新しい設定を足したときに、 未更新のバイナリが parse 失敗で全停止するのは安全側に振りすぎるため。 ## テスト sources のテストを 6 → 11 件へ。閾値の正常読み取り (0 を含む)、キー欠落が既定値でないこと、 型違い 3 種が kill-switch フラグごと停止側へ倒すこと、未知キー無視を追加した。 ## 本コミットの範囲 `cli-autonomy-gate` は閾値を `GateInputs` へ渡すようになったが、実測 draft 数の受け口 (`--open-draft-prs`) はまだ無いため `draft-pr` は `backpressure-unavailable` で deny のまま。 接続は 3/5 で行う。`cli-fix-push-gate` は `enabled` しか使わないため呼び出し形の追従のみ。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
WP-18 PR 1 (3/5)。判定コア (1/5) と閾値 (2/5) に続き、背圧の残り 1 入力である **実測件数**の受け口を CLI に開ける。これで `draft-pr` が構造的 deny を脱し、 ADR-052 原則 5 の契約を満たした状態でのみ許可されるようになる。 ## 引数の扱い `--open-draft-prs <count>` は省略可能。`fix-push` では判定に使わないためで、`draft-pr` で 省略した場合は `None` = 背圧未接続として deny に倒れる。**省略が許可へ倒れる経路は無い**。 値のパースは `u32` で、空文字 / 負値 / 小数 / 非数値 / 末尾空白は引数不正 (exit 2) として 弾く。呼び手の `gh api` が失敗したときの出力 (空文字など) を 0 件と読み違えて「draft が 1 件も無いので作ってよい」に倒れるのが最悪の failure mode なので、ここは黙って `None` へ 潰さず loud に落とす。 `--config` / `--operation` の必須性は従来どおり。引数ループは値取得を各 arm へ寄せ、 未知フラグの判定を値の有無より先に行う既存の順序を保った。 ## テスト 引数解析のテストを 4 → 7 件へ。省略時が `None` であること、`0` が正しく `Some(0)` として 読まれること (「0 件」と「数えられなかった」を型で区別する契約)、不正値 5 種が引数不正で あることを固定した。 ## 本コミットの範囲 exe 単体では背圧が接続された。実測値を渡す呼び手 (夜間 workflow の `gh api` step) は **本 PR には含まれず PR 3 で追加する** (ADR-069 chain 宣言 → 計画書 § WP-18 と ADR-071 を 5/5 で更新)。実 exe による drill は 4/5。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
WP-18 PR 1 (4/5)。1/5〜3/5 で実装した背圧の設計判断・試験運用条件・実測を永続化する。 ## 記録した決定 5 件 1. 指標は「未マージ draft PR 数 (claude/ prefix)」。run 回数や経過時間のような代理指標 ではなく、止めたい事象 (人間が捌けない量の未処理成果物) を直接数える 2. 背圧の状態は GateInputs だけが持つ。enum 側にも状態を置くと判定経路が二股に分かれ、 「テストは通るが実運用では別の枝を通る」drift を生む 3. 閾値は autonomy-config.toml の max_open_draft_prs、判定は >=。0 は draft-pr クラス だけの停止、キー欠落は既定値ではなく deny 4. 数えるのは呼び手 (workflow step の gh api)、判断するのは gate。exe が gh に依存すると ローカル drill が GitHub 到達性に依存し、安全装置の再現可能な検証ができなくなる 5. 数えられなかったことは 0 件ではない。不正値は exit 2 で loud に落とす 決定 4 の「呼び手が数を偽れる」問題は、schedule イベントが default branch の workflow 定義を 使うという GitHub の仕様で担保される (ADR-066 の config master ref 契約と同じ信頼境界)。 ## 外部 SaaS の課金・上限事実を移管 (計画書 § 2 の退役条件 2) 2026-08-06 に最新値を再確認して永続化した。 - public リポジトリ + standard runner の Actions 実行は無料・分数無制限 (GitHub 公式 docs で 原文確認)。GitHub Free の 2,000 分/月は private のみ - claude-code-action@v1 は claude_code_oauth_token で Max 枠を消費。OAuth token は個人 サブスクに紐づき、自動化の消費が対話作業のレート枠を圧迫しうる 要約: Actions の実行時間は無料だが Max 枠は有限。背圧の経済的根拠はここにある。 ## 検証記録 release build の実 exe で drill 12 シナリオを実施し全て設計どおりを確認した。#6/#7 の対で >= 境界、#8 で limit=0 の停止、#9 で fix push が draft 数から独立していること、#10 で 半壊 config が enabled ごと停止することを実バイナリ上で確認している。 unit test は判定コア 22 / sources 11 / 引数解析 7 件。網羅走査 1 件が 216 組合せを走査する。 ## bounded lifetime decision trigger (b)「閾値到達で実際に次の run が止まること」は本 ADR 固有の観測点で、 exe 単体 drill では作れない状態 (夜間ループが実際に 3 件積む必要がある)。期限は 2026-11-06。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
WP-18 PR 1 (5/5)。計画書側の 3 種類の更新。 ## 1. PR 1 完了の記帳 - WP-18 節の見出しと全体像表を「着手可」→「着手中(PR 1 実装済み)」へ - PR 構成 1 に実装時の設計判断を確定記録: 閾値判定の層は (a) gate 内を採用。 backpressure_connected() は廃し requires_draft_backpressure()(指標の要求のみ)と GateInputs の 2 フィールド(状態)へ分離した - 着手前決定 2 の記述を過去形へ(backpressure_connected() は既に存在しない名前のため、 現在形のまま残すと ADR-069 決定 1 の「名前一致」要件に反する) - WP-19 ステップ 2 を「前倒し済み」→「land 済み」へ ## 2. PR chain 宣言(ADR-069 決定 1) PR 1 が導入した 3 点(--open-draft-prs フラグ / max_open_draft_prs キー / DraftPr の許可 経路)は PR 3 まで呼び手を持たない。抽出↔呼び手のペアリングを表で具体名指定した。 順序を逆にできない根拠も明記した — ADR-052 原則 5 が背圧の接続を draft-pr クラス有効化の 前提条件としているため、背圧が先に land する必要がある(WP-17 の kill-switch 先行と同構造)。 なお PR 1 単体では draft-pr は deny のままで運用挙動は変わらない。 ## 3. SaaS 課金・上限事実の移管(退役条件 2 / 順位 117 の 3 ステップ原則) permanent 側(ADR-071 § 外部 SaaS の課金・上限事実)を先に作成 → 本ファイルの § 2 から GitHub Actions 課金 2 点と claude-code-action の OAuth 認証を削除し ADR-071 への参照へ 置き換えた。cloud routines の事実群は WP-19 / ADR-070 の担当範囲のため本節に残している。 runner 単価の相対比も private 化時のみ関係するため移管対象外とした。 pnpm lint:docs / markdownlint ともに green。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthrough
ChangesDraft PR 背圧制御
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant cli-autonomy-gate
participant RepoConfig
participant autonomy-policy
cli-autonomy-gate->>RepoConfig: 設定を読み取る
RepoConfig-->>cli-autonomy-gate: enabled と max_open_draft_prs
cli-autonomy-gate->>autonomy-policy: open_draft_prs と上限を渡す
autonomy-policy-->>cli-autonomy-gate: allow または deny
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🤖 PR Monitor 分析 (GitHub Actions バックストップ)
Applicable Findings (Critical / High / Major)(該当なし — レビュー未着のため) Applicable Findings (Medium 以下)(該当なし) Filtered (not applicable)(該当なし) 次のアクション
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
docs/adr/adr-071-draft-pr-backpressure.md (1)
76-79: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win外部事実の一次資料リンクを追加してください。
この ADR は GitHub Actions の料金条件と
anthropics/claude-code-action@v1の認証条件を、背圧の経済的根拠として使用しています。現在は確認日と要約だけで、一次資料へのリンクを再現可能な形で残していません。GitHub 公式資料と、対象 workflow のリポジトリ内パスまたは参照先を追加してください。仕様変更時に再確認できます。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/adr/adr-071-draft-pr-backpressure.md` around lines 76 - 79, ADR-071 の料金・認証根拠を記載している表に、GitHub Actions の料金条件を裏付ける公式資料URLと、claude-code-action の認証条件を裏付ける公式資料または対象 workflow へのリポジトリ内参照を追加してください。既存の確認日と要約は維持し、各主張から対応する一次資料を再確認できる形にしてください。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/adr/adr-071-draft-pr-backpressure.md`:
- Around line 138-141: 限定的な夜間運用の説明に修正し、docs/adr/adr-071-draft-pr-backpressure.md
の残課題では既存の夜間運用が backpressure-unavailable で deny されると記載しつつ、--open-draft-prs
と有効設定による手動実行・drill の allow 経路を除外しないでください。docs/harness-improvement-plan.md では、PR
1 に本番 workflow の consumer がないことを示し、draft-pr の実行可能な許可経路自体が存在しないようには記載しないでください。
In `@docs/harness-improvement-plan.md`:
- Around line 28-29: Update the policy statement on line 27 in
docs/harness-improvement-plan.md to reflect that external SaaS billing, limits,
and OAuth facts are now maintained in ADR-071, while retaining the cloud
routines facts assigned to WP-19 and ADR-070. Remove or revise any wording that
says this file remains the source of truth for the migrated facts.
---
Nitpick comments:
In `@docs/adr/adr-071-draft-pr-backpressure.md`:
- Around line 76-79: ADR-071 の料金・認証根拠を記載している表に、GitHub Actions
の料金条件を裏付ける公式資料URLと、claude-code-action の認証条件を裏付ける公式資料または対象 workflow
へのリポジトリ内参照を追加してください。既存の確認日と要約は維持し、各主張から対応する一次資料を再確認できる形にしてください。
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 7162b7c8-d46a-4439-95ba-29dba14a30aa
📒 Files selected for processing (9)
CLAUDE.mdautonomy-config.tomldocs/adr/adr-071-draft-pr-backpressure.mddocs/harness-improvement-plan.mdsrc/cli-autonomy-gate/src/main.rssrc/cli-fix-push-gate/src/main.rssrc/lib-autonomy-policy/src/decision.rssrc/lib-autonomy-policy/src/lib.rssrc/lib-autonomy-policy/src/sources.rs
| ### 残課題 | ||
|
|
||
| - 実測件数を渡す呼び手 (夜間 workflow の `gh api` step) は本 ADR の PR には含まれない。WP-18 PR 3 で追加する。それまで `draft-pr` は `backpressure-unavailable` で deny のままであり、**運用挙動は変わらない**。 | ||
| - bounded lifetime (b) の観測 = 閾値到達での実停止は、夜間ループが 3 件の draft を積むまで発生しない。WP-18 の 2 週間の試験運用期間中に観測できなければ、閾値を一時的に下げて意図的に到達させる。 |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
「draft-pr は deny のまま」の適用範囲を限定してください。
両文書は、PR 3 まで draft-pr に許可経路がないように読めます。しかし、ADR-071 の Line 106-108 は、--open-draft-prs と有効な設定を渡した実行ファイルが allow になることを示しています。
「計画された夜間 workflow の caller が未実装」という意味に限定してください。
docs/adr/adr-071-draft-pr-backpressure.md#L138-L141: 「既存の夜間運用ではbackpressure-unavailableで deny」と記載し、手動実行と drill の allow 経路を除外しないでください。docs/harness-improvement-plan.md#L171-L179: 「PR 1 には本番 workflow の consumer がない」と記載し、draft-prの実行可能な許可経路自体がないように記載しないでください。
📍 Affects 2 files
docs/adr/adr-071-draft-pr-backpressure.md#L138-L141(this comment)docs/harness-improvement-plan.md#L171-L179
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/adr/adr-071-draft-pr-backpressure.md` around lines 138 - 141,
限定的な夜間運用の説明に修正し、docs/adr/adr-071-draft-pr-backpressure.md の残課題では既存の夜間運用が
backpressure-unavailable で deny されると記載しつつ、--open-draft-prs と有効設定による手動実行・drill の
allow 経路を除外しないでください。docs/harness-improvement-plan.md では、PR 1 に本番 workflow の
consumer がないことを示し、draft-pr の実行可能な許可経路自体が存在しないようには記載しないでください。
| > | ||
| > **移管済み(2026-08-06、WP-18 PR 1)**: GitHub Actions 課金 2 点と claude-code-action の OAuth 認証は最新値を再確認したうえで [ADR-071](adr/adr-071-draft-pr-backpressure.md) § 外部 SaaS の課金・上限事実へ移し、本節からは削除した。残る cloud routines の事実群は WP-19 / [ADR-070](adr/adr-070-weekly-review-cloud-routine.md) の担当範囲のため本節に残す。 |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
移管済みの事実と矛盾する旧方針を削除または更新してください。
Line 27 は「外部 SaaS の事実を本ファイルに保持する」と記載しています。一方、Line 29 は同じ事実を ADR-071 へ移管済みと記載しています。
Line 27 を現在の管理場所に合わせて更新してください。古い方針が残ると、将来の更新先を誤る可能性があります。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/harness-improvement-plan.md` around lines 28 - 29, Update the policy
statement on line 27 in docs/harness-improvement-plan.md to reflect that
external SaaS billing, limits, and OAuth facts are now maintained in ADR-071,
while retaining the cloud routines facts assigned to WP-19 and ADR-070. Remove
or revise any wording that says this file remains the source of truth for the
migrated facts.
🤖 PR Monitor 分析 (GitHub Actions バックストップ)
Applicable Findings (Critical / High / Major)(該当なし) Applicable Findings (Medium 以下)
Filtered (not applicable)
次のアクション
|
PR #361 への CodeRabbit レビュー (Minor 2 件) の反映。どちらも「書いた内容が実態より 広い/古い」型の指摘で、妥当。 ## 1. ADR-071 § 残課題: 「draft-pr は deny のまま」の適用範囲を限定 旧文は無条件に「deny のまま」と読めたが、正確には**リポジトリ内の自動化経路に --open-draft-prs を渡す呼び手が 1 つも無いため** deny になる、が正しい。exe を手動で 実行して 3 拠点をすべて満たせば allow になる (drill として意図した挙動)。 「運用挙動は変わらない」という主張の根拠を、exe の挙動ではなく呼び手の不在に置き直した。 根拠を取り違えたまま PR 3 で呼び手が入ると、主張だけが stale に残る。 ## 2. 計画書 § 2 preamble: 移管済みの事実と矛盾する旧方針を更新 旧文は「現時点では ADR 化せず本ファイルに保持する」と書いていたが、同じ blockquote の 次の行で「ADR-071 へ移管済み」と述べており矛盾していた。 方針文を「担当 WP の ADR 起票時に移管し本節から削除する」という恒常ルールへ書き換え、 移管済み / 未移管を別項目に分けた。未移管の内訳 (cloud routines の daily cap / webhook 上限 / GitHub App 必須 / 緑ステータスの意味) も具体名で列挙し、次の担当 WP が何を移管 すべきか読み取れるようにした。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
PR #361 への CodeRabbit レビュー (Minor 2 件) の反映。どちらも「書いた内容が実態より 広い/古い」型の指摘で、妥当。 ## 1. 「draft-pr は deny のまま」の適用範囲を限定 (2 箇所) 指摘は「**両文書**が PR 3 まで draft-pr に許可経路が無いように読める」というもの。実際には ADR-071 § 検証記録の drill #6 が示すとおり、--open-draft-prs と有効な config を渡せば exe は allow になる。 正確には**リポジトリ内の自動化経路に --open-draft-prs を渡す呼び手が 1 つも無いため** deny に なる、が正しい。「運用挙動は変わらない」の根拠を exe の挙動ではなく呼び手の不在へ置き直した。 根拠を取り違えたまま PR 3 で呼び手が入ると、主張だけが stale に残る。 修正箇所は 2 つ: - docs/adr/adr-071-*.md § 残課題 - docs/harness-improvement-plan.md § WP-18 の PR chain 宣言 計画書側から ADR-071 § 残課題への参照も付け、同じ限定が 1 箇所に集約されるようにした。 ## 2. 計画書 § 2 preamble: 移管済みの事実と矛盾する旧方針を更新 旧文は「現時点では ADR 化せず本ファイルに保持する」と書いていたが、同じ blockquote の 次の行で「ADR-071 へ移管済み」と述べており矛盾していた。 方針文を「担当 WP の ADR 起票時に移管し本節から削除する」という恒常ルールへ書き換え、 移管済み / 未移管を別項目に分けた。未移管の内訳 (cloud routines の daily cap / webhook 上限 / GitHub App 必須 / 緑ステータスの意味) も具体名で列挙し、次の担当 WP が何を移管 すべきか読み取れるようにした。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
ddf36bc to
966a895
Compare
* docs(todo): WP-18 で検出した問題を 4 エントリへ登録 (順位 374-377) WP-18 (夜間 todo 消化ループ、#361 / #362 / #363) の実装中に pre-push review・ CodeRabbit・ユーザー指摘で検出した問題 9 件のうち、todo 登録が要る 8 件を **実装時の PR 粒度**で 4 エントリへまとめる。切り分けは 2026-08-06 にユーザー確認済み。 ## 評価時の #1 を検証し、todo 登録が不要になった #1 は「Bash prefix 許可の悪用可能性検証と全経路への横展開」として登録予定だった。 ユーザー指示により登録前に検証したところ、**前提が誤りだった**。 #363 の security review は「`Bash(cargo test:*)` は前方一致でシェルを解釈しないため `cargo test` に任意コマンドを連結すると通過する」と主張していた。公式ドキュメントは これを明確に否定している: Claude Code is aware of shell operators, so a rule like `Bash(safe-cmd *)` won't give it permission to run the command `safe-cmd && other-cmd`. The recognized command separators are `&&`, `||`, `;`, `|`, `|&`, `&`, and newlines. A rule must match each subcommand independently. `--allowedTools` も同じルール体系に属する (managed settings の deny を --allowedTools で 上書きできない、と明記されている)。 結果: - `pr-monitor.yml` の Phase A 分析 agent に**当該の穴は無く、対処不要**。production の live な穴という当初の見立ては誤りだった - 残作業は `ADR-072` 決定 5 の根拠記述の訂正のみで、#363 が open のうちに同 PR へ直接 反映する。よって todo エントリを立てない 検証結果と経緯はセクション冒頭の対応表に残した。 ## この一件自体を教訓として取り込んだ 「レビュー指摘への対応時チェックリスト」エントリに 4 項目目を追加した — **指摘が技術的 前提 (ツールの挙動・仕様) に依拠しているなら、対処より先にその前提を検証する**。とくに 設計変更や他経路への横展開を伴う場合。 今回は未検証の前提のまま (a) agent から Bash を落とす設計変更を行い、(b) それを ADR の 決定として記録し、(c) さらに「同じ形が production にもある」と横展開の警告まで出していた。 一次情報に当たれば 1 回の WebFetch で否定できた。 ## 内訳 - 順位 374: WP-18 夜間ループの実走スモーク実施 (Tier 1、評価時の #2/#3) - 順位 375: レビュー指摘への対応時チェックリスト (Tier 2、評価時の #4/#5/#6 + 今回の #1) - 順位 376: push-runner の bookmark 自動前進がスタック境界を壊す (Tier 2、評価時の #7) - 順位 377: 夜間ループの防御を検知から防止へ格上げする判断 (Tier 3、評価時の #8/#9) ## まとめ方の方針 リポジトリの既存バッチ登録 (#350〜#357 の 24 件を 8 エントリへ) と同じく実装時の PR 粒度で まとめた。評価時の番号との対応はセクション冒頭に表で残してある。 順位 374 (スモーク) の観測項目は `ADR-072` の実走スモーク節に表があるため、todo 側は スケジューリングの掛かりだけを持ちチェックリストを複製しない。同じ表を 2 箇所で管理すると 必ず drift する (#362 の post-merge feedback が指摘した single source-of-truth 問題と同型)。 ADR-033 (絶対番号は table のみに保持) に従い、エントリ本文には順位番号を書いていない。 todo20.md は 50KB 閾値内。pnpm lint:docs / markdownlint ともに green。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(todo): #363 post-merge feedback の採用 6 件を登録 (順位 378-383) WP-18 最終 PR (#363、ADR-072) のマージ後 feedback が Tier 1 に 4 件・Tier 2 に 2 件を 採用候補として挙げた。ユーザー承認 (2026-08-07) を得て登録する。 ## 6 件は 1 本の根から出ている 台帳 (docs/claude-code-web-tasks.md) の 内容 / 対象ファイル / 注意 は自由記述のまま 無人 agent のプロンプトへ流入する。agent は $GITHUB_WORKSPACE 全体に書き込め、その 出力は draft PR 本文という公開面に出る。ADR-054 の信頼境界そのもの。 - 378 (XS) 台帳を ADR-035 の docs-only 除外パス表へ追加 — 他 3 件の前提。台帳だけを 変える PR が緩い評価経路に乗ると、対策そのものを迂回する台帳 PR が通りうる - 379 (S) tool scope を work/** へ限定 — ADR-072 決定 7 の改ざん検知が必要になって いる根本原因。実装後も検知層は残す (防御を 1 枚に減らす変更ではない) - 380 (M) 台帳フィールドを untrusted data として明示 framing - 381 (S) 台帳由来 SUMMARY の draft PR 本文出力に screening - 382 (M) injection payload の regression test (380 に依存) - 383 (S) is_separator_row のパイプ検証欠落 ## 期限を「定常運用開始前」に固定する 実効リスクは現時点では低い — 悪意ある台帳行を master へマージするのはユーザー自身で、 単独運用では外部からの注入経路が無い。ただし夜間ループが定常運用に入り draft PR の 流量が増えると前提が変わるため、無期限の Tier 積みにしない。 順位 374 (実走スモーク) は dry_run で PR を作らないため本件の実害が無く、待たせない。 ## 383 は実コードで確認済み is_table_row は行頭 | を要求するが、is_separator_row は split_cells の結果しか見ない。 split_cells("---") は ["---"] を返し全セルが '-' のみなので真になる。markdown の 水平線がセパレータ行として通る (todo ファイル自身が --- を使っている)。 ADR-072 決定 2 の fail-closed 設計の coverage hole。 ## 併せて 順位 374 のスモーク観測項目数を 4 → 8 へ修正した (ADR-072 側の実測と不一致だった)。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(harness-plan): WP-18 を 3 PR マージ済へ更新し残作業 2 系統を明示する #363 のマージ (2026-08-07) で WP-18 の実装 3 本がすべて land した。 ## 「実装完了 = WP 完了」ではないことを表で残す コードは全部 master にあるが、**夜間ループはまだ 1 度も走っていない**。この状態を 「実装済」の一語で片付けると、次のセッションが受け入れ基準を満たしたものと誤読する。 残作業を 2 系統に分けて表にした: 1. 実走スモーク (順位 374) — 受け入れ基準の中核 2. prompt injection 対策 4 件 (順位 378-381) — 定常運用開始前に必須 ## スモークの前提が充足したことを記録 受け入れ基準の表は「(a) workflow が master にある (b) 台帳に無人可マークがある」を 未充足として書いていたが、**両方ともマージで解消した**。残る操作は GitHub UI 側の AUTONOMY_ENABLED 設定のみなので、その 1 点へ書き換えた。 ## 依存関係を明示する 378-381 は 1 本の根 (台帳の自由記述が無検証で agent プロンプトへ流入) から出ている。 一方スモークは dry_run で PR を作らないため本件の実害が無い。したがって **スモークは 378-381 を待たずに着手してよい**と明記した。次セッションが順序で 迷わないようにするため。 ## 未 push の改善 3 点の所在を残す #363 の最終 push が security REJECT で止まったため、改ざん検知の red 化 / 決定 10 の 色分け表 / 決定 6 の列挙基準が master に載っていない。ローカル bookmark wp18/unpushed-improvements (fc22403c) に保持していることを記録した。いずれも 可観測性と文書の改善で、fail-closed 自体は master 版でも成立している。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(todo): 外部設定 (GitHub App / variables / secrets) の実体記録を登録 (順位 384) 新セッションでの指摘 (2026-08-07): workflow は vars.NIGHTLY_APP_ID / secrets.NIGHTLY_APP_PRIVATE_KEY を参照するが、App の作成・インストール・登録を 記録した文書がリポジトリ内に無い。 ## 欠けているのは設計根拠ではなく運用実体 ADR-072 決定 8 は「なぜ App token か」「なぜ PAT ではないか (オーナー PAT は Repository admin として ADR-067 の ruleset backstop を素通りする)」「どの権限を 付けるか (Workflows は付けない)」「なぜ publish 直前に発行するか (token 寿命 1 時間)」を厚く残している。 記録が無いのは以下: - App を実際に作成した事実・日付・名称・インストール範囲 - NIGHTLY_APP_ID = variable / NIGHTLY_APP_PRIVATE_KEY = secret という登録先の別 - 既存の Claude GitHub App との区別 (あちらは Workflows を含む広い権限を持つ別物) - 再構築手順 (鍵ローテーション・派生プロジェクト展開) NIGHTLY_APP の文字列はリポジトリ全体で workflow の 2 行と ADR 残課題の 1 行にしか 現れない。 ## これは ADR-051 違反 ADR-051 (クロスシステム設定 coupling) は内部設定と外部 SaaS 設定が論理結合する場合に (1) 両設定ファイルへの相互参照コメント (2) 期待値の組み合わせ表の ADR 必須記載 (3) 変更は両側を同一 PR、の 3 点を規律として定めている。workflow ↔ GitHub App + repository variables/secrets はこの型で、3 点とも未実施。 前例として ADR-067 段 0 は repository ruleset を ruleset 名つきで「設定済み」と 記録している。ADR-072 は同じ扱いをしていない。同型の欠落が AUTONOMY_ENABLED にも あり (ADR-066 は「Actions variable を使う」とは書くが現状値を記録していない)、 本エントリで一緒に扱う。 ## 順位 374 と同時実施にする理由 スモークでは AUTONOMY_ENABLED の設定と App token の実動確認のため GitHub UI を 触るので、その過程で実値がすべて揃う。先行して記録しようとすると値が確定せず 二度手間になる。 ## 教訓を残す App の作成手順・Expire user authorization tokens の扱い・既存 App との違いは 2026-08-07 のセッションでユーザーへ提示したが、リポジトリへ残さなかった。会話は 次のセッションに残らないが workflow は残る。参照だけが残って由来が消える状態を 作った。順位 375 と同じクラスの失敗としてエントリ本文に記録した。 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(review): CodeRabbit Major 4 件を妥当性判定のうえ 3 件へ対応する (#364) 自動 fix 経路 (f698d19) が 1 件 (#4 台帳への非記録ルール追加) を対応済みで、 本コミットはその内容を含んだうえで残りを手で対応した結果である。同一ファイルの 近接行のため path 単位で分離できず 1 コミットに畳み込まれている。 ## 妥当性の判定 severity ラベルではなく、プロジェクトの設計方針に照らして 1 件ずつ判定した。 - #1 adr-072:335 (秘密値を ADR に記録しない) — **妥当**。「実走スモークで実値を 確認し ADR へ追記する」は秘密鍵本文まで書くと読める。ADR-051 が記録を課すのは 結合の存在と期待値の組み合わせであって秘密の実値ではない。設定メタデータに 限定し、鍵本文と token は ADR にも git 履歴にも残さないことを明記した - #2 harness-improvement-plan:223 (受け入れ基準が成功経路だけ) — **妥当**。本 プロジェクトは背圧 12 シナリオ・kill-switch 8 シナリオと停止側を drill で 固めてきたが、夜間ループの停止側は実走未観測。WP-17 の残課題 (明示的 false と config 側 deny が実走未観測) と同じ穴。AUTONOMY_ENABLED の 3 状態を受け入れ 基準へ追加した。指摘本文が名指しした 2 箇所 (計画書 L223 / todo20 L293-304) の 両方に反映している - #3 todo20:480 (prompt injection の回帰 fixture) — **妥当**。順位 382 の payload 例 "; echo PWNED; #" は shell injection であって prompt injection ではない。 台帳テキストが流れ込む先は shell ではなく LLM プロンプトなので、テストが目的と 噛み合っていなかった。自然言語 adversarial payload (本命) と shell/パース形式 payload (堅牢性) の 2 系統へ分離した ## 自動 fix の実測確認 f698d19 は 1 ファイル 2 行追加のみで範囲外の編集ゼロ。内容も妥当だったため そのまま採用した (ADR-068 の後退検知の趣旨に沿って diff を実測で確認済み)。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
概要
WP-18(夜間 todo 消化ループ)の PR 1 / 3 本。draft PR 作成クラス(ADR-052 の自動実行可クラス)を有効化するための前提条件である**背圧(自主減速)**を決定論層に実装する。
これまで
lib-autonomy-policyはOperation::backpressure_connected()がDraftPr => falseを固定で返し、kill-switch の 2 面がどちらも有効でもdraft-prを構造的に deny していた。これは未実装の placeholder ではなく「背圧より先に draft PR 自動作成が有効化される順序事故」を型で塞ぐ意図的な状態で、ADR-052 原則 5 の契約に対応する。本 PR はこの deny を、契約を満たしたうえで解除する。設計判断は ADR-071 に起票した(試験運用、bounded lifetime 2026-11-06)。
変更内容(5 コミット)
feat(autonomy-policy)backpressure_connected()を廃し、requires_draft_backpressure()(指標の要求)とGateInputs::{open_draft_prs, max_open_draft_prs}(状態)へ分離feat(autonomy-policy)max_open_draft_prsをautonomy-config.tomlから 1 回の read で取り込むfeat(autonomy-gate)--open-draft-prsで実測 draft 数を受け取り背圧を接続docs(adr-071)docs(harness-plan)設計上の要点
背圧の状態は 1 箇所だけが持つ
計画書が明示要件としていた「同じ背圧状態を 2 箇所で持たない」に対応する。
Operationはどの指標を要求するかだけを持ち、指標の実測値・閾値はGateInputsが持つ。enum 側にも状態を置くと片方だけ更新した瞬間に判定経路が二股に分かれるため、背圧の真偽を導出する場所はevaluate()の 1 箇所に限った。FixPushが draft 数を要求しないのは背圧が無いからではなく、その背圧が cli-pr-monitor の有界 retry(max_retries)で、呼び出しごとに gate へ渡す状態を持たないため。この非対称は doc コメントとテストの両方で固定した。閾値判定の層
計画書が「実装時の設計判断」としていた 2 択のうち (a) gate 内を採用した。WP-19 ステップ 2 が「instruction 層の自己抑制ではなく決定論層へ格上げする」方針であり、判定を workflow step 側に置くと減速ロジックが YAML の式に散るため。
欠損はすべて停止側へ
0(数えて 0 件)とNone(数えられなかった)を型で区別する--open-draft-prsの不正値(空文字 / 負値 / 小数 / 非数値)→ exit 2 で loud に落とす。gh api失敗時の出力を 0 件と読み違えるのが最も避けたい failure mode のためenabledごと読めなくなる = 全停止。config が半壊した状態を「kill-switch だけ有効」で運転させない判定は
>=max_open_draft_prs = 3なら 3 件目が未マージの間は新規作成しない。0は「draft を 1 件も作らない」= draft-pr クラスだけの停止で、全体 kill-switch を倒さずに夜間ループだけを止める操作点になる。PR chain 宣言(ADR-069 決定 1)
本 PR が導入する 3 点は PR 3 まで呼び手を持たない。ペアリングは
docs/harness-improvement-plan.md§ WP-18 の表で具体名指定した。cli-autonomy-gateの--open-draft-prs <count>gh apiで数えた件数を渡すautonomy-config.tomlの[autonomy] max_open_draft_prs--configに渡す master ref の写しを通じて読まれるOperation::DraftPrの許可経路cli-autonomy-gate --operation draft-prを実行し exit 0 のときだけ後続へ進む順序は逆にできない。ADR-052 原則 5 が背圧の接続を draft-pr クラス有効化の前提条件としているため(WP-17 の kill-switch 先行と同構造)。
本 PR 単体では
draft-prはbackpressure-unavailableで deny のままであり、運用挙動は変わらない。検証
drill 12 シナリオ(release build の実 exe)
--open-draft-prs省略 / 閾値キー無しbackpressure-unavailable、exit 1ok(2/3)、exit 0backpressure-saturated、saturated(3/3)、exit 1backpressure-saturated、exit 1fix-push/ open=99 limit=3structural、exit 0"3"repo-config-unavailable(enabledごと停止)、exit 1--open-draft-prs abc/-1#6/#7 の対で
>=境界、#8 でlimit = 0の停止、#9 で fix push が draft 数から独立していることを実バイナリ上で確認している。その他
cargo test --workspacegreen(40 スイート)/cargo clippy --workspace --all-targets警告ゼロpnpm lint:docs/ markdownlint green[AUTONOMY_ALLOW] operation=draft-pr ... backpressure(draft-pr)=ok(1/3)計画書からの知識移管
docs/harness-improvement-plan.md§ 2 が保持していた外部 SaaS の課金・上限事実のうち、GitHub Actions 課金 2 点と claude-code-action の OAuth 認証を 2026-08-06 に最新値で再確認し ADR-071 § 外部 SaaS の課金・上限事実へ移管した(退役条件 2 / 順位 117 の 3 ステップ原則)。cloud routines の事実群は WP-19 / ADR-070 の担当範囲のため計画書に残している。要約すると Actions の実行時間は無料だが Max 枠は有限であり、これが背圧の経済的根拠になる。
Summary by CodeRabbit