Skip to content

feat(pr-monitor): Phase B 無人 fix push を追加し ADR-067 を起票 (WP-17 2c) - #352

Merged
aloekun merged 9 commits into
masterfrom
feat/wp17-r2c-phase-b
Aug 3, 2026
Merged

feat(pr-monitor): Phase B 無人 fix push を追加し ADR-067 を起票 (WP-17 2c)#352
aloekun merged 9 commits into
masterfrom
feat/wp17-r2c-phase-b

Conversation

@aloekun

@aloekun aloekun commented Aug 3, 2026

Copy link
Copy Markdown
Owner

概要

WP-17 PR 2 の再分割 2c(最終)です。2b で入った cli-fix-push-gate の workflow 呼び手を
land し、Phase B(claude/ ブランチ限定の無人 fix push)を構成します。これで 2b の
chain 宣言が約束した消費者が揃い、宣言チェーンが閉じます。

マージと有効化のタイミング

autonomy-config.toml は本 PR で enabled = true になり、Actions variable
AUTONOMY_ENABLED は設定済みのため、マージすると kill-switch の両層が揃います。

ただしマージ直後に実際に起きることはほぼ何もありません。fix job は step 2
(Decide whether Phase B applies)以降の全 11 step が proceed == 'true' でゲートされて
おり、proceed = true は「非 fork・OPEN・claude/ prefix ブランチ」のみ。claude/*
PR は現存せず、base リポジトリにブランチを作るには write 権限が必要、fork は明示 deny です。
つまり当面は「CodeRabbit イベントごとに fix job が数秒で proceed=false 終了する」だけで、
LLM 起動(Max 枠消費)も checkout/build も発生しません(計画書の「Phase B の実効価値は
WP-18 着手まで小さい」の記載どおり)。

それでも下記の手順でマージ前スモーク → variable 削除 → マージ → 再設定と段階を踏み
ます。理由: 本 PR は pre-push レビュー 5 ラウンドで実在の Critical が出続けており、静的
レビューだけで確信が収束していないためです(ADR-066 の「削除 = 停止」を設計どおり使う)。

マージ手順(順序厳守)

  1. 段 0(ユーザー、GitHub UI): repository ruleset で claude/ 以外への GITHUB_TOKEN
    push を deny(5 層目の防波堤)。
  2. 段 0.5(ユーザー、マージ前): Actions → pr-monitor → Run workflow で ref に本 PR の
    ブランチ feat/wp17-r2c-phase-b を選択
    し、pr_number に適当な open PR 番号を入れて
    実行。gate と config は master ref から調達されるため master 側は enabled = false
    ままで、fix job は config 層で停止するのが期待動作。ここで workflow 構文 / job 配線 /
    variable 層 / master-ref 調達 / deny 経路(kill-switch が効く側)が実走確認できます。
  3. variable AUTONOMY_ENABLED を削除(ユーザー。段 0.5 は variable 層を通す必要が
    あるため、削除は必ず段 0.5 の後)。
  4. マージ。variable が無いため fix job は if: で起動せず、live になりません。
  5. 段 1: variable を再設定 → 非 claude/ PR への workflow_dispatch で
    [FIX_PUSH_DENY] branch=... claude/ prefix ではない の degrade を確認。
  6. 段 2: claude/ prefix のテストブランチで docs 指摘のある PR を作り、allow 経路
    (gate exit 0 → workflow step が push)と deny 経路(variable 削除で job skip)を観測。
  7. 結果を ADR-067 の検証記録と ADR-066 / ADR-068 の bounded lifetime 観測へ記帳。

スモークの追加観測項目: coderabbitai[bot] の permission 解決

actor gate(レビュー 5 ラウンド中の修正で導入)は pull_request_review 経路の reviewer に
実リポジトリ権限(admin/maintain/write)を要求します。coderabbitai[bot] は collaborator
ではない可能性が高く
、その場合 permission 解決が失敗 → 空 → deny となり、CodeRabbit の
レビュー提出経路の Phase B は恒久 deny になります(fail-closed なので危険はないが、
walkthrough コメント = issue_comment 経路だけが生きる形になる)。

段 1〜2 で run log の [PHASE_B_ACTOR] / [PHASE_B_ACTOR_UNRESOLVED] マーカーを確認し、
bot 経路が deny であれば actor gate への bot allowlist 追加を follow-up として判断して
ください(コメント内容側はレビュー中に入った決定論著者フィルタが既に守っているため、
追加しても多層防御は崩れません)。

設計(詳細は ADR-067)

内容
agent は push しない fix agent は Bash を持たず、書き込みは pr/docs/** のみ。push は workflow step
findings と fix は別 agent allowlist を fix agent 自身に作らせると自己申告の追認になる
入力は決定論層で著者フィルタ coderabbitai[bot] の投稿のみを jq で抽出してから LLM に渡す。findings agent は gh api を叩けない
ゲートと config は master ref から PR ブランチ側を使うと自律 actor が自己解除できる
4 軸 AND / fail-closed kill-switch / claude/ prefix / docs-only / scope guard
actor gate needs.analyze.result == 'success' + reviewer の実リポジトリ権限(admin/maintain/write)

レビューで検出・修正した欠陥(5 ラウンド)

pre-push レビューが実在の認可・注入欠陥を 7 件指摘し、すべて修正済みです。

# 深刻度 内容
1 Critical head_ref の未エスケープ展開 → ゲート実行前のコマンド注入。ブランチ名に $(...) が使えるため成立
2 Critical カスタム if:needs の暗黙 success を上書きし、analyze の actor 制限を継承していなかった
3 Critical findings agent が著者フィルタなしで comments/reviews を取得。権限ゼロのアカウントが指摘を捏造し無人 push を誘導可能
4 High 「この step は担保ではない」というコメントが誤り。ゲートの 4 軸は fork / PR state を見ておらず、実際はこの step が唯一の検査
5 Medium author_associationCOLLABORATOR/MEMBER は write 権限を含意しない
6 Blocking continue-on-error 欠落で degrade step ごと skip
7 Medium degrade の if: に暗黙 success() が前置され、前段失敗時に診断行が出ない

加えて自主対応 3 件(findings agent の未使用権限削除、reviewer 権限解決の env 経由化、
API 失敗の loud marker 化)。各ラウンドで YAML パース・if: の単一性・step 構造・
claude_args の全行フラグ形式を機械検証しています。

ADR 記帳

  • ADR-067 起票 — Phase B の設計全文、外部 SaaS 事実の永続化、bounded lifetime
    (自律 fix push 3〜5 回で判定、期限 2026-11-02)
  • ADR-069 § 実測 1/2 — chain 宣言の初回 dogfood(trigger (a) 充足)と、宣言の
    「検証可能性」という欠落要件の発見
  • ADR-068 § 観測 — docs-only fix の事実性はどの決定論層も検査していない、という穴の記録
  • ADR-052 の stale 記述訂正

検証

  • cargo test --workspace 1945 件 pass / pnpm lint:docs / lint:md 0 error
  • workflow は js-yaml でパース検証(13 step、fix job の if: / permissions / claude_args)
  • ゲート単体 drill 7 シナリオは 2b で実測済み(ADR-067 § 検証記録)
  • E2E 実走は上記マージ手順の段 0.5〜2 で実施

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 新機能

    • 条件を満たすプルリクエストで、ドキュメントのみの修正を自動適用・反映できるようになりました。
    • 修正内容、対象範囲、ブランチなどを検証し、安全性を確認できた場合のみ反映します。
    • 条件不成立や検証失敗時は自動反映せず、従来のレビュー処理へ移行します。
  • ドキュメント

    • 自動修正機能の運用条件、制約、停止手順、検証結果に関する設計資料を更新しました。
    • 関連する作業計画とアーキテクチャ記録を整理しました。

aloekun and others added 7 commits August 3, 2026 18:06
pr-monitor.yml に fix job を追加し、Actions variable AUTONOMY_ENABLED = 'true' の
ときだけ claude/ ブランチ PR の docs 指摘を無人で修正・push する。既定 OFF。

## contents: write 昇格に対する代替担保

Phase A の安全担保の主体は contents: read (push が 403 で決定論的に失敗) だった。
Phase B ではこれが使えないため 4 点で代替する:
1. fix agent に Bash / gh / git を一切与えない。push を実行できるのは workflow step
   だけで、LLM は push の主体になれない (Phase A で「コメント投稿はエージェント外の
   後続 step」としたのと同じ形)
2. agent の書き込み先を pr/docs/** に scope する (許可ツール自体をパス制限)
3. push 直前に cli-fix-push-gate が 4 軸 AND を決定論判定し、非ゼロなら push しない
4. ゲート exe と autonomy-config.toml を master ref から調達する

4 が信頼境界の要。PR ブランチの checkout に含まれるゲートのソースや config を使うと、
自律 actor 自身が自分の制限を書き換えて自己解除できる (ADR-054 と同型)。master を
別ディレクトリへ checkout し、そこで cargo build したバイナリと config だけを使う。

## findings と fix の agent 分離

scope guard の allowlist を fix agent 自身に作らせると自己申告の追認になるため、
read-only の findings agent を先行させて allowlist を確定させる。ローカル経路で
review facet と fix step が別エージェントなのと同じ分離を CI でも保つ。

## degrade 経路

早期打ち切り (fork / 非 OPEN / 非 claude ブランチ)、findings ゼロ、ゲート deny の
いずれでも run を失敗させず、[FIX_PUSH_DENY] を出して Phase A 相当 (分析コメントのみ)
に落ちる。gate step は continue-on-error で outcome を分岐に使う。

## 副次的な安全性

GITHUB_TOKEN による push は新たな workflow run を発火させない (GitHub 仕様)。
Phase B → pr-monitor 再起動の無限ループが構造的に起きない。

## 実装上の注意点 (レビュー観点)

- findings agent の出力パスはリポジトリルート起点を要求する。`pr/` プレフィックスを
  付けると全件が scope 違反になるため prompt で明示した
- git の --name-status は tab 区切りだが lib-scope-guard は空白区切りを期待するため
  最初の tab のみ空白へ正規化する。rename は "R100" status となりパーサが fail-closed
  で弾く
- findings_json が skip されると count が空文字列になる。`!= '0'` だけでは通過するため
  outcome の成功を明示的に AND した

検証: js-yaml でパースし job/step/条件チェーンを確認。実走スモークは Actions variable
設定と claude/ テストブランチが要るためユーザー操作後に実施する (ADR-067 § 残課題)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
呼び手 (pr-monitor.yml の Phase B fix job) が実装されたため、autonomy-config.toml の
[autonomy] enabled を true へ倒す。リポジトリとして自律 fix push を許可する意思表示。

**これだけでは Phase B は動かない。** 判定は repo config と外部フラグの AND で、
GitHub Actions 側は Actions variable AUTONOMY_ENABLED = 'true' が別途必要。
それは admin (リポジトリ所有者) だけが設定できるため、実際の有効化タイミングは
引き続き人間が握る。本コミットのマージによる挙動の変化はゼロ。

検証 (pnpm autonomy-status): repo_config=enabled / AUTONOMY_ENABLED=unset で
reason=external-unset の deny。AND 合成が設計どおり効いていることを実測した。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… PR 2)

Phase B の設計判断を永続成果物へ移管し、計画書 (ephemeral) の PR 2 節を ADR 参照 +
残作業のみへ縮約する (順位 117 の知識移管 3 ステップ)。

ADR-067 が記録する主な決定:
- agent を push の主体にしない。Phase A で「コメント投稿はエージェント外の後続 step」と
  した形を push でも踏襲する。contents: write を持つのは job だが、行使できるのは
  決定論的 step だけで、prompt injection が成立しても push 先・内容は変えられない
- findings agent と fix agent の分離。fix を書く agent 自身に findings を出させると
  scope guard の allowlist が自己申告になり ADR-054 の防御が成立しない
- ゲート exe と config を master ref から調達。PR ブランチ側を使うと自律 actor が
  自分の制限を書き換えて自己解除できる。ADR-066 § 決定 3 は config だけを想定していたが、
  ゲート実行ファイル自体も同じ信頼境界に属することを本 ADR で明示した
- 自動化範囲は docs 指摘の修正に限る。Tier 3 cleanup は機械判定できず分類不能 =
  ゲート必須へ倒れる (ADR-052 原則 3)。意図的に狭い保守的な出発点
- degrade は失敗ではない。Phase B は Phase A の上乗せで、上乗せ不成立を CI 失敗に
  すると本物の失敗と区別できなくなる (ADR-065 の判断と同じ論理)
- 無限ループは GITHUB_TOKEN push が run を発火させない仕様に依存している。token 種別を
  変える際はこの防御が消えることを明記した

§ 2 外部 SaaS 事実の永続化 (計画書の必須要件): 2026-08-02 に公式 docs で再確認し
両事実とも維持を確認して ADR へ移管した。
- public リポジトリ + standard runner の Actions は無料・無制限 (分数枠は private のみ)
- claude-code-action は claude_code_oauth_token (claude setup-token 生成、Pro/Max) 対応
本リポジトリは public のため cargo build を含む job 追加でも Actions 課金は発生しないが、
Max 枠は agent 2 本分消費する点を欠点として記録した。

ADR-052 の stale 記述訂正:
- 実装スコープ節の「gate.rs の docs-only 判定を lib へ切り出す (現状 pub(crate))」は
  ADR-057 の副産物として完了済み。取り消し線 + 訂正注記を付けた
- 同節冒頭に「呼び手は WP-17 で実装済み (ADR-066 / ADR-067)」の追記を入れ、
  「呼び手が無いので分類関数は見送る」という起票時判断が現状と食い違わないようにした

検証: cargo test --workspace 1936 件 pass (失敗 0)、cargo clippy --workspace
-D warnings 緑、pnpm lint:docs / lint:md (120 ファイル) 0 error。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2c の land にあたり、2b で得られた 2 件の実測を永続記録へ移す。あわせて計画書の
状態行を更新する。

## ADR-069 § 実測 1: chain 宣言の初回 dogfood (trigger (a) 充足)

PR #351 で、宣言付き先頭 PR が missing-consumer で REJECT されないことを実測した。
simplicity review は宣言を字面で受け取らず、決定 1 の 3 要件を個別に照合したうえで
(diff 内の計画書である / 後続 PR と step 名を具体名で指名 / 引数 4 種が main.rs の
parse_args と一致) non-blocking warning へ降格した。「名前一致」要件が実際に検査される
ことを確認できた。

## ADR-069 § 実測 2: 宣言の「検証可能性」という欠落要件

同 PR で、決定 1 の 3 要件では捉えられない問題が出た。当初の宣言「2c の実体で照合済み」
は**真**だが、PR の diff だけを見るレビュアーには**検証できない主張**だった。決定 1 の
名前一致要件は暗黙に「diff 内で照合できること」を前提にしている。後続 PR の実体にしか
存在しない名前を含める場合は、その部分が検証不能である旨を宣言自身が明示するのが正しい。
実測 1 件のため要件化はせず、本採用時の判断材料として記録に留める。

## ADR-068 § 観測: docs-only fix の事実性は無検査

上記 2 の往復で、post-PR の fix step が真の記述を偽へ書き換えて auto-push した。このとき
決定論層はすべて設計どおり動作している — scope guard は編集**範囲**を、docs-only 判定は
変更**クラス**を、後退検知は量的後退を見るが、**内容の真偽はどの層も見ていない**。
コードではコンパイル・テストが事実性の代理検査になるが docs には代理が無い。

観測 1 件で機構は足さない (最小処置原則)。再検討の条件を 2 つ明記した。うち 1 つは
Phase B の無人 fix push (本 PR で live になる) で同種の誤りが出たとき — Phase B の対象は
docs 指摘に限られるため、この穴は Phase B の主要リスク面と重なる。ADR-067 の bounded
lifetime 観測時に併せて確認する。

## workflow 構文検証 (計画書 § 2c 手順 3)

js-yaml で pr-monitor.yml をパースし、fix job の構造を機械的に確認した:

- jobs: analyze, fix / triggers: pull_request_review, issue_comment, workflow_dispatch
- fix.if: `vars.AUTONOMY_ENABLED == 'true'` (kill-switch 第 1 層)
- fix.permissions: contents: write, pull-requests: read
- 12 step。step 10 `Gate fix push (deterministic, 4-axis AND)` は continue-on-error、
  step 11 が `Push fix (workflow-authored, not agent-authored)`

step 10 の名称が 2b の chain 宣言と完全一致していることも確認した (ADR-069 決定 1 の
名前一致要件を、後続 PR 側から閉じたことになる)。

検証: cargo test --workspace 1945 件 pass、pnpm lint:docs / lint:md 0 error。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
pre-push simplicity review の非ブロッキング指摘への対応。

`Report degrade to Phase A` の guard `steps.gate.outcome != 'success'` は 2 つの異なる
事象で真になる:

1. gate が走って push を拒否した (outcome = failure)
2. gate に到達しなかった (findings 0 件 / 前段 step の skip・失敗。outcome = '' or 'skipped')

旧実装はどちらでも「直前の gate step の [FIX_PUSH_DENY] 行を参照してください」と出して
いたため、2 のケースで**存在しない行を案内**していた。

この workflow の run log は ADR-067 bounded lifetime の観測チャネルそのもの (自律 fix push
3〜5 回で判定する)。degrade 理由が不正確だと、判定材料として読むときに「gate が拒否した」
と「そもそも到達していない」を取り違える。両者は意味が全く違う — 前者は 4 軸判定が働いた
証拠だが、後者は判定に至っていないだけである。

skip された step の outcome は '' と 'skipped' のどちらもあり得るため、「gate が走った」
ことを示す値 (failure) だけを明示的に判定し、それ以外は未到達として扱う (fail-safe な
分岐方向)。

検証: js-yaml パースで 12 step の構造が維持されていることを確認。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
pre-push simplicity review の非ブロッキング指摘への対応。

findings agent の `--allowedTools` に `Bash(gh pr diff:*)` と `Read(master-ref/CLAUDE.md)`
が入っていたが、本 agent のプロンプトはどちらも参照しない (指摘は comments / reviews の
2 エンドポイントから取得し、`file` の実在確認に `pr/docs/**` を読むだけ)。Phase A の
analyze job の allowedTools からの写しと見られる。

**本 agent の出力は scope guard (ADR-054) の allowlist を確定させる**ため、余剰権限は
「allowlist を作る主体」の攻撃面をそのまま広げる。findings と fix を別 agent に分けた
のは自己申告の追認を避けるためで、その分離の価値は findings 側の権限が絞られている
ことに依存する。本 PR 自身の主題 (最小権限・信頼境界) に照らして落とす。

## 検証スクリプトを 1 本追加した理由

説明コメントを `claude_args: |` の中に書きかけて気付いたが、**リテラルブロック内の `#`
行は YAML コメントではなく引数文字列**になる。混入すると agent に不正なフラグが渡る。
目視では気付きにくいため、js-yaml でパースして claude_args の全行が `--` 始まりか検査
するスクリプトを scratchpad に置き、本コミットで実行して 3 agent 分すべて緑を確認した
(説明はブロック外の YAML コメントへ移動済み)。

検証: js-yaml パースで 12 step 構造が維持されていること、claude_args 全 12 行が
フラグ形式であることを確認。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
前ラウンドの fix が追加した `Resolve reviewer repository permission` step への follow-up。
指摘の趣旨 (author_association では write を含意しない) の対応自体は妥当だが、実装に
2 点の弱さがあったため補強する。

## (a) reviewer 名を env 経由へ

`${{ github.event.review.user.login }}` を bash の run ブロックへ直接展開していた。
GitHub の username は英数字とハイフンのみでシェル注入は成立しないため実害は無いが、
同じ job の他 step は SEC-NEW-pr-monitor-yml-L512 対策で env indirection に統一済み
であり、ここだけ例外にすると「安全性が値の文字種を読者が知っていることに依存する」
状態が残る。GITHUB_REPOSITORY も組み込み env を使い、run ブロックから式展開を無くした。

## (b) API 失敗を無音にしない

`collaborators/{user}/permission` は push 権限を要求する endpoint のため、
GITHUB_TOKEN の permissions 次第では 403 になり得る (reviewer が collaborator で
なければ 404)。旧実装は `set -e` も無く失敗時に PERMISSION が空のまま step 成功と
なっていた。

空 permission は fix job の actor gate で不一致になり Phase B は起動しない = fail-closed
なので方向は正しい。しかし **「権限が足りない reviewer だった」と「API 自体が呼べない」
は原因が全く違う**。後者なら pull_request_review 経路の Phase B が恒久的に死ぬが、
run log には何も出ないため気付けない。ADR-064 が排除した「silent success」と同型の穴。

成功時 `[PHASE_B_ACTOR]`、失敗時 `[PHASE_B_ACTOR_UNRESOLVED]` + stderr を出力し、
どちらの経路を通ったか run log から判別できるようにした。判定自体は従来どおり
fail-closed のまま。

なお本 endpoint が GITHUB_TOKEN で実際に呼べるかは静的には確定できない。マージ前
スモーク (計画書 § 2c 段 0.5) の観測項目として扱う — 呼べなければ上記 marker が出る。

検証: js-yaml パースで 12 step 構造と claude_args 全行のフラグ形式を確認。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: cd363bfd-5171-4b14-ace8-cd87dd70e0db

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

PR モニターに Phase B を追加しました。CodeRabbit の docs 指摘を allowlist 化し、許可された Markdown だけを修正します。4 軸ゲートが成功した場合のみ workflow step が commit・push します。

Changes

Phase B 自律修正フロー

Layer / File(s) Summary
起動条件と設計契約
.github/workflows/pr-monitor.yml, autonomy-config.toml, docs/adr/adr-067-phase-b-unattended-fix-push.md, docs/adr/adr-052-autonomy-execution-boundary-classes.md, CLAUDE.md
レビュー投稿者の実リポジトリ権限を解決します。AUTONOMY_ENABLED、config、権限を起動条件にします。agent と workflow step の責務を分離します。
PR 対象選択と master 基準
.github/workflows/pr-monitor.yml, docs/adr/adr-067-phase-b-unattended-fix-push.md
非 fork、OPEN、claude/ ブランチの PR だけを対象にします。PR ブランチと master ref を分離して checkout します。
findings 抽出と docs 編集
.github/workflows/pr-monitor.yml, docs/adr/adr-067-phase-b-unattended-fix-push.md
CodeRabbit のレビュー情報を JSON findings に変換します。fix agent は allowlist 内の docs/**/*.md だけを編集します。
ゲート判定と push
.github/workflows/pr-monitor.yml, autonomy-config.toml, docs/adr/adr-067-phase-b-unattended-fix-push.md, docs/adr/adr-068-fix-step-authority-boundary.md, docs/adr/adr-069-pr-chain-declaration.md, docs/harness-improvement-plan.md
master 由来のゲートで kill-switch、target、内容、scope、findings を AND 判定します。成功時だけ workflow step が commit・push します。拒否時または前段失敗時は Phase A 相当へ degrade します。関連する運用記録と計画状態を更新します。

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Reviewer
  participant PRMonitor
  participant FindingsAgent
  participant FixAgent
  participant FixPushGate
  participant GitHub
  Reviewer->>PRMonitor: CodeRabbit レビューを投稿
  PRMonitor->>GitHub: reviewer 権限と PR メタデータを取得
  PRMonitor->>FindingsAgent: CodeRabbit findings を提供
  FindingsAgent->>PRMonitor: docs allowlist を返却
  PRMonitor->>FixAgent: allowlist を提供
  FixAgent->>PRMonitor: docs の修正差分を返却
  PRMonitor->>FixPushGate: 4 軸の入力を渡す
  FixPushGate->>PRMonitor: push 可否を返却
  PRMonitor->>GitHub: 成功時に commit・push
