fix-pr-review について
fix-pr-reviewは、GitHub URLまたはローカルファイルのPRレビュー指摘を選別し、対応するスキルです。指摘を分類して検証済みの修正を適用し、差分を確認したうえでGitHubのスレッドへの返信と解決も行えます。
主な機能
- 01GitHubのレビュー情報取得またはローカルファイル読込
- 02トリアージ基準による指摘の分類
- 03修正の適用と対象を絞った型チェック
- 04/doneによる修正差分の検証
- 05GitHubスレッドへの返信と解決
活用シーン
- 01CodeRabbitや人間によるPRフィードバックへの対応
- 02レビュー出力から選んだ修正の適用
- 03修正後のGitHubレビュー議論の解決
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bhagyamudgal/ skills --skill fix-pr-reviewインストール後、Claude Code で/fix-pr-reviewを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/branch-safety.mdfetch-review-data.mdfinal-report.mdgithub-reply-resolve.mdneeds-input-triage.mdper-fix-loop.mdtriage-prompt.mdtriage-rubric.md詳細
/fix-pr-review:PR レビューコメントのトリアージ、修正、解決
CodeRabbit、/review-pr、または貼り付けられたテキストから PR レビューを受け取ります。各指摘をトリアージし、検証済みの修正を適用して、/done を実行した後、1 つのワークフローで GitHub の会話に返信し、解決します。
実行にユーザーの判断がまだ必要な場合に限り、AskUserQuestion を使用します:ブランチの安全性、stash の確認、意見が分かれた項目の確認、--interactive による修正ごとの確認、型チェック失敗のトリアージ、完了後の次のアクションです。/fix-pr-review の実行、またはレビュー指摘の修正を明示的に依頼することは、検証済み FIX プランの実行を許可します。プランの承認を別途求めないでください。必須の選択肢はすべて具体的な内容にし、検討したうえで、最も推奨するものを先頭に「(推奨)」を付けて示します。
クイックリファレンス
フェーズ概要
| フェーズ | 内容 | 主な出力 |
|---|---|---|
| 1 | 前提条件、入力の検出、ブランチの安全性、ベースラインの型チェック | BASE_SHA、repo_map、baseline_errors |
| 2 | GitHub またはローカルファイルからレビュー情報を取得 | 統合された Comment[] 配列 |
| 3 | トリアージサブエージェント:R-rubric に基づいて各指摘を分類 | トリアージプラン(FIX/DISMISS/DEFER/DISAGREE/NEEDS-INPUT) |
| 4 | プラン実行ゲート:検証し、呼び出し時の意図を尊重 | 実行可能なプラン |
| 5 | 修正を実行:順次編集+ファイル単位の限定的な型チェック | 変更ファイル、項目ごとの fix_status |
| 5.5 | 収束サブエージェント:クラスの完全性、逆リスク、新たな同種箇所 | 修正ごとの判定。不足箇所への適用 |
| 6 | 修正差分に限定した /done の受け入れ検証。コミットや公開への引き継ぎなし | 検証済み修正差分、done_verified_snapshot |
| 7 | GitHub で返信+解決(ローカルファイルの場合はスキップ) | スレッドを解決済みに |
| 8 | 最終処理:NEEDS-INPUT の確定、stash の復元、報告、抑制設定の書き込み、次のアクション | 最終レポート |
R-Rubric の概要(フェーズ 3 STEP 4。最初に一致したルールを適用)
| ルール | 分類 | 必要な項目 |
|---|---|---|
| R1 | DISMISS:自己矛盾している/誤り | 追加フィールドなし |
| R2 | DISMISS:実在しないファイルまたは行を指摘 | デッドリンクの再アンカーに失敗 |
| R4 | DISMISS:すでに修正済み | prior_commit_sha |
| R5 | DISMISS:CLAUDE.md と矛盾 | claude_md_quote |
| R3 | DISMISS:純粋なスタイル/命名 | 再利用性のフラグが付いていない |
| R10 | NEEDS-INPUT:修正によってベースブランチで観測可能な動作が変わる | R10 の形式での why_unclear |
| R6 | FIX:バグ/セキュリティ/パフォーマンス/正確性/再利用性 | 30 文字以上の fix_plan、change_class、test_scenario、inverse_risk、class_completeness(verdict を含む) |
| R7 | DEFER:妥当だがスコープ外 | 追跡用の参照 |
| R8 | DISAGREE:正当な技術的見解の相違 | disagree_rationale |
| R9 | NEEDS-INPUT:曖昧/ユーザーの知識が必要 | why_unclear |
R4/R5 が R3 より上位にあるのは意図的であり、偶然ではありません。また、R10 は R6 より上位にあるため、技術的に正しいという理由だけで指摘が修正ループに進むことはありません。ルーブリック全文とこの順序の理由は references/triage-rubric.md にあります。
主な相互参照
- R-rubric の定義:
references/triage-rubric.md。フェーズ 3 STEP 4 でトリアージサブエージェントが読み込みます。メインエージェントは読み込みません - プラン検証ルール:フェーズ 4(R-rubric で必須となるフィールドを検証)
- 修正実行の振り分け:フェーズ 5(R6 FIX 項目を実行)
- 収束:フェーズ 5.5(プランの
class_completenessとinverse_riskを使用し、fix_statusと修正ごとのconvergence:レポート行に反映) - 返信バリデーター:
references/github-reply-resolve.mdの Step 7b(GitHub 返信の形式ルール) - レポートのグループ化:フェーズ 8(R 分類ごとにグループ化)
- 抑制設定:フェーズ 3「レビュー抑制設定の読み込み」(メインエージェントがサブエージェントの起動前に読み込み)+
references/triage-prompt.md(サブエージェントが分類前に適用)+フェーズ 8(書き込み)
参照ファイル
各ファイルの読み込み条件は、使用箇所のポインターに記載されています。事前に読み込まず、その箇所で読み込んでください。
references/fetch-review-data.md:入力タイプごとの GraphQL/REST フェッチ、CodeRabbit のレビュー本文の構造、Commentスキーマ。メイン処理がフェーズ 2 の GitHub フェッチ手順で読み込みます。また、ローカルファイルの経路で未読の場合は、Commentスキーマの正規化手順でも読み込みます。references/triage-prompt.md:フェーズ 3 のサブエージェント用プロンプト全体(STEP 0 → STEP 6 +出力形式)。メイン処理がフェーズ 3 で読み込み、プレースホルダーを置き換えて、そのまま渡します。references/triage-rubric.md:R1~R10 の詳細、NEEDS-INPUT の判定基準、change_classの使用例、返信形式。トリアージのサブエージェントが STEP 4 で読み込みます。references/github-reply-resolve.md:投稿/解決の手順 7a~7d。メイン処理がフェーズ 7 で読み込みます。ローカルファイル入力では読み込みません。references/final-report.md:フェーズ 8 のレポートテンプレートと表示ルール。メイン処理がフェーズ 8 で出力前に読み込みます。references/branch-safety.md:リポジトリとブランチへの移動、および detached HEAD と異なるブランチに関する質問。メイン処理が GitHub 入力の場合にフェーズ 1 で読み込みます。ローカルファイルの場合はスキップします。references/per-fix-loop.md:修正ごとのループ、対話形式の確認、限定的な型チェックとベースライン比較、再試行/スキップ/中止。メイン処理がフェーズ 5 のループで読み込みます。references/needs-input-triage.md:NEEDS-INPUT の確定、項目ごとのトリアージ、フェーズ 8 の修正と検証、GitHub への返信前の事前確認。件数が 0 でない場合に限り、メイン処理がフェーズ 8 の手順 1 で読み込みます。
参照ファイルのうち、ここに同梱されていないものが 1 つあります。${CLAUDE_SKILL_DIR}/../review-pr/references/repo-map.md には repo_map_files/repo_map_exports のシェルがあり、このスキルと /review-pr で共有している唯一のコピーです。メイン処理が packages/ または apps/ が存在する場合にフェーズ 1 で読み込みます。
使用方法
/fix-pr-review https://github.com/owner/repo/pull/123
/fix-pr-review https://github.com/owner/repo/pull/123#pullrequestreview-4089716169
/fix-pr-review https://github.com/owner/repo/pull/123#discussion_r3064352825
/fix-pr-review ./review.md # local output from /review-pr
/fix-pr-review /tmp/review-pr-123-findings.md # local review export
/fix-pr-review # no arg → ask user to paste
オプションのフラグ:
--dry-run:計画を表示した後に停止し、実行しません--interactive:各 FIX 項目を適用する前に確認します--all-nitpicks:デフォルトの却下ではなく、Nitpick をすべてトリアージします
トリアージの対象
CodeRabbit、人間、その他のボットを問わず、すべてのレビュアーのコメントを同じ方法でトリアージします。ここで「CodeRabbit」を中心に説明しているのは、最も一般的なユースケースを反映したものです。
フェーズ 1:前提条件+入力の検出+ブランチの安全性(メイン処理)
前提条件の確認
command -v gh >/dev/null 2>&1 || { echo "Install gh CLI: https://cli.github.com"; exit 1; }
git rev-parse --is-inside-work-tree >/dev/null 2>&1 || { echo "Not inside a git repo. cd into your clone first."; exit 1; }
gh auth status 2>&1 | grep -q "Logged in" || { echo "Run 'gh auth login' first"; exit 1; }
引数から入力タイプを検出する
#pullrequestreview-<id>を含む → レビュー URL#discussion_r<id>を含む → ディスカッション URL(単一のコメント+スレッド)./で始まる//で始まる/.mdで終わる → ローカルファイル- フラグメントを含まず、
https://github.com/<owner>/<repo>/pull/<num>に一致する → PR URL - 空 → 内容を貼り付けるか、URL を指定するようユーザーに依頼
実行許可を記録する
元のリクエストで /fix-pr-review を明示的に呼び出している場合、またはレビューの指摘を修正、対処、適用、処理、解決するよう命令形で依頼している場合は、EXECUTION_AUTHORIZED=true に設定します。URL だけの場合、または確認、説明、レビュー、トリアージのみを求める読み取り専用のリクエストの場合は、false に設定します。一致するリクエスト文を execution_authorization_evidence として保持します。フェーズ 4 では明示的な実行の選択によってこの値を置き換えることができ、フェーズ 7 では最終的な証拠を preflight-mutations に渡します。
正しいリポジトリとブランチを確保する(GitHub 入力のみ)
URL から owner、repo、number を解析し、${CLAUDE_SKILL_DIR}/references/branch-safety.md に従って PR のブランチに移動します。今すぐ読み込んでください。作業ツリーがマージ、リベース、またはチェリーピックの途中にある場合は停止し、何かに触れる前に競合の解決を resolving-merge-conflicts に引き継ぎます。
未コミットの作業を自動でスタッシュする(ブランチの安全性)
このステップは、GitHub とローカルファイルのどちらの入力タイプでも実行されます。修正がスタッシュされていない作業中の変更に重ねられることはありません。
git status --porcelain
空でない場合は、AskUserQuestion を使用します。
質問: header: "スタッシュ" text: "未コミットの変更が検出されました。修正を適用する前に自動でスタッシュしますか?内容は最後に復元されます。" options: - label: "自動でスタッシュ" description: "今すぐ変更をスタッシュします。実行完了時に復元されます" - label: "中止" description: "停止します。まず自分で作業をコミットまたはスタッシュします"
「自動でスタッシュ」を選択した場合は、git stash push -u -m "fix-pr-review auto-stash $(date +%s)" を実行します。成功した場合に限り、STASH_OID=$(git rev-parse -q --verify refs/stash) を記録して STASH_PUSHED=true に設定し、その後 git status --porcelain が空であることを確認します。プッシュに失敗した場合は何も記録せず、作成されていないスタッシュを作成済みとして扱うのではなく、実行を中止します。実行が中止された場合、作業は git stash list で fix-pr-review auto-stash <timestamp> として確認できます。
「中止」を選択した場合は、「未コミットの作業を先にコミットまたはスタッシュしてください。」と出力して終了します。
スタッシュ復元ガード。 この実行中のすべての復元処理(ここ、およびすべての早期終了時)は、STASH_PUSHED=true の場合に限り実行します。記録された OID を適用するのは、スタックの先頭がその OID と一致する場合のみです(git stash apply "$STASH_OID" を使い、単独の pop は決して使いません)。適用が正常に完了し、スタックの先頭も引き続き一致する場合に限り、スタッシュを削除します。不一致があれば、すべてのエントリに手を加えず、stash_restored: foreign-top を記録して stash_restored: foreign-top, stash left untouched と出力し、適用も削除もせずに続行します。
マージベースを計算する(後で修正済みかどうかを検出するため)
BASE_SHA=$(git merge-base "origin/$(gh pr view <url> --json baseRefName -q .baseRefName)" HEAD)
Phase 3 の修正済みチェックで使うため、BASE_SHA として保存します。
修正前の型チェックのベースライン(絞り込み型チェックの比較対象)
Phase 5 の前にベースラインの型チェックを 1 回実行し、すでに失敗しているファイルの集合を取得します。
bun turbo run check-types 2>&1 | tee /tmp/fix-pr-review-baseline-$$.log
実行全体で使うパーサーを 1 つ定義します。各診断について、そのファイルをキーとして、ファイル位置、行、列の情報を取り除いた後の <診断コード> + <正規化されたメッセージ> を識別子とします。同一の識別子はマルチセットとして保持します。このパーサーで Phase 1 の出力を解析し、baseline_errors[path] に格納します。Phase 5 と Phase 8 のすべてのベースラインパスでは、同じパーサーと識別子の正規化を使用します。型チェックのツールが見つからない場合(turbo も tsc もない場合)は、ベースラインをスキップし、すべての修正について絞り込み型チェックを skipped として記録します。
共有パッケージのリポジトリマップを計算する(再利用を考慮した分類のため)
共有パッケージとアプリを調査し、Phase 3 の分類処理が、再利用や切り出しに関するコメントを既存の構成と照合できるようにします。packages/ と apps/ の両方をスキャンします。たとえば、apps/backend/src/modules/v1/feature-a/helpers.ts と feature-b/helpers.ts のような、アプリ内でのヘルパーの重複は、NestJS スタイルのモノレポではよくあり、packages/ のみのスキャンでは検出できません。
${CLAUDE_SKILL_DIR}/../review-pr/references/repo-map.md を読み込み、/review-pr と共有されているこのシェルの 1 つだけである Local mode ブロックを実行します。これは、グロブが zsh でも正しく機能するように bash -c でラップし、それぞれの出力を最大 500 行に制限して、切り詰めたことを明示します。packages/ または apps/ が存在する場合はこれを読み込みます。どちらも存在しない場合は実行するものがないため、以下のフォールバックを使用します。
両方の出力を repo_map_files と repo_map_exports として Phase 3 のサブエージェントプロンプト用に保存します。packages/ と apps/ のどちらも存在しない場合(モノレポではない場合)は、両方を N/A (not a monorepo) に設定し、IS_MONOREPO=false とします。分類プロンプトはこれを使って、grep の対象を src/ とリポジトリのルートに切り替えます。
Phase 2: レビューデータを取得する(メイン)
/review-pr の指摘に対する二経路の入力
/review-pr は、各指摘を特定のコード行に対する個別のインラインコメントとして投稿するようになりました。これらは、CodeRabbit のスレッドと同じ標準の GitHub PullRequestReviewThread を作成します。以下の既存の GraphQL 取得処理で、特別な解析を一切行わずに処理できます。
手動でエクスポートしたファイルや、以前の形式の /review-pr の指摘ファイルには、既存のローカルファイル経路を使用します。Phase 7 では、これらの入力に対する GitHub 操作をスキップします。
GitHub から取得する場合(PR URL/レビュー URL/ディスカッション URL)
Phase 1 では、これら3種類の入力のうち、ちょうど1つを検出しました。${CLAUDE_SKILL_DIR}/references/fetch-review-data.md を今すぐ読み込み、該当する種類のセクションだけを実行します。このファイルには、ページネーションに対応した GraphQL の reviewThreads クエリとその isResolved フィルター、/pulls/<num>/reviews/<review_id> および /pulls/comments/<comment_id> の REST エンドポイント、CodeRabbit のレビュー本文の構成、そして、インラインスレッドが作成されないためニットピックが現れる唯一の場所である 🤖 Prompt for all review comments with AI agents ブロックの解析方法が記載されています。
取得に失敗した場合は、エラーを表示して終了するため、不完全なコメント一覧に対してトリアージが実行されることはありません。これにより、GraphQL のレート制限、404、プライベートリポジトリ、ページネーションループ内の各ページでの失敗に対応します。404 の場合は、Couldn't access PR. Check repo access and run 'gh auth refresh -s repo'. と表示します。
ローカルファイルの場合(./review.md、/tmp/review-pr-*-findings.md など)
/review-pr の出力形式を解析します。## Findings セクションから指摘を抽出し、該当する場合は Severity / File / Category / Issue / Why it matters / Suggested fix に加えて Rule-class / Enclosing-symbol / Inverse risk / Class-sites も保持します。/review-pr はこれらを指摘ごとに出力します。これらを削除すると、レビュー担当者がすでに行った作業をこのスキルで再度導出することになります。
再導出せず、値を初期値として使う:Inverse risk: がある場合は、STEP 5 の inverse_risk の初期値として使い、ゼロから新たな値を導出するのではなく、コードに照らして検証します(名前が示す失敗モードが実在し、現在も当てはまることを確認します)。Class-sites: <A>/<N> がある場合は、STEP 1.5 の class_completeness をその N 件のサイトで初期化し、自分で検索して件数を検証します。検索は、レビュー担当者が見落としたサイトを見つけるために再実行するものであり、一覧を作り直すためではありません。Rule-class と Enclosing-symbol は、クラス全体の調査における signature の初期値になります。初期値がコードを読んだ結果と矛盾する場合は、コードを優先します。その差異を該当フィールドに記録します。
重大度の対応付け:/review-pr では Critical | Serious | Moderate | Minor を使用し、CodeRabbit では Critical | Major | Minor | Refactor | Nitpick を使用します。どちらも有効です。どちらの形式も受け入れる内部の Comment スキーマに正規化します。トリアージの優先度は次のように対応付けます:Critical = 最高、Serious/Major = 高、Moderate = 中、Minor/Refactor = 低、Nitpick = デフォルトで却下。
内部の Comment リストに正規化する
すべての入力経路はここに到達します。Phase 3〜8 が読み取る正確なフィールド名を含む Comment スキーマは、references/fetch-review-data.md で定義されています。ローカルファイル経路を使用し、まだ読んでいない場合は、今すぐそのファイルを読み込みます。
早期終了するケース
- リストが空(すべてのスレッドが解決済み、またはローカルファイルに指摘がない):
Nothing to triage. No unresolved comments found.と表示 → ガードの条件に従って stash を復元 → 終了コード 0。 - ニットピックのみが残り、かつ
--all-nitpicksが設定されていない:Only nitpicks found (N). Pass --all-nitpicks to triage them, or ignore.と表示 → ガードの条件に従って stash を復元 → 終了コード 0。
Phase 3:トリアージ用サブエージェント(general-purpose)
レビュー抑制設定の読み込み(メインエージェント、ディスパッチ前)
サブエージェントをディスパッチする前に、作業ツリーではなくベースリビジョンの .claude/review-suppressions.yml を読み込みます。チェックアウト済みの PR が自身のトリアージを抑制してはなりません。GitHub からの入力では、ピン留めされたベース OID の時点で読み込みます。ローカルでは git show "$PINNED_BASE_OID:.claude/review-suppressions.yml" を実行し(オブジェクトがない場合は一度だけ origin をフェッチします)、クロスリポジトリモードでは gh api repos/<owner>/<repo>/contents/.claude/review-suppressions.yml?ref=$PINNED_BASE_OID を実行します。PR のないローカルファイル入力では、HEAD 自体がトリアージ対象の変更である場合があります。信頼できるベースは、他の候補すべてを含む唯一の候補マージベースとして解決します。各メインラインにつきベースを 1 つ収集し、ローカルのメインライン自体がトリアージ対象の変更である可能性があるため、ローカルの相当物よりリモートエイリアスを優先します。そのうえで、残りすべてを含むベースが 1 つだけの場合に限り、それを採用します。同順位、比較不能な候補の組み合わせ、または候補が空の場合は、抑制を無効にします。
BASES=$(for remote in origin/main origin/master origin/develop; do
bare=${remote#origin/}
if git rev-parse --verify -q "$remote" >/dev/null 2>&1; then ref=$remote
elif git rev-parse --verify -q "$bare" >/dev/null 2>&1; then ref=$bare
else continue
fi
git merge-base HEAD "$ref" 2>/dev/null || continue
done | sort -u)
RESULT=""
if [ -n "$BASES" ]; then RESULT=$(printf '%s\n' "$BASES" | while IFS= read -r b; do
[ -n "$b" ] || continue
BAD=$(printf '%s\n' "$BASES" | grep -vx "$b" | while IFS= read -r o; do
git merge-base --is-ancestor "$o" "$b" 2>/dev/null || printf 'bad\n'
done)
[ -z "$BAD" ] && printf 'WINNER %s\n' "$b"
done); fi
採用されたコミットのファイルを読み込み、読み込み元をログに記録します。入力が空でも成功する方法で採用数を数えてください。grep -c は 0 件の場合に終了コード 1 を返します。
WINNERS=$(printf '%s\n' "$RESULT" | grep -c WINNER || true)
WINNERS が 1 で、採用されたコミットが HEAD 自体ではない場合に限り、それを使用します。HEAD と同じ採用結果は、信頼できる古いベースがないことを意味します。それ以外の場合は SUPPRESSIONS = "" に設定します。ポリシーなしでトリアージするとノイズが増え、レビュー対象の変更を信頼すると検出結果が隠れてしまいます。候補セットが空の場合、採用結果の行は出力されません。ベースに該当ファイルがない場合は SUPPRESSIONS = "" に設定し、PR で追加されたファイルを無視したことをログに記録します。
読み込んだ抑制設定を ## Review suppressions セクションとしてサブエージェントのプロンプトに渡します(CLAUDE.md の内容、PR の差分、リポジトリマップと同じ方法です。メインエージェントが取得し、サブエージェントはコンテキストとして受け取ります)。
ディスパッチ
Read、Grep、Bash ツールを備えた general-purpose サブエージェントを1 つディスパッチします。トリアージ計画は、このサブエージェント単独で作成します。サブエージェントが完全に失敗した場合は実行を中止し、その旨を伝えます。インラインで分類すると、計画全体の基盤となるグラウンディングとクラススイープの工程が省略されます。
重要:Bash の許可リスト(git log/diff/blame/show/merge-base/rev-parse、grep、rg)はプロンプトレベルの指示です。Claude Code の Agent ツールは Bash のコマンドごとにサンドボックス化しません。サブエージェントが他のコマンドを実行しないことは信頼されていますが、機械的に禁止されているわけではありません。
プロンプトテンプレート
プロンプト全体は references/triage-prompt.md にあります。今すぐ読み込み、<...> プレースホルダー(<SKILL_DIR> = このスキルの絶対パス、および Phase 1 のコンテキスト値、git diff <BASE_SHA>...HEAD の出力、リポジトリマップ、SUPPRESSIONS、Phase 2 の Comment[] 配列)を置き換えて、結果を一字一句そのままサブエージェントに渡します。これはサブエージェントが実行する文字列であり、あなたが従う指示でも、要約やインラインで言い換える内容でもありません。
STEP 4 では、サブエージェント自身が references/triage-rubric.md を参照します。このファイルは読みません。R-Rubric の概要表がメインエージェント向けの情報です。返された内容は Phase 4 で検証します。各 FIX について、プロンプトは fix_plan、change_class、test_scenario、inverse_risk:、class_completeness: を出力します。reusability_context: は FIX だけでなく、すべての項目に含まれます。
Phase 4:計画実行ゲート(メイン)
R-rubric に照らして検証します。概要表は上記、詳細は references/triage-rubric.md にあります。分類ごとの必須フィールドは、同ファイルで定義されています。
計画の検証(表示前)
ユーザーに何かを表示する前に、分類器の出力を機械的に検証します。
rubric: R5の DISMISS には、空でないclaude_md_quoteが必須です。rubric: R4の DISMISS には、空でないprior_commit_shaが必須です。- すべての DISAGREE には、空でない
disagree_rationaleが必須です(また、純粋なスタイル上の好みであってはなりません。「prefer」「cleaner」「nicer」などの語があり、具体的な反論がない場合は確認してください)。 - すべての FIX には、30 文字以上の
fix_planが必須です。 - すべての FIX では、
change_classがhardeningまたはlogic-changeのいずれかと完全に一致している必要があります(分類器が適用した判断基準はreferences/triage-rubric.mdにあります。このチェックでは文字列の値のみを確認します)。 - すべての FIX には、空でない
test_scenarioが必須です。change_class: hardeningの場合、値はsmoke test, happy path unchangedと完全に一致している必要があります。change_class: logic-changeの場合、具体的な再現手順を1文で記述する必要があります(「動作を確認する」だけでは不十分です)。 - すべての FIX には、具体的な障害モードを示すか、
none, pure additionと完全に一致する、空でないinverse_riskが必須です。曖昧な表現は検証に失敗します。値が空の場合や、「could have issues」「minor risk」「some risk」「possible regression」のような形式、または単独の「none」は不可です。障害モードを示す場合は、何が、どこで壊れるのかを記述します。フェーズ 5.5 ではこのフィールドを使用するため、名前のないリスクは検証できません。 - すべての FIX には、空でない
verdictがあり、COMPLETEまたはINCOMPLETEのいずれかで始まるclass_completenessブロックが必須です。INCOMPLETEの場合、除外した箇所を示し、それぞれの理由を記載する必要があります。箇所ごとの理由がないINCOMPLETE判定は検証に失敗します。 rubric: R10の NEEDS-INPUT には、current:、proposed:、intent evidence:の3つの部分をすべて含み、それぞれが空でないwhy_unclearが必須です。形式はreferences/triage-rubric.mdに記載されています。証拠の値としてfound nothingは有効ですが、空欄は不可です。- すべての項目には、空でない
grounding_aとgrounding_bが必須です。 - すべての項目には、
{ flagged: false }だけの場合も含め、reusability_contextフィールドが必須です。NEEDS-INPUT を含むすべての分類が対象です。フェーズ 7 の返信バリデーターはこのフィールドに基づいて分岐するため、フィールドがないと、その返信の再利用性チェックが暗黙に無効になります。
検証に失敗した場合:不足しているフィールドを具体的に列挙して、分類器に再度処理を指示します。再試行は最大1回です。2回目も失敗した場合は、検証エラーを出力して中止します。
計画の表示
次のヘッダーを付けて計画を出力します。
# Fix Plan, PR #<num>: <title>
# <N> findings triaged: <F> fix, <D> dismiss, <E> defer, <G> disagree, <I> needs-input, <n> nitpicks
CLAUDE.md による DISMISS を目立つように強調する
rubric: R5 の DISMISS がある場合は、メインの計画の前に、独立した強調セクションを出力します。
## ⚠ Dismissed because they contradict CLAUDE.md: review and override if any are exceptions
[D<n>] <file:line>: <comment ask>
CLAUDE.md rule: "<verbatim quote>"
Reply will be: "<reply>"
If this rule has a legitimate exception in this case, select D<n>
in the contested-item confirmation to change it to FIX or NEEDS-INPUT.
異議のある項目の確認(multiSelect)
異議のある項目とは、コード変更を行わずに返信を投稿してスレッドを解決する項目です。つまり、すべての DISMISS、DEFER、DISAGREE が該当します。ここで分類を誤ると、レビュアーとのやり取りが気づかれないまま終了します。Phase 5/7 で実行する前に、トリアージを確認してください。
異議のある項目が 0 件の場合は、この手順をスキップしてください。該当する項目がある場合は、AskUserQuestion を使用します。
Question: header: "Triage" text: " 件の項目について、コード変更なしで返信し、スレッドを解決します。再分類する項目を選択してください。選択されなかった項目は、予定どおりに進めます。" options: [DISMISS/DEFER/DISAGREE の項目ごとに 1 つのオプション:「[] file:line: ()、<reason の先頭約 60 文字>」] multiSelect: true
異議のある項目がオプション数の上限を超える場合は、複数の multiSelect 質問に分割してください。誤りのコストが最も大きい DISMISS を最初にします。
選択された項目ごとに、AskUserQuestion で追加質問します。
Question: header: "Item " text: "file:line。現在の分類は です。理由:。再分類先は?" options: - label: "FIX (Recommended)" description: "実際の問題として扱い、修正計画とともに FIX リストに追加します" - label: "NEEDS-INPUT" description: "保留にして何も投稿せず、最終レポートに記載します" - label: "Keep as-is" description: "誤って選択されたため、元の分類を維持します"
「FIX」の場合は、この項目だけを対象として分類器を再実行し、FIX に必要なすべてのフィールドを生成します。fix_plan、change_class、test_scenario、inverse_risk、class_completeness(クラス全体の調査を含む。再分類された項目はまだ調査されていません)、および reusability_context(調査によって変更されない限り、異議のある項目独自の値を引き継ぎます)。その後、変更された項目についてプランの検証を再実行します。ここで一部のフィールドしか生成しないと、検証に失敗し、1 回限りの再試行が消費されます。「NEEDS-INPUT」の場合は、why_unclear: "user contested the <classification> classification" を設定して NEEDS-INPUT に移し、項目の reusability_context を変更せずに引き継ぎます。「Keep as-is」の場合は変更しません。「Other」の場合は、自由記述のテキストを再分類の指示として扱います。
この手順では何も投稿せず、スレッドも解決しません。GitHub に触れるのは引き続き Phase 7 だけであり、この確認を通過した項目のみを処理します。スレッドの解決はレビュアーとのやり取りに取り消せないノイズを生じさせます。この確認を経ていない DISMISS、DEFER、DISAGREE は、この手順を通過するまで未回答のまま開かれています。
実行
--dry-run の場合:プランを出力し、dry run, not executing を出力して、ガードの下で stash を復元し、0 で終了します。
EXECUTION_AUTHORIZED=true の場合は、直接 Phase 5 に進みます。この呼び出しによって、検証済みのすべての FIX 項目の実行がすでに許可されています。--interactive が設定されている場合は、Phase 5 で項目ごとに確認を求めます。これはプラン全体の確認を追加するものではありません。
それ以外の場合は、AskUserQuestion を使用します。
Question: header: "Execute" text: "リクエストでは編集が明示的に許可されていません。検証済みのプランを実行しますか? FIX 件、DISMISS 件、DEFER 件、DISAGREE 件、NEEDS-INPUT 件。" options: - label: "Execute plan (Recommended)" description: "すべての FIX 項目を依存関係の順序に従って適用します" - label: "Cancel" description: "作業ツリーを変更せず、stash があれば復元します"
「Execute plan」の場合は、EXECUTION_AUTHORIZED=true に設定し、選択内容を execution_authorization_evidence として記録して、Phase 5 に進みます。「Cancel」の場合は、stash がプッシュされていればガードの下で復元し、cancelled を出力して 0 で終了します。
Phase 5:修正を実行する(メイン、順次)
検証済みプランから R6 FIX 項目を実行します(R6 の基準は R-Rubric Summary table を、検証については Phase 4 を参照)。
依存関係の解決
dependencies: フィールドから、単純なトポロジカルソートで実行順を作成します。循環(A→B→A)がある場合は、Cyclic fix dependencies detected. Correct the dependency fields and rerun /fix-pr-review <original-input>. というエラーで中止します。ガードの下でスタッシュを復元します。ゼロ以外の終了コードで終了します。
編集前のスナップショット(復元メカニズム。Edit ツールには元に戻す機能がありません)
最初の編集の前に、Phase 5 の状態ソースをバインドします。
| コンテキスト | active_snapshot | active_baseline_errors | 中止範囲 |
|---|---|---|---|
| 通常の Phase 5 | perfix_snapshot[idx] | Phase 1 の baseline_errors | 現在の修正 |
Phase 8 の項目 <idx> | phase8_item_snapshot[idx] | phase8_item_baseline_errors[idx] | 現在の項目のみ |
通常の Phase 5 では、実行全体で最初に Edit がファイルに触れる前に、そのファイルの完全な内容または権威ある不在状態を、実行レベルの中止用スナップショットにキャッシュします。
preedit_snapshot[path] = <full file content from Read>
通常の各修正の直前に、宣言されたすべてのパスのその時点での内容または権威ある不在状態を perfix_snapshot[idx] に記録します。そこには、それまでに適用されたすべての修正が含まれ、Retry と Skip で active_snapshot として使用されます。その修正の最後の試行が成功した直後、かつ後続の編集が行われる前に、perfix_snapshot[idx] と宣言された現在のパスを比較して、追加と削除を含む正確なバイナリーセーフのフォワードパッチを導出します。そのパッチを perfix_forward_patch[idx] に固定し、現在の正確な内容または権威ある不在状態を perfix_postimage[idx] に固定して、そのパッチとポストイメージで perfix_owned_components[idx] を初期化します。集約された作業ツリーの差分から、後になって修正の所有範囲を導出してはいけません。preedit_snapshot は全件中止にのみ使用します。Phase 8 のコンテキストでは、active_snapshot に宣言されたすべてのパスがすでに含まれていなければならず、ネストされた分岐は通常のスナップショットのいずれからも読み書きしてはいけません。アクティブなスナップショットから復元する際は、記録された内容を書き戻し、権威ある不在として記録されたパスを削除します。実行レベルの preedit_snapshot の全エントリを復元するのは全件中止の場合に限られます。Phase 8 の項目では phase8_item_files[idx] のみを復元し、それ以前に適用された修正は保持します。
修正ごとのループ
トポロジカル順に、各 FIX 項目のループを ${CLAUDE_SKILL_DIR}/references/per-fix-loop.md に従って進めます。今すぐ読み込んでください。このファイルには、対話形式の確認、ベースラインとの比較を伴う限定的な型チェック、再試行、スキップ、中止の各分岐に加え、症状への場当たり的なパッチではなく、systematic-debugging に項目を渡して再試行の回数を費やさないようにするルールが記載されています。
修正実行の追跡
fix_status[idx] = ok | retried_ok | inconclusive | skipped | aborted | type_check_skipped
| reverted_inverse_risk | inverse_risk_applied | partial | restored_failed
landed_fix_statuses = {ok, retried_ok, inconclusive, type_check_skipped}
後続フェーズおよび最終レポートで参照する、適用済み修正の正とする一覧は landed_fix_statuses です。Phase 5.5 は、復元に成功した場合にのみ reverted_inverse_risk を書き込み、安全な削除が立証できない場合は inverse_risk_applied を書き込みます。どちらのステータスも partial も、適用済みではありません。restored_failed は、失敗後に Phase 8 がその項目のスナップショットを復元したことを意味し、常に適用済みではありません。
Phase 5.5: 収束(サブエージェント)
すべての修正を適用した後、/done パイプラインの前に実行します。すべての修正がクラス完全で、逆リスクがなく、新たな兄弟項目を生み出していない場合、実行は収束しています。それ以外の状態は、次のレビューラウンドで検出されます。
general-purpose サブエージェントを1つだけ実行します。渡すものは git diff HEAD に加え、各修正の class_completeness サイト一覧と inverse_risk 文字列です。inverse_risk_applied に対する Phase 8 の修復では、phase8_remediation_kind、以前の完全な所有コンポーネント台帳、各コンポーネントの削除または置換予定を示す証拠も渡します。必要な情報はほかに自分で取得します。ファイルを読み直してリポジトリを grep するため、サブエージェントとして実行します。メイン側で必要なのは判定結果だけです。
For each fix below, verify against the working tree, not against the fix plan's claims.
1. CLASS COMPLETENESS: every site the class sweep marked `affected` in
`class_completeness.sites` must actually be changed. A fix that landed on 3 of 4
sites is INCOMPLETE, not done.
(Sites the plan's `verdict` deliberately excluded are not counted as unfixed.)
2. INVERSE RISK: the named failure mode must NOT be present in the applied code.
3. NEW SIBLINGS: did the fix itself introduce a new instance of the pattern it fixes,
or a new branch (error state, empty state, early return) that its siblings have but
this one lacks?
Report per fix, nothing else:
fix: <idx>
class_complete: yes | no, <unfixed site if no>
inverse_risk_present: no | yes, <file:line + one sentence>
new_siblings: none | <file:line + one sentence>
Evidence rules differ per check. "I lack evidence" is not an answer for check 1:
- Check 1 is decided MECHANICALLY by `git diff HEAD`. Each affected site either
appears in the diff or it does not; there is no undecidable state. Report `no`
with the unfixed site whenever a site is absent from the diff.
- Checks 2 and 3 default to `no` / `none` unless you can cite a concrete file:line
in the applied code. Do not speculate, do not re-review the PR, do not report
style issues.
Phase 8 の removal では、チェック1を機械的な修復完全性チェックに置き換えます。以前の所有コンポーネントはすべて修復台帳にちょうど1回ずつ記載され、結果の内容から各コンポーネントが存在しないことを証明できなければなりません。元の影響箇所が git diff HEAD に残っていることは要求しないでください。また、その箇所を出現させるために、却下された修正を決して再適用しないでください。Phase 8 の replacement では、以前の所有コンポーネントがすべて削除されるか、記録された置換後のバイト列で置き換えられていることを要求します。どちらの分岐でも、コンポーネントの証拠が欠けていれば class_complete: no です。逆リスクのチェックでは、通常時のデフォルトではなく、完全なコンポーネント台帳全体を通じた肯定的な証拠を要求します。
対応方法:
class_complete: no→ 不足している箇所を今すぐ適用し、その後1回だけ再検証します。2回目もnoの場合は停止します。fix_status[idx] = partialとし、未修正の箇所を記録して Phase 8 に引き継ぎます。3回目は実行しないでください。狭義の型チェック再試行(最大2回)や自己修復ループ(最大2回)と同様、このループの上限は2回です。 Phase 8 の修復では、不足している削除または置換の証拠だけを修正します。元の影響箇所が diff にないことだけを理由に、その箇所へ元の修正を適用しないでください。- クラス完全性を補う修正や、新たな兄弟項目を解消する修正は、それが完成させる修正の一部として扱います。修正前の状態を取得してから、正確なパッチと修正後の状態を、その修正の
perfix_owned_components[idx]に順番どおり追記します。また、ほかのすべての先行修正について、後続編集の証拠としても登録します。 inverse_risk_present: yes→ 提案は誤りです。それでも適用すると、より深刻な不具合をリリースすることになります。Phase 8 の場合は、active_snapshotから、権威ある不存在の状態も含め、宣言されたすべてのパスを復元し、現在の項目だけを中止します。通常の状況では、preedit_snapshotは Abort-all 用としてのみ保持します。所有権の証明にはperfix_owned_components[idx]と後続編集の証拠だけを使用します。git diff HEADや別の集約 diff から所有権を再構成してはいけません。逆適用候補では、所有コンポーネントを逆順に取り除きます。凍結された証拠により、排他的で重複しない所有権が証明され、一時的な候補によってほかのすべての後続編集が保持される場合に限り、適用してください。宣言されたパスのいずれにも、ほかの後続修正や収束編集が触れておらず、現在の宣言済みパスがすべて最後の所有コンポーネントの修正後の状態と一致する場合に限り、perfix_snapshot[idx]全体を復元します。それ以外の場合は修正を適用したままにし、fix_status[idx] = inverse_risk_appliedと設定して、revert: not attempted, exclusive ownership unprovenを記録し、NEEDS-INPUT に回します。Phase 8 では、リスクのある修正が適用されたままであることを明記します。 通常の逆リスク/スナップショットによる復元では、fix_status[idx] = reverted_inverse_riskと設定して、NEEDS-INPUT に回します。Phase 8 のアクティブスナップショット復元では、状態保持型の復元ルールを使用し、フォールバックはreverted_inverse_riskとします。new_siblings→ 同じ修正の一部として扱い、今すぐ対応します。
各修正の結果を convergence[idx] として記録します。Phase 8 ではこれを出力し、実行全体について収束/未収束の判定を1つ示します。サブエージェントが失敗した場合は、3つのチェックをインラインで実行し、convergence checked inline と記録します。
フェーズ 6:/done による検証(メイン)
すべての修正を適用したら、保留中の修正差分(git diff HEAD)に対して /done を実行します。/done は 4 つのセクションからなる受け入れワークフローであり、固定された 3 コマンドの手順ではありません。§1 では実行をひも付けて受け入れレーンを選択し、§2 では各必須レーンをその境界で検証し、§3 では各リクエスト項目、レーン、証拠の側面に状態を割り当て、§4 では準備状況カードを作成します。元のリクエストを検証済み修正計画にひも付け、すべてのチェックの対象を PR 全体ではなく修正差分に限定します。
ここでは Code レーンが常に適用されます。/fix-ts-errors を実行してエラーを解消します(ファイル単位の限定チェックでは検出できないファイル間エラーを捕捉し、ワークスペース全体のチェックを少なくとも 1 回実行します)。修正差分に対して /parallel-review を実行して、その converge-reviews の結果を適用し、ブロック対象の追加コメントスキャンを含む /simplify を実行して、各修正を差分に照らして確認します。/done §1 に記載されているルールに従い、修正が実際に影響した他のレーン(UI、ドキュメント、グローバル設定またはスキル、外部メタデータまたはデータ、公開またはデプロイ)をすべて選択します。それ以外は除外理由を添えて not-applicable として記録します。
/done §4 の引き継ぎは行わないでください。このスキルが公開を担当します。フェーズ 6 では git-commit と file-pr は利用できず、コミットまたはプッシュを開始できるのは、フェーズ 8 の完了後プロンプトだけです。
自動修復ループ(反復を明示的に追跡)
self_heal_iter = 0
done_remaining = []
while self_heal_iter < 2:
findings = run_parallel_review(diff="git diff HEAD")
blockers = [f for f in findings if f.severity in ("Critical", "Serious")]
if not blockers:
break
# Dispatch fresh subagent per blocker with the finding + the diff
for f in blockers:
apply_subagent_corrective_edits(f)
run_fix_ts_errors()
self_heal_iter += 1
# After loop: record whatever blockers remain (if any)
done_remaining = blockers
2 回反復した後も done_remaining が空でない場合は、最終報告に記録してフェーズ 7 に進みます。残りの問題はフェーズ 8 でユーザーに提示し、ユーザーが判断します。
Moderate/Minor の指摘は、自動修復せずに done_remaining に記録します。コミット時にユーザーが判断します。
すべての必須レーンの検証が完了したら、git-commit の Verified content snapshot 契約で必要となる、修正内容そのものを done_verified_snapshot として具体化します。/done §4 のパスを限定したスナップショット手順(create_verified_snapshot)を使って作成します。隔離された GIT_INDEX_FILE に HEAD を読み込み、宣言されたパスのみを git hash-object -w でハッシュ化し、それぞれを git update-index --add --cacheinfo <mode>,<blob>,<path> でステージし、宣言された削除項目ごとに --force-remove を実行してから、git write-tree を実行します。ここでの宣言パスの集合は、取り込まれたすべての修正で宣言されたパスの和集合です。自動スタッシュされた WIP と、その他のダーティなパスは、その集合にもオブジェクトデータベースにも含めません。実行単位のスタッシュには手を加えずに、スナップショットのツリーと対象パスのマニフェストを記録します。フェーズ 8 の修正では、その項目の検証が正常に完了した後に限り、宣言されたパスのみをこのスナップショットで更新できます。ツリーの再構築では、ライブワークツリーを再取得せず、隔離されたインデックスに HEAD ではなく前のスナップショットを読み込み、同じ update-index --cacheinfo の仕組みを使って検証済みバイト列のみを適用します。有効な done_verified_snapshot が存在しない場合、Commit と Push は利用できません。
フェーズ 7:GitHub で返信して解決(メイン)
返信形式のルールは references/github-reply-resolve.md にあり、フェーズ 4 の検証で参照されます。このスキルは /review-pr のキャッシュ(~/.claude/skills/review-pr/cache/)を読み書きしません。スレッドの解決は GitHub 上で行われます。/review-pr の再レビューでは、GraphQL による過去のレビュータイムラインの取得を通じて、解決済みスレッドを取得します。
スレッドへの返信と解決が、このフェーズで行うすべての GitHub 操作です。レビュー自体の CHANGES_REQUESTED 状態は、CodeRabbit が設定したまま変更しません。ユーザーがプッシュすると、次回の自動再レビュー時に CodeRabbit 自身が状態を解除します。
has_github_surface[idx] = thread_id != null AND (can_reply OR can_resolve) と定義します。このサーフェスを持たない各項目には、入力元にかかわらず、対応する not-applicable 状態を初期設定します。./review.md またはその他のローカルファイルから入力した場合、すべての項目がこの条件を満たします。その場合は初期設定を行った後、このフェーズの残りをスキップします。フェーズ 8 では、最終報告に向けて引き続き項目ごとに決定的な状態が必要です。
投稿の仕組み
${CLAUDE_SKILL_DIR}/references/github-reply-resolve.md を今すぐ読み込んでください。ここには、Step 7a(実際の修正後の差分からすべての FIX 返信を再生成すること。Phase 3 の reply_placeholder は使用しないこと、および返信が一切禁止される fix_status の値)、Step 7b(機械的な返信バリデーター:禁止される接頭辞、40 文字の下限、必須パターン、および reusability_context によって適用されるルール)、Step 7c(addPullRequestReviewThreadReply と resolveReviewThread の GraphQL 呼び出し)、Step 7d(昇格された細かな指摘には閉じるスレッドがないこと)が記載されています。
項目ごとのステータス追跡
gh_status[idx] = {
reply_state: landed | verified-existing | confirmed-absent | reconcile-required | skipped | not-applicable,
reply_err: <error message if any>,
resolve_state: resolved | already-resolved | confirmed-open | reconcile-required | skipped | not-applicable,
resolve_err: <error message if any>
}
既存の最終レポートレンダラー向けに、reply_state ∈ {landed, verified-existing, not-applicable} から reply_ok=true を、resolve_state ∈ {resolved, already-resolved, not-applicable} から resolve_ok=true を導出してください。has_github_surface=false のすべての項目には not-applicable を使用し、それらの項目は GitHub の失敗および返信/解決セクションから除外してください。skipped は、has_github_surface=true で、適用対象となる GitHub の変更操作が試行されなかった場合に限り使用してください。verified-existing は権威ある既存の返信として、already-resolved は権威ある解決済みの変更なしとして表示してください。解決されていることだけでは、返信が行われた証拠にはなりません。バッチ内のすべての項目を最後まで処理してください。 失敗が確認された後、または reconcile-required の結果が出た後は、依存するアクションをスキップし、バッチカードを無効にしてください。未解決の対象を除外した新しい ready カードが preflight-mutations から返された場合に限り、独立した保留中の項目の処理を続行してください。すべての失敗は、最終レポートの冒頭にまとめて表示してください。
Phase 8:最終処理(メイン)
レポートは R 分類ごとにグループ化します(R-Rubric Summary の表を参照)。抑制事項を書き込みます(学習ループ)。
1. NEEDS-INPUT を処理する
このステップ全体を通じて、実行レベルの stash には手を加えないでください。現在のワークフロー状態から needs_input_items を作成します。対象は、依然として NEEDS-INPUT に分類されているすべての項目と、Phase 5 または 5.5 でそこに振り分けられたすべての項目です。レンダリング済みレポートからこの件数を算出しないでください。${CLAUDE_SKILL_DIR}/references/needs-input-triage.md に従って、すべての NEEDS-INPUT 項目をトリアージしてください。このファイルは、件数がゼロでない場合に限り読み込みます。保留中の項目がなくなるまで、このステップを終了しないでください。
2. WIP を復元する
すべての NEEDS-INPUT 項目の処理が完了した後に限り、STASH_PUSHED=true の場合は、次の処理を行います。
if [ "$(git rev-parse -q --verify refs/stash)" = "$STASH_OID" ]; then
if git stash apply "$STASH_OID"; then
[ "$(git rev-parse -q --verify refs/stash)" = "$STASH_OID" ] && git stash drop || echo "STASH_CHANGED_MID_RESTORE"
elif [ -n "$(git diff --name-only --diff-filter=U)" ]; then
echo "STASH_CONFLICT"
else
echo "STASH_APPLY_FAILED"
fi
else
echo "STASH_TOP_MISMATCH"
fi
STASH_TOP_MISMATCH の場合は、stash_restored: foreign-top を記録して最終レポートに進んでください。別の stash がこちらの stash より上にあるため、何も適用されず、何も削除されていません。STASH_CONFLICT の場合は、apply によって残された競合マーカーをすべてそのままにし、drop をスキップしてください。復旧元として、そのエントリーは stash に残ります。最終レポートには stash_restored: conflict を記録してください。ユーザーの WIP を解決するかどうかはユーザーが判断します。STASH_APPLY_FAILED の場合は、競合マーカーがないまま apply がエラーになっているため、ワークツリーの状態は不明です。stash_restored: failed を記録し、ワークツリーとすべてのエントリーに手を加えず、レポートに進んでください。drop が STASH_CHANGED_MID_RESTORE を報告した場合は、内容の適用は正常に完了していますが、その前にスタックが移動しています。stash_restored: foreign-top を記録し、記録されたエントリーはユーザーが手動で drop できるよう残したまま、レポートに進んでください。復元が conflict または failed の場合、編集、型チェック、収束チェック、Phase 6 チェック、コミット、push は実行してはいけません。依存関係上、次に実行可能なアクションとして提示するのは stash の復旧のみです。
3. 最終レポートを一度だけ出力する
最終分類、fix_status、convergence、needs_input_status、gh_status の状態に基づいて、すべての件数を再計算します。${CLAUDE_SKILL_DIR}/references/final-report.md を今読み込み、その内容どおりに一度だけ出力します。inverse_risk_applied は スキップ/正常に反映されていない項目 に含め、未収束として数え、リスクのある修正が適用されたままです と記載します。この項目の依存関係を満たすためのアクションは「リスクのある自分の管理対象コンポーネントを削除するか、置き換えを適用してから、Phase 5.5 と Phase 6 を再実行し、done_verified_snapshot を再構築する」です。reverted_inverse_risk に関する従来の安全な復元を行わないルールは、inverse_risk_applied として解釈します。復元済みのステータスは、常に修正が削除されたことを意味します。レポートの失敗優先の順序には、Phase 7 と Phase 8 のすべての GitHub 結果が含まれます。各 [F<n>] をどの修正サブセクションに記載するか、および Test: 行の出力方法は、レポートのレンダリングルールに従います。
4. 抑制ルールの保存を提案する(学習ループ)
最終レポートの後、現在の DISMISS と DISAGREE の項目をすべて集めます。1 件以上ある場合は、今後のレビューで自動的に却下されるよう、それらを抑制ルールとして保存するか尋ねます。
AskUserQuestion を使用します。
Question: header: "学習" text: "今後のレビューで自動的に却下されるよう、これらの却下/異議のパターンを .claude/review-suppressions.yml に保存しますか?" options: [DISMISS/DISAGREE の項目ごとに 1 つ。パターンと理由を表示] multiSelect: true
選択された項目ごとに、.claude/review-suppressions.yml に追記します。
- pattern: "<normalized pattern from finding: key phrase, not full text>"
category: "<finding category if available>"
file: "<finding's file path. Include only if the rationale is specific to one file, omit for generic patterns>"
reason: "<dismiss/disagree rationale from triage>"
added: <today's date YYYY-MM-DD>
ファイルが存在しない場合は、次の内容で作成します。
suppressions:
- pattern: ...
項目が選択されない場合、またはユーザーが「その他」を選んでスキップする場合は、何も書き込みません。
次の場合は、この手順全体をスキップします。
- DISMISS または DISAGREE の項目がない
- 入力が Git リポジトリ外のローカルファイルであり、抑制ルールを書き込むプロジェクトルートがない
stash_restored=conflict(競合がある作業ツリーは読み取り専用のままです)stash_restored=failed(作業ツリーの状態が不明です)
5. 完了後の次のアクション
最終レポートを出力し、該当する場合は抑制ルールの手順を完了した後、最終分類や needs_input_status に関係なく、現在の fix_status が inverse_risk_applied であるすべての項目から inverse_risk_blockers を算出します。stash_restored=conflict の場合はプロンプトを表示せず、「スタッシュの競合を解決する」を唯一の依存関係を満たす次のアクションとして報告します。Commit と Push は引き続き利用できません。stash_restored=foreign-top の場合はプロンプトを表示せず、「スタックを調整する:記録された自動スタッシュのエントリーがまだスタッシュされています」を唯一の依存関係を満たす次のアクションとして報告します。Commit と Push は引き続き利用できません。stash_restored=failed の場合はプロンプトを表示せず、「作業ツリーとスタッシュを手動で復旧する」を唯一の依存関係を満たす次のアクションとして報告します。Commit と Push は引き続き利用できません。それ以外の場合、inverse_risk_blockers が空でなければプロンプトを表示せず、Step 3 の削除/置き換えアクションを依存関係を満たす次のアクションとして報告します。done_verified_snapshot が存在する場合でも、Commit と Push は利用できません。すべての修正が中止されている場合(何も適用されていない場合)はプロンプトをスキップします。それ以外の場合は AskUserQuestion を使用します。
Question:
header: "次のアクション"
text: "修正の実行が完了しました。 件の修正を適用、 件をスキップ、 件が要確認です。次に何をしますか?"
options:
- label: "変更をコミット"
description: "提案されたコミットメッセージを使用してステージングし、コミットします"
- label: "リモートにプッシュ"
description: "コミットしてプッシュし、PR を更新します"
- label: "残りを再実行"
description: "スキップ/要確認の項目に対して /fix-pr-review を再実行します"
- label: "完了"
description: "終了します。残りは手動で対応します"
「変更をコミット」または「リモートにプッシュ」では、inverse_risk_blockers が空であり、stash_restored が conflict、foreign-top、failed のいずれでもなく、有効な done_verified_snapshot があることを必須とします。表示されたレポートをそのまま信頼せず、ブロッカーの集合を再計算します。集合が空でない場合は、アクションを停止します。スナップショットを指定して、検証済みコンテンツスナップショットの封印済みインデックスモードで git-commit を呼び出します。ライブのワークツリーをステージングまたは再ステージングしてはいけません。作成されたコミットのツリーがスナップショットのツリーと一致することを必須とします。通常どおり復元された WIP はワークツリーに残し、候補コミットの対象外とします。
「リモートにプッシュ」では、まずコミットし、その後、公開ブランチとプッシュ試行 SHA を固定する前に、コミットのツリーが引き続きスナップショットと一致することを必須とします。GitHub PR の入力の場合は、現在の PR の headRefName と headRepository.id および nameWithOwner を再読み込みし、これらの信頼できる値を固定します。Phase 1 で想定された PR ブランチとアクティブブランチが、固定したヘッド名と一致することを必須とし、<exact-ref> を refs/heads/<frozen-headRefName> に設定します。そのヘッドリポジトリの ID は意図する公開先であり、入力元/ベースリポジトリとは独立しています。ローカルファイルまたは現在の PR がないその他の入力の場合は、アクティブブランチを固定し、<exact-ref> を refs/heads/<active-branch> として導出します。アクティブなシンボリック参照が <exact-ref> と一致し、そのブランチ参照と HEAD が同じ SHA に解決される場合に限り、プッシュ試行 SHA を固定します。<preflighted-remote> を確定する前に、意図する公開先を解決します。GitHub PR の入力の場合は、設定済みのリモートを列挙し、それぞれの順序付き完全な fetch/push エンドポイントセットをすべて検証します。すべてのエンドポイントが PR のヘッド ID と一致するリモートが 1 つだけなら、自動選択します。一致するリモートが複数ある場合は、具体的な <remote>: <nameWithOwner> (<id>) の選択肢を使って直ちに AskUserQuestion を呼び出し、必要に応じてページ分割します。一致するリモートがない場合は、Configure a remote whose complete endpoint sets resolve to the current PR head repository, then choose Push to remote again. を表示して停止します。選択されたリモートを <preflighted-remote> とします。
ローカルファイルまたは現在の PR がないその他の入力の場合は、「リモートにプッシュ」の選択直後に AskUserQuestion を呼び出します。設定済みのすべてのリモートを調査し、順序付きの完全な fetch および push エンドポイントセットを出力せずに取得します。認証済みの gh repo view ... --json id,nameWithOwner を使って、各エンドポイントを個別に正規化して解決し、すべてのエンドポイントが同じリポジトリ ID と nameWithOwner に解決されるリモートだけを残します。残した各リモートは、具体的な選択肢 <remote>: <nameWithOwner> (<id>) として表示します。失敗したエンドポイントまたはセットの不一致とともに不適格なリモートを一覧表示しますが、選択肢にはしてはいけません。選択肢の上限にすべての有効なリモートが収まらない場合は、互いに重複しない具体的な選択肢のセットにページ分割し、ユーザーが選択するまで Show next remotes の選択肢を表示します。その選択によって両方の完全なセットを固定し、<preflighted-remote> と明示的な意図する公開先を設定して、事前確認の認可とガードに進みます。有効なリモートがない場合は、次の内容を表示して停止します:Configure a remote whose complete fetch and push endpoint sets resolve to one authenticated GitHub repository, then choose Push to remote again.
git remote get-url --all <preflighted-remote> と git remote get-url --push --all <preflighted-remote> から、順序を保った完全なセットを出力せずに取得し、各エンドポイントを認証情報を含まない URL の識別情報に正規化します。転送方式、ホスト、ポート、所有者/リポジトリは保持しつつ、scp 形式と ssh:// のような同等の表記、デフォルトポート、末尾のスラッシュ、.git サフィックスは同一として扱います。認証済みの gh repo view ... --json id,nameWithOwner を使って、正規化した各エンドポイントを個別に解決し、すべてのエンドポイントの ID と nameWithOwner が意図した公開先と一致することを必須とします。順序を保った正規化済みセットまたはそのダイジェストと解決済み ID のみを保持し、認証情報は決して保持しません。リモート名、両方の完全なエンドポイントセット、意図した公開先を記録します。追加、削除、順序変更、解決失敗、リポジトリ不一致があれば、reconcile-required とします。名前付きリモートへのプッシュで設定済みの完全なプッシュ先セットを対象にできるのは、その固定済みセットが引き続き一致する場合に限ります。
<exact-ref> を照会し、リモート SHA または権威ある不在情報を記録します。存在する場合は、固定済み SHA の祖先であることを必須とします。git push の直前に、正確なリモート、順序を保った両方の完全なエンドポイントセットとリポジトリ ID、意図した公開先、<exact-ref>、固定済みローカル SHA、予期されるリモート SHA または不在情報、アップストリームの状態、コミット範囲、依存する ref、ユーザーの選択を指定して preflight-mutations を呼び出します。PR が存在する場合は、PR のベース、固定済みの headRefName、<exact-ref>、head リポジトリ ID をそのガードと無効化条件に含めます。有効なシンボリック ref、ブランチ ref の SHA、HEAD、固定済みの公開ブランチと正確な ref、選択したリモートの完全な識別情報をガードと無効化条件に含めたうえで、両方のエンドポイントセットを再列挙して比較してから、次の正確なプッシュを実行します。
git push --force-with-lease="<exact-ref>:<expected-sha-or-empty>" "<preflighted-remote>" "<frozen-local-sha>:<exact-ref>"
git ls-remote --heads "<preflighted-remote>" "<exact-ref>"
失敗終了や曖昧な終了を含め、プッシュを試みた後は毎回、まずリモートの状態を確定します。両方の完全なエンドポイントセットを再列挙し、<exact-ref> に対する正確な git ls-remote の読み戻しを一度実行します。権威あるリモート SHA が固定済み SHA と一致し、順序を保ったセットに変更がなく、すべてのエンドポイントが引き続き意図した公開先と一致する場合に限り、プッシュが反映されたと記録します。古い SHA や予期しない SHA、読み戻し不能、エンドポイントの追加、削除、順序変更、未解決、不一致があれば、reconcile-required とします。停止し、コマンドの結果だけを根拠に再試行してはいけません。
リモートの結果を保持した後、有効なシンボリック ref、固定済みの公開ブランチ ref の SHA、HEAD を再読み込みします。シンボリック ref が <exact-ref> と一致し、両方のローカル SHA が固定済み SHA と一致する場合に限り続行します。リモートへの反映後にローカルの値が一つでも変わっていた場合は、remote landed / local publication moved と記録し、公開全体を reconcile-required として、プッシュを再試行せずに停止します。リモートに反映されていない場合は、ローカルの状態にかかわらず、確認された状態を保持して reconcile-required として停止します。リモートとローカルの両方の状態が検証を通過した後に限り、GitHub PR の入力で headRefName、headRefOid、headRepository.id を読み取り、それぞれが固定済みの head 名、固定済み SHA、意図した公開先の ID と一致することを必須とします。"Re-run on remaining" の場合:元の入力がローカルファイルなら、スキップ/入力待ちの項目に範囲を限定して /fix-pr-review <original-file-path> を呼び出します。それ以外の場合は、残りの項目に範囲を限定して /fix-pr-review <url> を呼び出します。"Done" の場合:終了します。
6. 終了
コミットが行われるのは、上記の完了後のプロンプトで明示的に "Commit changes" または "Push to remote" を選択した場合のみです。それ以外の場合は、作業ツリーをそのままにします。レポートに記載された推奨コミットメッセージを引き継ぎに使用します。