Loading

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルはPhase Bの無人fix push追加とADR-067起票というプルリクエストの主要変更を明確に示しています。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/wp17-r2c-phase-b

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

🤖 PR Monitor 分析 (GitHub Actions バックストップ)

  • トリガー: issue_comment (created) / 実行 run
  • CI: rust (ubuntu-latest) / rust (windows-latest) ともに in_progress(未完了、失敗なし)
  • レビュー状況: CodeRabbit は「処理中」の定型コメントのみ("Currently processing new changes... please wait")。実質的な指摘・レビューはまだ 0 件。人間レビューも 0 件。インライン指摘も 0 件
  • Verdict: user_decision(CI 未完了・CodeRabbit レビュー未着のため、現時点では判断材料がなく人間/次セッションの追跡待ち)

Applicable Findings (Critical / High / Major)

該当なし(レビュー指摘 0 件)

Applicable Findings (Medium 以下)

該当なし

Filtered (not applicable)

該当なし

diff 概要(レビュー指摘が無いための軽量サマリー)

8 ファイル変更、+607/-8。中心は .github/workflows/pr-monitor.yml(+386/-1、ADR-067 に基づく Phase B 無人 fix push job の新規追加)。付随して autonomy-config.toml[autonomy] enabled = true への変更、新規 ADR-067(166 行)、ADR-052/068/069 への追記、CLAUDE.md の索引更新、docs/harness-improvement-plan.md のステータス更新。コード(.rs 等)の変更は無し — docs + workflow YAML + config のみ。

次のアクション

  • CI(rust ubuntu/windows)と CodeRabbit レビューの完了を待つ。特に autonomy-config.tomlenabled = true(Phase B の一段目のフラグ)と、新設 fix job の権限昇格 (contents: write) 部分は CodeRabbit 到着後に重点確認する価値が高い。
  • ADR-067 記載の「実走スモーク未実施」「repository ruleset 未設定」の残課題はレビューとは独立に人間のフォローアップが必要。

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
.github/workflows/pr-monitor.yml (1)

615-623: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

ゲート引数のパスも env 経由へ揃えてください。

${{ steps.diff.outputs.path }}${{ steps.findings_json.outputs.path }} を run スクリプト内で直接展開しています。値は同一 job の step が生成した $RUNNER_TEMP 配下の固定パスであり、現時点で攻撃者は制御できません。したがって実際の注入リスクはありません。

ただしこの workflow は他の step で env indirection に統一しています(Line 181-184 の方針)。zizmor も template-injection として検出します。同じ方針へ揃えると、静的解析のノイズが消え、将来 path の生成元が変わった場合の耐性も上がります。

♻️ 提案するリファクタ
         env:
           AUTONOMY_ENABLED: ${{ vars.AUTONOMY_ENABLED }}
           HEAD_REF: ${{ steps.pr.outputs.head_ref }}
+          DIFF_SUMMARY_FILE: ${{ steps.diff.outputs.path }}
+          FINDINGS_FILE: ${{ steps.findings_json.outputs.path }}
         run: |
           master-ref/target/release/cli-fix-push-gate \
             --branch "$HEAD_REF" \
             --config master-ref/autonomy-config.toml \
-            --diff-summary-file "${{ steps.diff.outputs.path }}" \
-            --findings-file "${{ steps.findings_json.outputs.path }}"
+            --diff-summary-file "$DIFF_SUMMARY_FILE" \
+            --findings-file "$FINDINGS_FILE"
🤖 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 @.github/workflows/pr-monitor.yml around lines 615 - 623, Update the gate
invocation in the workflow step using the existing env-indirection convention:
expose the diff output path and findings JSON output path through named
environment variables, then reference those variables in the run script instead
of directly interpolating the step outputs. Keep the current step output values
and CLI arguments unchanged.

Source: Linters/SAST tools

🤖 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 @.github/workflows/pr-monitor.yml:
- Around line 625-640: Update the “Push fix” step to use an id such as push and
continue-on-error: true so push conflicts do not fail the workflow; then extend
the “Report degrade to Phase A” condition and branching to inspect
steps.push.outcome and report a degrade when the push does not succeed.
- Around line 483-486: Update the gh api calls that populate
findings-input/comments.json and findings-input/reviews.json to use --paginate
and aggregate all paginated results into a single JSON array, while retaining
the coderabbitai[bot] user filter for each page; ensure the jq handling produces
valid combined JSON rather than separate page outputs.

In `@autonomy-config.toml`:
- Around line 42-50: Update the comments above enabled in autonomy-config.toml
to reflect that AUTONOMY_ENABLED is already configured and this flag makes Phase
B live when merged. Remove the statement that an additional admin-set variable
is required for activation, while retaining accurate emergency-stop guidance.

In `@docs/adr/adr-052-autonomy-execution-boundary-classes.md`:
- Line 99: 同一 ADR 内の将来の分類関数参照が、既に完了した gate.rs からの切り出しと矛盾している。参照セクションの
`src/cli-pr-monitor/src/stages/gate.rs` を `lib-docs-policy` および
`lib_docs_policy::is_docs_only_summary` を指す記述へ更新し、単一実装を再利用する方針に統一する。

In `@docs/adr/adr-067-phase-b-unattended-fix-push.md`:
- Around line 127-129: Update the fix job step-count references in
docs/adr/adr-067-phase-b-unattended-fix-push.md and
docs/harness-improvement-plan.md from 12 to 13, including the ADR’s statement
about the verified condition chain. Do not change the workflow or unrelated
documentation.

---

Nitpick comments:
In @.github/workflows/pr-monitor.yml:
- Around line 615-623: Update the gate invocation in the workflow step using the
existing env-indirection convention: expose the diff output path and findings
JSON output path through named environment variables, then reference those
variables in the run script instead of directly interpolating the step outputs.
Keep the current step output values and CLI arguments unchanged.
🪄 Autofix (Beta)

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: 9ff14990-df4a-4979-8eb7-71ebf306327a

📥 Commits

Reviewing files that changed from the base of the PR and between b655311 and 88184fd.

📒 Files selected for processing (8)
  • .github/workflows/pr-monitor.yml
  • CLAUDE.md
  • autonomy-config.toml
  • docs/adr/adr-052-autonomy-execution-boundary-classes.md
  • docs/adr/adr-067-phase-b-unattended-fix-push.md
  • docs/adr/adr-068-fix-step-authority-boundary.md
  • docs/adr/adr-069-pr-chain-declaration.md
  • docs/harness-improvement-plan.md

Comment thread .github/workflows/pr-monitor.yml Outdated
Comment on lines +483 to +486
gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}/comments" \
--jq '[.[] | select(.user.login == "coderabbitai[bot]")]' > findings-input/comments.json
gh api "repos/${{ github.repository }}/pulls/${PR_NUMBER}/reviews" \
--jq '[.[] | select(.user.login == "coderabbitai[bot]")]' > findings-input/reviews.json

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

gh api --paginate --slurp option availability GitHub CLI version

💡 Result:

The --paginate and --slurp options are available for the gh api command in the GitHub CLI [1][2][3]. The --paginate option fetches all pages of results by making additional HTTP requests until no further pages are returned [1][3]. When using --paginate with GraphQL, the query must include a pagination variable (typically $endCursor: String) and request the pageInfo{ hasNextPage, endCursor } fields [1][4]. The --slurp option must be used in conjunction with --paginate [5]. It wraps all pages of JSON arrays or objects into a single outer JSON array [1][6]. Important usage limitations include: 1. --slurp cannot be used simultaneously with --jq or --template [5][7]. Attempting to use them together will result in an error, as the CLI explicitly prevents this combination [5][7]. 2. --paginate is generally restricted to GET requests and cannot be used with the --input flag [5]. Because --slurp is not currently compatible with --jq, users often process the output of gh api --paginate --slurp by piping it to an external jq command [4][6].

Citations:


🌐 Web query:

github cli gh api jq paginate slurp examples

💡 Result:

The gh api command provides options to handle paginated API responses from GitHub. Key Concepts --paginate: Automatically requests all pages of results until no more are available [1][2]. For GraphQL queries, the query must include an $endCursor: String variable and fetch pageInfo { hasNextPage, endCursor } [1][3]. --slurp: Wraps all pages of JSON responses into a single, top-level JSON array [1][2]. This is useful when you need to process the combined output as a single valid JSON document [4][5]. Important Compatibility Note As of August 2026, the --slurp option cannot be used simultaneously with the --jq or --template flags within a single gh api command [6][5]. If you attempt to use them together, the command will return an error [5]. Recommended Workflow To process paginated results with jq, it is common to use the following two-step pattern: 1. Use --paginate with --jq to extract the desired nested array from each page [7]. 2. Pipe the output to the external jq tool with the --slurp (-s) flag to combine them into a single array [7]. Example: Extracting nested data from paginated results # This command extracts the nodes array from each paginated response # and then pipes the separate page results into jq to combine them into one list. gh api graphql -f query=' query($endCursor: String) { viewer { repositories(first: 100, after: $endCursor) { nodes { nameWithOwner } pageInfo { hasNextPage endCursor } } } } ' --paginate --jq '.data.viewer.repositories.nodes[]' | jq -s '.' In this example, the --jq flag ensures that only the list of nodes is emitted for each page, and jq -s (slurp) joins these lists into a single consolidated JSON array [7]. Alternative: Using --slurp with gh api If you do not need to use --jq or --template immediately, you can use --slurp directly to gather all raw response pages: gh api graphql --paginate --slurp -f query='...' This returns a single JSON array containing all page objects, which can then be processed in a separate piped jq command [1][3].

Citations:


🌐 Web query:

site:cli.github.com/manual/gh_api gh api --paginate --slurp jq

💡 Result:

The combination of --paginate, --slurp, and -q/--jq in the gh api command is used to fetch all pages of a paginated GitHub API response and process them as a single collection [1]. 1. --paginate: This flag instructs the GitHub CLI to automatically follow pagination links (or use GraphQL cursor-based pagination) until all results have been retrieved [1]. 2. --slurp: When used with --paginate, this flag collects all individual pages (which are returned as separate JSON objects or arrays) and wraps them into a single, top-level JSON array [1]. This allows tools like jq to process the entire dataset at once rather than one page at a time. 3. -q or --jq: This flag allows you to pass a jq filter to parse, transform, or select values from the resulting JSON [1]. Because --slurp has combined all pages into one array, your jq filter will operate on that entire collection, making it significantly easier to perform aggregations, counts, or global transformations across all paginated results [1]. Example usage: gh api graphql --paginate --slurp -f query='...' | jq '...' In this context, the --slurp option ensures the data piped into jq is a single array containing every object from every page, which is essential for complex jq operations like reducing or counting all items [1].

Citations:


🌐 Web query:

"gh api" "--slurp" "--jq" "cannot be used"

💡 Result:

In the GitHub CLI (gh), you cannot use the --slurp flag in combination with --jq or --template [1][2]. This restriction is enforced by hard-coded mutual exclusivity in the CLI's codebase [2][3], which prevents these flags from being used together due to complexities in how the tool manages pagination and output processing [3]. If you attempt to run a command such as gh api --paginate --slurp --jq..., the CLI will return an error stating that the --slurp option is not supported with --jq or --template [1][2]. Workaround: To achieve the desired result—processing paginated API responses as a single consolidated JSON array—you can use the following approach: 1. Use gh api with --paginate and a targeted --jq expression to output the specific data stream you are interested in (e.g., extracting an array of nodes from each page) [4]. 2. Pipe the output to the external jq tool and use its --slurp (-s) flag to consolidate those streams into a single JSON array [4]. Example: gh api graphql -f query='...' --paginate --jq '.data.items[]' | jq -s '.' This method isolates the relevant data from each paginated response on the client side before piping it to jq for final aggregation [5][4].

Citations:


CodeRabbit の指摘取得はすべてのページを取得してください。

gh api --jq のみでは既定の 1 ページ目(最大 30 件)だけを返します。CodeRabbit のインラインコメントまたはレビューが 30 件を超える PR では、Phase B の findings が取りこぼれます。gh api --paginate を追加し、複数ページ出力を 1 つの JSON 配列にまとめてください。--paginate--jq を使う場合、各ページごとに jq 指定が必要になるため、このスクリプトでは各ページごとの選択で対応する必要があります。

🤖 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 @.github/workflows/pr-monitor.yml around lines 483 - 486, Update the gh api
calls that populate findings-input/comments.json and findings-input/reviews.json
to use --paginate and aggregate all paginated results into a single JSON array,
while retaining the coderabbitai[bot] user filter for each page; ensure the jq
handling produces valid combined JSON rather than separate page outputs.

Comment on lines +625 to +640
- name: Push fix (workflow-authored, not agent-authored)
if: steps.applies.outputs.proceed == 'true' && steps.gate.outcome == 'success'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HEAD_REF: ${{ steps.pr.outputs.head_ref }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
run: |
set -euo pipefail
git -C pr config user.name "github-actions[bot]"
git -C pr config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git -C pr commit -m "docs: PR #${PR_NUMBER} のレビュー指摘に対する無人 fix (pr-monitor Phase B)"
# GITHUB_TOKEN による push は新たな workflow run を発火させない (GitHub の仕様)。
# これが Phase B → pr-monitor 再起動の無限ループを構造的に防いでいる。
git -C pr push \
"https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" \
"HEAD:refs/heads/${HEAD_REF}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

push 競合が run 失敗になります。degrade 設計と不整合です。

git push は非 force です。checkout から push までの間に PR 作者または他の自動化が同一 claude/ ブランチへ push すると、non-fast-forward で reject されます。この step は continue-on-error を持たないため job が失敗し、監視 run が赤くなります。

ADR-067 § 決定 6 は「上乗せが効かないことを CI 失敗として扱うと本物の失敗と区別できなくなる」としています。push 競合は Phase B の上乗せが効かなかったケースであり、本物の失敗ではありません。continue-on-error: true を付け、失敗時に degrade として報告する方が設計と整合します。

🐛 提案する修正
       - name: Push fix (workflow-authored, not agent-authored)
+        id: push
         if: steps.applies.outputs.proceed == 'true' && steps.gate.outcome == 'success'
+        continue-on-error: true
         env:

Report degrade to Phase A の条件と分岐に steps.push.outcome を追加してください。

🤖 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 @.github/workflows/pr-monitor.yml around lines 625 - 640, Update the “Push
fix” step to use an id such as push and continue-on-error: true so push
conflicts do not fail the workflow; then extend the “Report degrade to Phase A”
condition and branching to inspect steps.push.outcome and report a degrade when
the push does not succeed.

Comment thread autonomy-config.toml
Comment on lines +42 to +50
# WP-17 PR 2 で true へ倒した。呼び手 (pr-monitor.yml の Phase B fix job) が実装され、
# リポジトリとしては自律 fix push を許可する意思表示をした状態。
#
# ただし判定は本フラグと外部フラグの AND なので、**これだけでは Phase B は動かない**。
# GitHub Actions 側は Actions variable AUTONOMY_ENABLED = 'true' が別途必要で、それは
# admin (リポジトリ所有者) だけが設定できる。実際の有効化タイミングは admin が握る。
#
# 停止する場合: 恒久停止は本行を false へ、緊急停止は Actions variable を削除する。
enabled = true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

コメントの記述と Actions variable の実状が食い違います。

Line 46-47 は「Actions variable AUTONOMY_ENABLED = 'true' が別途必要で、実際の有効化タイミングは admin が握る」と書いています。しかし docs/harness-improvement-plan.md Line 128 は variable を 設定済み と記録し、Line 193 は「2c がマージされた瞬間に Phase B が live になる」と明記しています。

つまり本行を true にした時点で 2 拠点 AND は両方成立します。コメントは「これだけでは Phase B は動かない」と読めるため、マージ順序のリスクを過小に見せます。

🐛 提案する修正
-# ただし判定は本フラグと外部フラグの AND なので、**これだけでは Phase B は動かない**。
-# GitHub Actions 側は Actions variable AUTONOMY_ENABLED = 'true' が別途必要で、それは
-# admin (リポジトリ所有者) だけが設定できる。実際の有効化タイミングは admin が握る。
+# 判定は本フラグと外部フラグ (Actions variable AUTONOMY_ENABLED = 'true') の AND である。
+# **注意**: variable は 2026-08-02 に設定済み (docs/harness-improvement-plan.md § WP-17
+# PR 1 の引き渡し前提 4)。したがって本行を true にすると、本 PR のマージ時点で Phase B は
+# live になる。段階的に有効化する場合は、マージ前に variable を削除する。
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# WP-17 PR 2 で true へ倒した。呼び手 (pr-monitor.yml の Phase B fix job) が実装され、
# リポジトリとしては自律 fix push を許可する意思表示をした状態。
#
# ただし判定は本フラグと外部フラグの AND なので、**これだけでは Phase B は動かない**。
# GitHub Actions 側は Actions variable AUTONOMY_ENABLED = 'true' が別途必要で、それは
# admin (リポジトリ所有者) だけが設定できる。実際の有効化タイミングは admin が握る。
#
# 停止する場合: 恒久停止は本行を false へ、緊急停止は Actions variable を削除する。
enabled = true
# WP-17 PR 2 で true へ倒した。呼び手 (pr-monitor.yml の Phase B fix job) が実装され、
# リポジトリとしては自律 fix push を許可する意思表示をした状態。
#
# 判定は本フラグと外部フラグ (Actions variable AUTONOMY_ENABLED = 'true') の AND である。
# **注意**: variable は 2026-08-02 に設定済み (docs/harness-improvement-plan.md § WP-17
# PR 1 の引き渡し前提 4)。したがって本行を true にすると、本 PR のマージ時点で Phase B は
# live になる。段階的に有効化する場合は、マージ前に variable を削除する。
#
# 停止する場合: 恒久停止は本行を false へ、緊急停止は Actions variable を削除する。
enabled = true
🤖 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 `@autonomy-config.toml` around lines 42 - 50, Update the comments above enabled
in autonomy-config.toml to reflect that AUTONOMY_ENABLED is already configured
and this flag makes Phase B live when merged. Remove the statement that an
additional admin-set variable is required for activation, while retaining
accurate emergency-stop guidance.

- **理由**: 現状 PR 作成/マージの事前許可は 100% harness 層(`.claude/settings.json` の `permissions.ask`)で強制されており、**Rust 側に事前許可ゲートも自律実行経路も存在しない**(`cli-push-runner` / `cli-merge-pipeline` を調査し確認)。分類関数を今実装しても呼び手が無く dead code(YAGNI)になる。呼び手は自律実行経路(イベント駆動バックボーン Phase B、夜間ループ)が初めて生む。
- **将来の実装方針**(呼び手着手時):
- `cli-pr-monitor` の `src/cli-pr-monitor/src/stages/gate.rs` にある `is_docs_only_summary` / `is_docs_only_path`(ADR-035 の path 基準を実装済・fail-closed)を lib(`lib-jj-helpers` または新 `lib-diff-classify`)へ切り出して再利用する。現状は `pub(crate)` で cli-pr-monitor 内部限定。
- ~~`cli-pr-monitor` の `src/cli-pr-monitor/src/stages/gate.rs` にある `is_docs_only_summary` / `is_docs_only_path`(ADR-035 の path 基準を実装済・fail-closed)を lib(`lib-jj-helpers` または新 `lib-diff-classify`)へ切り出して再利用する。現状は `pub(crate)` で cli-pr-monitor 内部限定。~~ **(2026-08-02 訂正)** この切り出しは [ADR-057](adr-057-docs-only-deterministic-routing.md) の副産物として既に完了しており、`lib-docs-policy` が ADR-035 path 基準の単一実装になっている。呼び手は `lib_docs_policy::is_docs_only_summary` を呼ぶだけでよい

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

同一 ADR 内に stale な参照が残ります。

Line 99 は「切り出しは ADR-057 の副産物として完了済みで、lib-docs-policy が単一実装」と訂正しました。一方、§ 参照(Line 138)は src/cli-pr-monitor/src/stages/gate.rs を「将来の分類関数の再利用母体」と記載したままです。この 2 つは矛盾します。

学習事項に従い、docs/adr/ は設計の source of truth です。同 PR で Line 138 も lib-docs-policy へ更新してください。

♻️ 提案する修正(Line 138)
-- `src/cli-pr-monitor/src/stages/gate.rs`(`is_docs_only_summary` / `is_docs_only_path`)— 将来の分類関数の再利用母体
+- `src/lib-docs-policy`(`is_docs_only_summary` / `is_docs_only_path`)— ADR-035 path 基準の単一実装。分類関数の再利用母体([ADR-057](adr-057-docs-only-deterministic-routing.md) で `cli-pr-monitor` から切り出し済み)

学習事項に基づく指摘です: 「Use the architecture decisions documented in docs/adr/ as the source of truth」。

🤖 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-052-autonomy-execution-boundary-classes.md` at line 99, 同一 ADR
内の将来の分類関数参照が、既に完了した gate.rs からの切り出しと矛盾している。参照セクションの
`src/cli-pr-monitor/src/stages/gate.rs` を `lib-docs-policy` および
`lib_docs_policy::is_docs_only_summary` を指す記述へ更新し、単一実装を再利用する方針に統一する。

Source: Learnings

Comment on lines +127 to +129
### workflow (2026-08-02 時点で未実走)

YAML は js-yaml でパースし、job 構成 (`analyze` / `fix`)、`fix.if`、job 権限、12 step の条件チェーンを確認した。**実走スモークは未実施** — Actions variable の設定と `claude/` テストブランチの用意が要るため (§ 残課題)。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

fix job の step 数が記載と一致しません。

本節は「12 step の条件チェーンを確認した」と記録します。.github/workflows/pr-monitor.ymlfix job の step を数えると 13 件です。

  1. Resolve PR metadata
  2. Decide whether Phase B applies
  3. Checkout PR branch
  4. Checkout master
  5. Build fix push gate from master
  6. Fetch CodeRabbit review comments
  7. Collect findings
  8. Extract findings JSON
  9. Apply fixes
  10. Compute fix diff summary
  11. Gate fix push
  12. Push fix
  13. Report degrade to Phase A

docs/harness-improvement-plan.md Line 151 も「12 step」と書いています。ADR-068 § 観測(Line 91)は「docs の事実性には代理検査が無い」と記録しています。この種の数値はまさにその対象です。両方の記述を 13 へ更新してください。

#!/bin/bash
# fix job の step 数を機械的に数える。
fd -g 'pr-monitor.yml' .github | while read -r f; do
  python3 - "$f" <<'PY'
import sys, re
lines = open(sys.argv[1]).read().splitlines()
in_fix = False
count = 0
for line in lines:
    if re.match(r'^  fix:\s*$', line):
        in_fix = True
        continue
    if in_fix and re.match(r'^  [A-Za-z_-]+:', line):
        break
    if in_fix and re.match(r'^      - name:', line):
        count += 1
        print(line.strip())
print("fix job step count:", count)
PY
done
🤖 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-067-phase-b-unattended-fix-push.md` around lines 127 - 129,
Update the fix job step-count references in
docs/adr/adr-067-phase-b-unattended-fix-push.md and
docs/harness-improvement-plan.md from 12 to 13, including the ADR’s statement
about the verified condition chain. Do not change the workflow or unrelated
documentation.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

🤖 PR Monitor 分析 (GitHub Actions バックストップ)

  • トリガー: pull_request_review (submitted) / 実行 run
  • CI: rust (ubuntu-latest) pass (1m26s) / rust (windows-latest) pass (2m40s) / CodeRabbit review completed (pass)。analyze(本 workflow 自身)は実行中のため pending
  • レビュー状況: CodeRabbit が COMMENTED レビューを1件投稿(actionable 5件 + nitpick 1件)。人間レビューは0件。会話コメントには本 workflow の過去の分析コメント(issue_comment 起因、11:29:27 投稿、CI/レビュー未着時点のもの)が存在するが、その後に実質的な新規レビュー・新規インライン指摘が生じているため再分析
  • Verdict: needs_fix(Major 指摘が1件 applicable)

Applicable Findings (Critical / High / Major)

# File (Line) Reviewer Issue Recommended Action
1 .github/workflows/pr-monitor.yml (483-486) CodeRabbit (Major) gh api --jq は既定で1ページ目(最大30件)しか取得しない。CodeRabbit の指摘が30件を超えるPRでは Phase B の findings 収集が取りこぼれる --paginate を追加し複数ページを1つのJSON配列に集約する(各ページで author フィルタを維持)

Applicable Findings (Medium 以下)

# File (Line) Reviewer Issue Recommended Action
2 .github/workflows/pr-monitor.yml (625-640) CodeRabbit (Minor) Push fix step が非force pushで continue-on-error を持たず、push競合(non-fast-forward)が run 失敗として赤くなる。ADR-067 § 決定6の「上乗せ失敗と本物の失敗を区別する」方針と不整合 step に id: push + continue-on-error: true を付与し、Report degrade to Phase A の条件へ steps.push.outcome を組み込む
3 autonomy-config.toml (42-50) CodeRabbit (Minor) enabled = true 上のコメントが「Actions variable の追加設定が別途必要」と記述しているが、実態(AUTONOMY_ENABLED は既に設定済みでこのフラグがマージ後に Phase B を有効化する)と食い違う コメントを実態に合わせて修正しつつ、緊急停止手順の記述は維持する
4 .github/workflows/pr-monitor.yml (615-623) CodeRabbit (Trivial/nitpick) cli-fix-push-gate 呼び出しの --diff-summary-file/--findings-file 引数がstep output を直接展開しており、他箇所(L181-184)の env indirection 方針と不統一(現状の実害はなし、zizmorノイズ源) 該当2引数を env 経由に統一する

Filtered (not applicable)

# File (Line) Issue Filter Reason
5 docs/adr/adr-052-autonomy-execution-boundary-classes.md (99 / 138) Line 99 は ADR-057 経由の lib-docs-policy への切り出し完了を反映したが、Line 138 の参照先が旧 src/cli-pr-monitor/src/stages/gate.rs のままで矛盾 Scope mismatch: docs/adr/ は analyze-coderabbit.md Step 2 の読み取り専用ゾーン(指摘内容自体は妥当だが自動修正対象外)
6 docs/adr/adr-067-phase-b-unattended-fix-push.md (127-129) 「12 step の条件チェーンを確認した」との記述に対し、実際の fix job の step 数は13件 Scope mismatch: docs/adr/ は読み取り専用ゾーン(同上)

次のアクション

aloekun and others added 2 commits August 3, 2026 20:39
Resolved findings:
- [Major] .github/workflows/pr-monitor.yml:486 CodeRabbit の指摘取得はすべてのページを取得してください。
- [Minor] .github/workflows/pr-monitor.yml:640 push 競合が run 失敗になります。degrade 設計と不整合です。
- [Minor] autonomy-config.toml:50 コメントの記述と Actions variable の実状が食い違います。
- [Minor] docs/adr/adr-052-autonomy-execution-boundary-classes.md:99 同一 ADR 内に stale な参照が残ります。
- [Minor] docs/adr/adr-067-phase-b-unattended-fix-push.md:129 fix job の step 数が記載と一致しません。
直前の takt fix コミット (findings 1-2 = pagination / push 競合の degrade 化) は検分の
うえ維持した (js-yaml で 13 step 構造・id: push・continue-on-error を実測確認済み)。
本コミットは takt がタイムアウトで未対応だった doc 系 3 件と、計画書の期待動作訂正を
まとめる。

## CodeRabbit finding 3: autonomy-config.toml のコメントと variable 実状の食い違い

コメントが「AUTONOMY_ENABLED が別途必要 (= 未設定)」と読める書き方で、実状 (設定済み、
かつマージ手順で削除→再設定される) と食い違っていた。**コメントに variable の設定状態を
書かない**形へ変更 — 外部 SaaS 側の実状と config 内の記述が食い違う drift は ADR-051 の
クロスシステム coupling がまさに避けるべきとした形。現在値の正は GitHub UI 側にあると
明記した。

## CodeRabbit finding 4: ADR-052 の stale 参照の残り

実装スコープ節 (L99) は 2c で訂正済みだったが、関連リンク節 (L138) に同じ stale 参照
(`gate.rs` の分類関数が「将来の再利用母体」) が残っていた。lib-docs-policy (ADR-057 で
切り出し済み) を指すよう訂正し、L99 の訂正記録への参照を付けた。

## CodeRabbit finding 5: ADR-067 の step 数不一致

検証記録の「12 step」は起票時点の値で、pre-push レビュー 5 ラウンドの対応で
`Fetch CodeRabbit review comments` step が増え現在は 13。数を直すだけでなく増えた経緯を
併記した (検証は追加後の構成で再実行済み)。

## 計画書 § 2c 段 0.5 の期待動作訂正 (自己申告)

段 0.5 の記述「fix job は config 層で停止するのが期待動作」は**非 claude 対象では誤り**。
fix job の全 step は proceed ゲートされており、非 `claude/*` PR を対象にすると config 層
より手前の prefix 層 (applies step) で停止する。master-ref 調達・config 層 deny に到達
するには `claude/*` PR + docs 指摘が必要 (= 段 2 の構成)。誤った期待を持ってスモークを
実行すると「config deny が出ない = 壊れている?」と誤読するため、観測範囲を層単位で
明記し直した。段 1 の括弧書き (「config が有効化されて初めて prefix 層まで到達する」) も
同じ誤り (prefix 層は config より手前) のため訂正。段 2 へ coderabbitai[bot] permission
解決の観測項目 ([PHASE_B_ACTOR] marker) を追加した。

検証: pnpm lint:docs / lint:md 0 error、cargo test (config 消費 crate) 27 件 pass、
js-yaml パース 13 step 緑。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@aloekun
aloekun merged commit d12462d into master Aug 3, 2026
5 checks passed
@aloekun
aloekun deleted the feat/wp17-r2c-phase-b branch August 3, 2026 12:59
aloekun added a commit that referenced this pull request Aug 4, 2026
…067) (#356)

スモーク段 2 の実走 (2026-08-04) で `Fetch CodeRabbit review comments` step が exit 1 で
失敗し、Phase B の allow 経路がそこで停止した。

## 原因

`gh api` は **`--slurp` と `--jq` の併用を拒否する**:

    the `--slurp` option is not supported with `--jq` or `--template`

この組み合わせは #352 の CodeRabbit 指摘 (ページネーション未対応で 30 件超の指摘が黙って
欠落する) への修正として takt fix が入れたもの。pre-push review (simplicity / security)、
CodeRabbit、js-yaml による構文検証のいずれも通過していた — **gh の CLI フラグ間の排他制約は
静的検査では検出できず、実走で初めて露見した**。

## 修正

フィルタを gh の `--jq` から**外部 `jq`** へ移す:

    gh api "..." --paginate --slurp | jq '[.[][] | select(...)]' > findings-input/xxx.json

`--slurp` を外して `--paginate --jq` にする案は採らない — その場合 `--jq` がページ単位に
適用され、出力が複数 JSON 配列の連結になって単一配列としてパースできず、#352 が直した
ページネーション欠落を別の形で再導入する。`jq` は runner 標準搭載で、本 workflow 内でも
既に 14 箇所で使用している。

なぜこの組み合わせが不可なのかを doc comment に出典 (実走日) 付きで明記した。同種の再発を
防ぐため他の `gh api` 呼び出しも監査し、L198 の permission 解決が `--jq` 単独で `--slurp` を
使っていないことを確認済み。

## 検証

- js-yaml パースで 13 step 構造と claude_args 全行のフラグ形式を確認
- **実走検証はスモーク段 2 (PR #355) の再実行が兼ねる** — 本修正が master に入って初めて
  `workflow_dispatch` (ref = master) で検証できるため、マージが検証の前提になる

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
aloekun added a commit that referenced this pull request Aug 4, 2026
スモーク段 2 の 2 回目の実走 (2026-08-04) で `Extract findings JSON` step が exit 1 で失敗し、
Phase B が findings 取得直後で停止した。

## 原因: 出力形式の保証を指示層だけに委ねていた

findings agent は仕込んだ docs 指摘 3 件を**過不足なく検出**していたが、出力を ```json で
囲んで返した:

    jq: parse error: Invalid numeric literal at line 2, column 0
    [FIX_PUSH_DENY] findings agent の出力が JSON 配列ではありません
    ```json
    [
      {"file": "docs/phase-b-smoke-test.md", ...},
      ...
    ]
    ```

prompt は「前置き・後書き・**コードフェンスを一切含まない** JSON 配列のみ」と明示していたが、
agent はこれに従わなかった。**指示層だけで出力形式を保証する設計では、モデルの気まぐれで
経路全体が止まる** (ADR-042: ルールでなく仕組みで守る)。

## 修正: 決定論層でフェンス行を落とす

`Extract findings JSON` で jq に渡す前に sed でフェンス行のみを除去する:

    sed -e 's/^[[:space:]]*```[[:alnum:]]*[[:space:]]*$//' "$RAW_FILE" > "$FINDINGS_FILE"

設計上の線引き:

- **フェンスを剥がす以上のことはしない**。中身の修復 (引用符の補完、部分抽出等) は試みない。
  agent が全く違う形式を返した場合は従来どおり落とすべきで、ヒューリスティックな救済は
  「壊れた入力をそれらしく通す」経路を作る
- **fail-closed は維持**。剥がした後も配列でなければ下の guard が exit 1 で止める
- 診断出力を `$RAW_FILE` (剥がす前) に変更。フェンス以外が原因で落ちた場合に、agent が実際に
  何を返したかがログに残る

prompt 側も二層目の防御として残し、「フェンスがあると後続がパースに失敗する」という理由と
実際に発生した日付を明記した (指示は保険であり主たる担保ではない旨も併記)。

## 検証

- **実際に落ちた入力でロジックを実測**: ```json で囲まれた配列 → 除去後にパース成功
  (isArray: true、要素 2 件)。フェンスなしの素の配列 → 副作用なくパース成功
- js-yaml パースで 13 step 構造と claude_args 全行のフラグ形式を確認
- 実走検証はスモーク段 2 (PR #355) の 3 回目の dispatch が兼ねる

## 併せて観測できたこと (段 2 の中間成果)

- findings agent が仕込んだ不整合 3 点を正確に検出 = 観測装置の設計は妥当
- 決定論的著者フィルタ (#352) と gh api 修正 (#356) が実走で正常動作
- degrade 分岐 (#353 で修正) が `GATE_OUTCOME: skipped` を正しく判別し、
  「gate step に到達しませんでした」を出力 = fail-closed と診断が設計どおり機能

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant