shoji9x9

pr-finalize-loop

作成済み GitHub PR の CI エラー解消とレビュー指摘対応を、CI が成功しレビュー指摘が尽きるまで自律ループで回すスキル。PR URL を受け取り、CI 失敗の修正・レビュースレッドの返信/解決・commit/push・設定したレビューツール(Copilot/Claude Code/Codex/none)への再レビュー依頼を反復する。自分の PR でなければ着手前に確認する。ループ中はユーザー確認を挟まず自律動作するが、人間判断を要する指摘だけは確認し、反映後にループへ戻る。`--max-iterations`(既定 5)で無限ループを防ぐ。レビュー対応単体は姉妹スキル pr-review-handle が担う。「PR を最後まで解決して」「CI とレビュー指摘がなくなるまで回して」「PR の CI とレビューを収束させて」「pr-finalize-loop」で必ず発動する。

shoji9x9 0 Actualitzat fa 2 setm.

Recursos

2
GitHub

Instal·la

npx skillscat add shoji9x9/skills/agents-skills-pr-finalize-loop

Instal·la des del registre de SkillsCat.

SKILL.md

Pr Finalize Loop

作成済みの GitHub PR を、CI が成功し、未解決のレビューの指摘が無くなるまで、自律して収束させる。
CI の失敗の修正、レビューの指摘への返信と解決、commit と push、設定したレビューツールへの再レビューの依頼という決まった往復を、人が何度も繰り返す代わりにループで回す。
PR そのものを作ることは、このスキルの対象外である(別に行う)。

この往復では、直して push すると CI とレビューがもう一度実行され、また直すことになる。収束するまで続けるので、止める時点を誤ると終わらない。
そのため、このスキルは次の 3 点を固定する。

  1. ループの間は、利用者に確認せずに自律して進める。自分の PR でなければ、着手する前に 1 回だけ確認する。
  2. 例外として、人の判断が要るレビューの指摘だけは確認し、判断を反映した後でループに戻る。
  3. 反復の回数の上限と、行き詰まりの検知で、必ず止まる。

1 回分のレビューへの対応(確認・返信・解決)のやり方は、姉妹スキル [[pr-review-handle]] と同じである。このスキルは、それを自律したループとしてまとめる。

使い方

pr-finalize-loop <PR URL> [--max-iterations <N>] [--wait-ci-before-review] [--review-tool <tool>]
  • <PR URL>(必須): https://github.com/<owner>/<repo>/pull/<番号>。番号だけを渡されたら、現在の repo の PR とみなす。
  • --max-iterations <N>(任意。デフォルトは 5): ループを繰り返す回数の上限。ループが終わらないのを防ぐ。
    1 回の反復は、状態の取得、CI とレビューへの対応、commit と push、再実行を待つ、までの 1 周である。
  • --wait-ci-before-review(任意。デフォルトはオフ): push した後の再レビューの依頼を、CI の再実行が終わるのを待ってから出す。
    デフォルト(オフ)では、push の直後に CI の完了を待たずに依頼し、CI とレビューを並行して進める。収束が速くなる。
    レビューが進行中なら(設定したツールの自動レビューでも、別のエージェントのレビューでも)依頼を保留する。
    失敗している HEAD にレビューを始めさせたくないときだけ指定する。
  • --review-tool <tool>(任意): この実行だけ、copilot・claude-code・codex・none のどれかを使う。共有の設定を変えずに、クレジットの状況などに一時的に対応できる。
  • ループの間は、利用者に確認せずに自律して進める。
    ループの中での例外は、後述の「自律性ポリシー」にある、人の判断が要るレビューの指摘だけである。着手する前の PR の持ち主の確認は、ループの外で行う。

例: pr-finalize-loop https://github.com/<owner>/<repo>/pull/6 / pr-finalize-loop 6 --max-iterations 3 / pr-finalize-loop 6 --review-tool codex

自然文でも発動する(「PR を最後まで解決して」「CI とレビュー指摘がなくなるまで回して」「PR の CI とレビューを収束させて」)。

前提

  • ツール: gh(GitHub CLI。gh api graphql・gh pr checks・gh run view を含む)、git
  • 前提スキル: なし。レビューへの対応のやり方は [[pr-review-handle]] と同じだが、このスキルは自律して動く版を中に持ち、単独で動く
  • MCP: なし
  • シェル: bash(POSIX 互換シェル)。コマンド例は bash で書いているので、Windows では WSL や Git Bash などの bash 環境で実行する
  • ランタイム: 要らない(node・pnpm・python など)。ただし、CI を直すときに、対象のリポジトリのランタイムが要ることはある

ブランチ運用・commit 規約の参照

ブランチ運用と commit の規約はリポジトリごとに違う。
決め方(設定ファイル、よく使われる文書の探索、利用者への確認の順)と、設定ファイル .config/skills/shoji9x9/skills.yml の扱いは、`references/conventions.md` にある。
どの規約に決まっても、次の操作の決まりは常に守る。--amend と force push をしない。関係するファイルだけを stage する。長い commit の本文は git commit -F <file> で渡す。

レビューツールの選択

push の後などに再レビューを依頼する AI レビュアーは、CLI のオプション、環境変数、共有の設定から選ぶ。
選ぶ順序と、ツールごとの依頼の方法と成立の確かめ方は、`references/review-tool.md` にある。
依頼先は同梱のスクリプト scripts/resolve-review-tool.sh で決め、値と、それがどの層(cli・env・config・default)から来たかを報告してから使う。
決める順序を推測すると層を取り違え、設定してある値を「未設定」と判定して、別のツールに依頼してしまう。手順は `references/review-tool.md` にある。

値は copilot・claude-code・codex・none のどれかである。
none のときは再レビューを一切依頼せず、収束と完了の判定から「HEAD がレビュー済み」の条件を外す。CI がすべて成功し、未解決のスレッドが無く、スレッドの外の指摘にも対応していれば完了とする。
この先の本文で「レビューの依頼」と書くときは、設定した review_tool への依頼を指す。

自律性ポリシー

  • ループの間は、確認せずに自律して実行する。CI の失敗の修正、レビューの指摘への返信と解決、commit と push、レビューツールへの再依頼を、利用者に 1 つずつ確認せずに進める。
  • ループの中での例外は、人の判断が要るレビューの指摘だけである(着手する前の PR の持ち主の確認は、下の必須の前提を確かめた後で別に行う)。
    次の指摘は、勝手に直さず、誤って解決もせず、その 1 件だけ利用者に判断を求める。妥当かをコードだけでは判断できない指摘、直し方が複数あって影響が大きい指摘、設計の判断が絡む指摘である。
    判断を反映したら(直すか、直さない根拠を返信して解決したら)ループに戻り、収束するまで続ける。この確認でループを打ち切らない。
  • 着手する前に、次の必須の前提を確かめる。満たさなければ着手せずに止まり、報告する。自律して commit と push をするので、対象を取り違えると危ない。そのため必ず先に確かめる。
    • PR が OPEN である。MERGED か CLOSED なら、仕上げる対象が無いと報告して終える。head ブランチが消えていることがあるので、これを最初に判定する。
    • 現在の repo と、PR の owner・repo が一致する。
    • 現在のローカルブランチが、PR の head ブランチと一致する。
  • 必須の前提を確かめた後、ループに入る前に 1 回、PR の持ち主を確かめる。
    自分が PR の作成者でも担当者でもなければ、自律したループは他の人の PR に commit・push・resolve をすることになる。
    判定の方法は `references/pr-ownership.md` で定義している。判定が not-owner なら、作成者と担当者を示して、続けるか中止するかを利用者に確認する。続けると決まったら、ループの間は聞き直さない。
    PR の作成者と担当者を取得できなければ、着手せずに止まる。
    自分の login を取得できない(ユーザーでないトークンで認証している)なら、判定を飛ばして続けるか中止するかを利用者に確認する。この扱いも、同じ references/pr-ownership.md で定義している。

基本フロー

着手する前の必須の前提と、PR の持ち主の確認を通ったら、iteration = 1 から --max-iterations(デフォルトは 5)まで、次を繰り返す。

  1. 状態を取得する。この段階ではレビューを依頼しない。待つ間隔と上限は、後述の「ポーリングと待機」に従う。

    • 要約を先に取得する。`references/state-query.md` を読み、review・thread・トップレベルのコメント・timeline・check-run は、先に索引(compact index)を取得する。
      全文を個別に取得するのは、現在の HEAD、前回の取得より後に遅れて届いた前の HEAD のレビュー、未処理の ID、未解決の指摘、レビューが届いたかの判定に要る check-run の出力だけにする。
      加工していない API の応答の全体を、反復のたびに会話に返さない。
    • PR の状態を確かめ直す。gh pr view <番号> --repo <owner>/<repo> --json state を再取得し、OPEN でなくなっていたら(他の人のマージやクローズなどで対象が無くなったら)、仕上げる対象が無くなったとして止まる。
      着手する前だけでなく、各反復の最初にも確かめ、無くなった対象の CI とレビューを待ち続けない。
    • CI: gh pr checks <番号> --repo <owner>/<repo> --watch --fail-fast で完了を待つ(どれかが失敗した時点で抜ける)。
      push の直後は、チェックがまだ登録されておらず、すぐに no checks が返ることがある。そのときは間隔を空けて数回まで確かめ直す。
    • 未解決のレビュースレッド: 後述の GraphQL を --paginate で全件取得し、isResolved == false で絞る。すべてのレビュアーを対象にし、作成者では絞らない。
    • 現在の HEAD がレビュー済みかを判定する(後述の「HEAD のレビュー済み判定」)。
      根拠に使うのは、レビュー、現在の HEAD のレビュー用の check-run、現在の HEAD の完全な commit の OID を書いたレビューの bot のコメントである。
    • レビューが進行中かを確かめる。現在の HEAD に進行中のレビュー(PR の作成時や push のときの自動レビューを含む)や、進行中のレビューのエージェントが無いかを見る。
      方法は後述の「レビュー進行中の検出」にあり、review_tool によって変わる。none は再依頼しないので、この保留そのものが要らない。
      進行中なら依頼せず、上限を決めて結果を待ち、届いた分を反映してから判定する。
    • レビューの内容と突き合わせる。HEAD への作成者以外のレビューがコメントを作っているのに、reviewThreads から取得できなければ、反映が遅れているとみなし、間隔を空けて再取得する(後述の「レビュー内容との整合検証」)。
    • スレッドの外の指摘を取得する。指摘はスレッドだけでなく、レビューの本文と PR のトップレベルのコメントにも書かれる(後述の「スレッド外に置かれた指摘(レビュー本文・トップレベルコメント)」)。
      スレッドが 0 件で comments.totalCount が 0 でも、対応していない指摘が残っていることがある。そのため、HEAD への作成者以外のレビューの body とトップレベルのコメントを、必ず切り詰めずに読む。
  2. 収束したかを判定する。依頼するより先に判定する。
    次のすべてを満たせば完了とし、要約を報告して終える。すでに CI とレビューがそろっている PR は、この時点でレビューも依頼せずに、何も変えずに終わる。

    • CI がすべて成功している。
    • 未解決のスレッドが無い。
    • レビューの本文とトップレベルのコメントに、対応していない指摘が無い。
    • 現在の HEAD がレビュー済みである。
    • レビューの内容との突き合わせが通っている。

    review_tool: none のときは「HEAD がレビュー済み」を条件にしない。CI がすべて成功し、未解決のスレッドが無く、スレッドの外(レビューの本文とトップレベルのコメント)の指摘にも対応していれば完了とする(この先の依頼の手順も飛ばす)。

    • 直近のレビューへの対応(返信、解決、スレッドの外への対応の記録)の createdAt より後のレビューが HEAD に付いていなければ、コードを push したかに関わらず、「HEAD がレビュー済み」を満たさないものとして扱う(review_tool: none を除く)。
      今の HEAD へのレビューはその対応より前に行われたもので、レビュアーは対応の内容を見ていない。
      手順 2 は手順 4 より前に判定するので、判定の材料は「この反復でこれから行う対応」ではなく、「直近の対応より後のレビューがあるか」にする。
      前者にすると、前の反復の対応を拾えず、対応した反復の次で収束したと判定してしまう。
      満たさなければ手順 6 で再レビューを依頼し、新しいレビューの結果が届くか、上限まで待ち終えるまで、収束したと判定しない。
    • CI がすべて成功して未解決のスレッドも無いのに、HEAD がレビューされていないときだけ(review_tool: none を除く)、レビューを依頼する。
      後述の「レビュー進行中の検出」を通ってから、設定したレビューツールに依頼し、上限を決めて待つ(後述の「再レビュー依頼」)。
      レビューが付けば、次の反復で拾う。
      上限までに付かなければ、「レビュー未着で待機終了」として止まる。これは「完了」とは別の止まった理由にする。
      上限は目安なので、そう報告する前に、判定に使うすべての方法でもう一度取得する。
  3. CI の失敗を直す。失敗したチェックのログを取得し(後述)、原因をコードの事実と照らして分析して直す。
    直せないとき、または同じ失敗が前の反復から良くならないときは、「行き詰まり」として扱う(後述の「停止条件」)。

  4. レビューの指摘を 1 件ずつ解消する。スレッド、レビューの本文、トップレベルのコメントの 3 つをすべて対象にする。

    1. 該当する path の line の付近を読み、指摘がコードの事実と合うかを評価する。
    2. 妥当で直す必要があれば、対象のファイルを直す。直さないなら、その根拠を用意する(例: 別の仕組みですでに対処している、指摘が事実と違う、設計の判断として意図している)。
    3. スレッドに返信してから解決する。この順序を必ず守り、返信していないスレッドは解決しない。
    4. レビューの本文とトップレベルのコメントの指摘には、返信するスレッドが無い(resolve もできない)。
      PR のトップレベルのコメントで、対象の箇所・判断・根拠・実測した結果を書いて返す。直した場合も、見送った場合も残す。
    5. 人の判断が要るときは、ここで直しも解決もせずに、利用者に判断を求める。判断を反映して返信と解決をしたうえで、ループを続ける。
  5. commit と push をする。手順 3 と 4 を両方終えてから、まとめて行う。
    レビューへの対応と CI の修正で触ったファイルだけを stage し、論理的な単位で conventional commit にして push する。関係の無い変更を入れない。コードを直していなければ、commit も push もしない。

  6. 対応した後で、レビューが確実に実行される状態にする(review_tool: none のときは、この手順を丸ごと飛ばす)。
    きっかけは push だけではない。コードを直さず、手順 4 の返信・解決・スレッドの外への対応の記録だけで終わった反復も、その対応をレビュアーが見ていないので、同じように扱う。対応したから収束した、とはしない。

    • push した反復: 新しい HEAD はレビューされていないので依頼する。
      まず、push に合わせて自動レビューが始まっていないかを確かめる(後述の「レビュー進行中の検出」。copilot ではタイムラインの Copilot 宛ての review_requested イベント、claude-code と codex では進行中の bot のレビューかコメント)。
      始まっていれば、このスキルからは依頼せず、そのレビューの結果を次の反復で拾う。
      自動レビューが無いときだけ、レビューツールに再依頼する。依頼は、モードに関わらず、後述の「レビュー進行中の検出」を通ってから行う。
      デフォルトでは CI の完了を待たずに依頼し、CI の再実行が終わるのは次の反復の最初の手順 1 で待つ(CI とレビューが並行して進む)。
      --wait-ci-before-review を指定したときだけ、push による CI の再実行が終わるのを待ち、新しい HEAD がまだレビューされていなければ依頼する。
    • push しなかった反復(返信・解決・スレッドの外への対応の記録だけ): この反復でそのどれも行っていなければ、何もしない(依頼せず、手順 7 に進む)。
      行っていれば、リモートの HEAD は変わらず、CI も新しく実行されないので、--wait-ci-before-review は関係しない。
      「レビュー進行中の検出」を通ってから、今の HEAD を対象に依頼する。
      基準の時刻には push が終わった時刻が無いので、HEAD の commit の committedDate ではなく、この反復で最後に投稿した返信やコメントの createdAt を下限に使う。それより前のレビューは対応を見ていない。

    リポジトリに別のレビューの bot(CI から起動される auto-review など)があるというだけで、それをレビューツールへの依頼の代わりとみなして依頼を省かない。
    進行中のときに保留して判定し直すのは、検出の手順に従う。保留は省略ではない。HEAD がレビュー済みなら依頼しないのは、収束の判定のとおりである。
    HEAD がレビューされていないまま依頼そのものを省いてよいのは、利用者が明示して指示したときだけである。

  7. 行き詰まりを検知する。この反復で、コードの修正もレビューへの対応も新しく何もできず、かつ CI の失敗が前の反復と同じで良くなっていなければ、止まる(後述の「停止条件」)。

  8. iteration を 1 増やす。--max-iterations に達したら止まる。

停止条件

どの場合も、終えるときに次を要約して報告する。CI の状態、残った未解決のスレッド、スレッドの外(レビューの本文とトップレベルのコメント)に残った指摘と総合の判定、反復の回数、止まった理由。
未解決のスレッドを残して終わるときも、中身に対応せずに resolve して、偽って解決したことにはしない。

止まった理由 条件
完了 CI がすべて成功し、未解決のスレッドが無く、レビューの本文とトップレベルのコメントに対応していない指摘が無く、HEAD がレビュー済みである。review_tool: none では HEAD がレビュー済みかを問わず、CI がすべて成功し、未解決のスレッドが無く、スレッドの外の指摘にも対応していれば完了とする
レビュー未着で待機終了 上のうち HEAD がレビュー済みであることだけを満たさず、レビューが現れるのを待つ時間が上限に達した
最大反復到達 --max-iterations(デフォルトは 5)に達した。残っている CI の失敗、未解決のスレッド、スレッドの外(レビューの本文とトップレベルのコメント)の指摘を書く
行き詰まり 同じ CI の失敗が良くならず、新しく打てる手が無い。失敗の内容と、どうすれば直せそうかを報告する
仕上げ対象なし 着手する前か、ループの中の状態の取得で見つける。PR が OPEN でない(MERGED か CLOSED)。ループの途中で他の人のマージやクローズで対象が無くなったときも同じように止まる
前提不一致 着手する前に止まる。repo が一致しない、または現在のブランチが PR の head と一致しない
持ち主の確認で中止 着手する前に止まる。自分が PR の作成者でも担当者でもない(または自分の login を取得できない)ことを示し、利用者が中止を選んだ

「レビュー未着で待機終了」は、「完了」とは別の止まった理由として報告する。依頼が成立していれば、遅れて届いたレビューに未解決の指摘が残りうる。
報告には、依頼した時刻、最後に取得した時刻、待つ時間の上限とその根拠(観測した届くまでの時間)を添える。

人の判断が要るレビューの指摘で確認するのは、止まる条件ではない。判断を反映した後でループに戻る。

ポーリングと待機

待つときは必ず上限を決める。終わらない待ちと、ポーリングのしすぎの両方を避ける。具体的な間隔と回数は、リポジトリの CI にかかる時間に合わせて変えてよい。

  • CI の完了を待つ: gh pr checks --watch に任せる。gh が中でポーリングし、完了するまで待つ。間隔は --interval <秒> で決める。自分で短い間隔のループを書いて呼び続けない。
  • no checks を確かめ直す: push の直後にチェックがまだ登録されていなければ、数回まで確かめ直す。
    それでも登録されなければ、この HEAD では CI が実行されないとみなして CI を待つのをやめ、収束の判定に進む。CI が無いこと自体は失敗ではない。
  • レビューが現れるのを待つ(--watch にあたるものが無い): レビューを依頼した後、一定の間隔で未解決のスレッドとレビューがあるかを再取得し、上限まで待つ。
    上限を超えたら、その反復はレビューが届かないまま閉じ、CI などの作業を進める。届かなかったことは報告に残す。
    残りの作業が無くなり、上限に達したまま終わるなら、止まった理由は「完了」ではなく「レビュー未着で待機終了」にする。
    • 完了の条件は、「HEAD のレビュー済み判定」と同じ 3 つの方法で書く。作成者以外のレビューが届いたこと、レビュー用の check-run、commit を書いた bot のコメントである。
      1 つの方法だけを見て待つ処理を書かない。他の方法で届いているレビューを「届いていない」と報告することになる。
      参照する文書に「〜のことがある」と書かれた方法は、例外を足したものであって、方法の置き換えではない。例外だけを実装の条件にしない。
    • 上限は、同じリポジトリの同じレビューツールで観測した、届くまでの時間から決める。実測した通常の遅れより短い固定の上限(90 秒など)で打ち切らない。
      打ち切った後に届いたレビューの、未解決のスレッドを取りこぼす。
    • 上限に達したことを「届いていない」として報告する前に、判定に使うすべての方法で 1 回取得し直す。上限は目安にすぎず、超えたことは届いていない証拠にならない。
    • 依頼が成立していてレビューが届いていなければ、「収束」ではなく「レビュー未着で待機終了」と報告する。CI とスレッドに問題が無いことと、レビューが収束したことを、同じ言葉で報告しない。
  • 進行中のレビューの完了を待つ: 進行中のレビュー(設定したツールの自動レビューでも、別のエージェントのレビューでも)を見つけて依頼を保留したときも、上限のあるポーリングで待つ。
    上限までに終わらなければ、進行中のシグナルは当てにならないとみなして通常の依頼の判断に戻り、そのことを報告に残す。止まったワークフローのせいで収束が止まらないようにする。
    ただし、名前が決まっていないツールで、何のものか特定できない未完了の check-run が残ったときは、依頼の判断に戻らない。その反復の依頼を保留する(「レビュー進行中の検出」)。

長時間実行・コンテキストの引き継ぎ

収束には時間がかかり、途中でコンテキストの自動圧縮(auto-compaction)が起きることがある。それに耐えるため、状態は GitHub にある実際の状態から取得し直す。

  • 各反復は、GitHub の実際の状態から再開できるようにする。手順 1 で CI の状態と未解決のスレッドを取得し直す。保存済みの返信と解決から、実際の状態を組み立て直せる。
  • 反復の回数の予算(--max-iterations)と行き詰まりの検知だけは、記憶に頼りやすい。「何回目の反復か」と「直近の CI の失敗の要点」を短い進み具合のメモに残し、再開するときの起点にする。
    メモを失ったら、GitHub の実際の状態から今の状況を導き直す。残りの作業が無ければ、反復を足さずに今の状況を報告して止まる。
    そのときは HEAD がレビュー済みかを取得し直して確かめ、レビューされていなければ「完了」ではなく「レビュー未着で待機終了」として報告する。予算がはっきりしないことを、レビューがそろった根拠にしない。

gh メカニクス

すべてのレビュアーを対象にするので、未解決のスレッドやレビューを取得するときに作成者で絞る必要は無い。
review_tool: copilot を使うときは、Copilot の作成者の login が API によって書き方が違うので、依頼と検出ではこの違いに注意する。
REST では Copilot、GraphQL では copilot-pull-request-reviewer、依頼に使うのは copilot-pull-request-reviewer[bot] である(詳しくは `references/review-tool.md`)。

着手前チェック(repo / head ブランチの一致)

gh pr view <番号> --repo <owner>/<repo> --json headRefName,baseRefName,url,state
git branch --show-current
  • state が OPEN でなければ(MERGED か CLOSED)、仕上げる対象が無いと報告して終える。head ブランチが削除されていることもあるので、ブランチの一致より先に判定する。
  • 現在の repo(gh repo view --json nameWithOwner -q .nameWithOwner)と、PR の owner・repo が一致しなければ止まる。
  • headRefName と現在のブランチが違えば、直す対象を取り違えるので止まる。

CI 状態の確認

gh pr checks <番号> --repo <owner>/<repo> --watch --fail-fast
  • すべてのチェックが終わるまで待ち、すべて成功なら終了コード 0、どれかが失敗したら 0 以外で終わる。

  • push の直後は、チェックがまだ登録されておらず、すぐに no checks が返ることがある。そのときは「ポーリングと待機」に従って確かめ直す。

  • push の直後に --watch がすぐ終わっても(exit 0)、CI が完了したとは信じない。
    force push や push し直した直後は、必須チェックがまだ登録されておらず、先に登録される飛ばすだけのチェック(CodeQL の skipping など)だけが見える瞬間がある。
    --watch はその集合が終わった時点で exit 0 で終わる(必須チェックは pending のまま)。すぐに no checks が返るのと同じ種類の誤判定である。
    判定は、必須チェック(check・signatures など、ブランチの保護で必須に指定したもの)だけを見て行う。
    --json のフィールド(bucket, completedAt, description, event, link, name, startedAt, state, workflow)には「必須か」を表すものが無いので、--required フラグで絞る(https://cli.github.com/manual/gh_pr_checks)。

    gh pr checks <番号> --repo <owner>/<repo> --required --json name,state,bucket

    結果を「failed」「pending」「未登録」に分けて扱い、pending にまとめない。

    • bucket が fail か cancel の行がある: CI の失敗が確定しているので、待たずに「CI 失敗ログの取得」に進む。
      mergeStateStatus が変わるのを待つことで代わりにしない。必須チェックが失敗した PR は BLOCKED のままで CLEAN や UNSTABLE にならないので、CI が失敗していると、反復のたびにポーリングの上限まで時間を使ってしまう。
    • pending が残っている: 「ポーリングと待機」の上限の中で確かめ直す。
    • すべてが pending でなく、fail も cancel も無い: CI が完了して成功したとみなす。補助として、gh pr view <番号> --repo <owner>/<repo> --json mergeStateStatus が CLEAN か UNSTABLE であることも確かめられる。
    • 必須チェックが 0 件: 必須チェックがまだ登録されていないか、リポジトリが必須チェックを設定していないかのどちらかである。行が無いことを、pending が無いことと同じに扱わない(--required でも同じ)。
      このとき gh は空の配列を返さず、no required checks reported on the '<branch>' branch を stderr に出して 0 以外で終わる。force push の直後に登録されていない状態が、まさにこれである。
      コマンドの誤りとして扱わず、この場合は「ポーリングと待機」の no checks の確かめ直しに従う。

CI 失敗ログの取得(修正の手がかり)

失敗したチェックの名前と、対応する GitHub Actions の run の失敗のログを取得して、原因を絞る。

gh pr checks <番号> --repo <owner>/<repo> --json name,state,bucket,link \
  --jq '.[] | select(.bucket=="fail")'
gh run view <run-id> --repo <owner>/<repo> --log-failed   # 失敗ジョブのログだけ表示
  • bucket は、state を pass・fail・pending・skipping・cancel に分類した値である。
    fail には FAILURE と ERROR だけでなく、TIMED_OUT・ACTION_REQUIRED・STARTUP_FAILURE も入るので、state を直接並べるより失敗を取りこぼさない。
    キャンセルも拾うなら、or .bucket=="cancel" を足す。
  • link から run-id を取り、--log-failed で失敗したステップのログに絞る。原因はコードの事実と照らして判断し、推測で広い範囲を書き換えない。

未解決スレッドの取得(GraphQL・全ページ取得)

threadId(解決に要る)、解決の状態、先頭のコメントの databaseId(返信に要る)をまとめて取得できる。未解決のスレッドは 1 ページに収まらないことがあるので、--paginate で全ページを取得する。

gh api graphql --paginate -f query='
query($endCursor: String) {
  repository(owner: "<owner>", name: "<repo>") {
    pullRequest(number: <番号>) {
      reviewThreads(first: 100, after: $endCursor) {
        pageInfo { hasNextPage endCursor }
        nodes {
          id
          isResolved
          comments(first: 1) {
            nodes { databaseId author { login } path line body }
          }
        }
      }
    }
  }
}'

isResolved == false のスレッドだけを 1 件ずつ処理する。返信先には、先頭のコメントの databaseId を使う。

返信(REST)

本文はバッククォートや $ を含みうるので、quoted heredoc(かファイルを書くツール)でファイルに書き、-F body=@<path> で渡す。gh api には --body-file が無い。

body_file=$(mktemp)
cat > "$body_file" <<'EOF'
<返信本文>
EOF
gh api --method POST \
  repos/<owner>/<repo>/pulls/<番号>/comments/<comment-id>/replies \
  -F body=@"$body_file"
rc=$?
rm -f "$body_file"
(exit "$rc")  # gh の失敗を後片付けの終了コードで隠さない

解決(GraphQL)

返信を投稿した後で、スレッドを解決する。

gh api graphql -f query='
mutation {
  resolveReviewThread(input: { threadId: "<threadId>" }) {
    thread { isResolved }
  }
}'

HEAD のレビュー済み判定

現在の HEAD(最新の commit)がレビュー済みかは、次の根拠を現在の HEAD と突き合わせて判定する。前の commit へのレビューや古い完了のコメントを根拠に、最新の push をレビュー済みとしないためである。

gh api graphql --paginate -f query='
query($endCursor: String) {
  repository(owner: "<owner>", name: "<repo>") {
    pullRequest(number: <番号>) {
      headRefOid
      author { login }
      reviews(first: 100, after: $endCursor) {
        pageInfo { hasNextPage endCursor }
        nodes { author { login } state commit { oid } }
      }
    }
  }
}'
  • レビューは --paginate で全ページを取得する。
    作成者を除くこと(次の項目)を前提にすると、作成者の返信(COMMENTED のレビュー)が直近に続いたときに、作成者以外の HEAD へのレビューが last: N の範囲から押し出されることがある。
    そのため 1 回だけの取得では「レビューされていない」と誤って判定し、要らない再依頼をしてしまう。

  • PR の作成者(pullRequest.author.login)によるレビューは、必ず判定から除く。
    レビュースレッドへの返信は、REST と GraphQL では作成者の state: COMMENTED のレビューとして記録され、その commit.oid が返信した後の新しい HEAD を指すことがある(実測)。
    除かないと、このスキルの標準の流れ(直す・返信する・push する)を回すたびに、誰もレビューしていない新しい HEAD を「レビュー済み」と誤って判定し、再依頼を忘れる。

  • 作成者以外のレビューのどれかの commit.oid が headRefOid と一致すれば、現在の HEAD はレビュー済みである。

  • review_tool が claude-code か codex のときは、指摘が 0 件だと、レビューの結果がトップレベルのコメントか check-run だけに載り、reviews[] にレコードそのものが作られないことがある。次のどちらかも、レビューが届いた根拠として認める。

    1. headRefOid を ref にして取得した check-run のうち、名前・GitHub App・出力の内容から Claude のレビュー用だと確かめられ、正常に完了したもの。
      status: completed だけでは足りない。conclusion と、output.title・output.summary も読み、失敗・timeout・skip・spend cap などでレビューが行われなかったものを除く。
    2. PR の作成者以外のレビューの bot によるトップレベルのコメントのうち、本文がレビューの完了かレビューの結果を示し、レビューした commit が現在の headRefOid と一致するもの。
      Codex は Reviewed commit を短縮 SHA で書く(実測)ので、手で補わず、gh api repos/<owner>/<repo>/commits/<短縮SHA> --jq .sha で完全な SHA に解決し、headRefOid と文字単位で一致することを確かめる。
      解決に失敗したもの、候補が複数あるもの、一致しないもの、working などの進行中のもの、エラーや skip のもの、関係の無い bot のコメントは除く。
  • コメントの created_at や updated_at が直近の push の基準の時刻より後だというだけでは、レビュー済みの根拠にしない。前の HEAD で始まったレビューが新しい push の後に完了すると、この時刻の条件を満たしてしまうからである。
    本文の commit を完全な SHA に解決できない完了のコメントは、指摘を集めることと check-run の意味を確かめることには使えるが、それだけで現在の HEAD にレビューが届いた証拠にはならない。

  • check-run は、GitHub の commit の ref 用の endpoint で、現在の HEAD に絞って取得する。
    デフォルトの filter=latest は、同じ名前の check-run の古い再実行をまとめてしまう。その HEAD のすべての試行を判定する必要があれば、filter=all とページネーションを使う。

    gh api --paginate \
      "repos/<owner>/<repo>/commits/<headRefOid>/check-runs?filter=all&per_page=100" \
      --jq '.check_runs[] | {name, head_sha, status, conclusion, app: .app.slug, started_at, completed_at, title: .output.title, summary: .output.summary}'

    API の形は GitHub の check runs REST API を、Claude Code Review の指摘が 0 件のときの出力は Claude Code Review 公式ドキュメント を参照する。

  • 上の根拠がどれも無ければ、最新の HEAD はレビューされていない。
    レビュー済みと判定した後も、レビューの本文・トップレベルのコメント・check-run の出力に、対応していない指摘や失敗が無いかを、この後の収集と突き合わせで確かめる。「届いた」と「指摘が無い」を同じものとして扱わない。

  • 収束の判定では、この「HEAD がレビュー済み」を条件に入れる(review_tool: none を除く)。すでにレビュー済みならレビューを依頼しない。完了した PR に余計なレビューを起こさないためである。

レビュー内容との整合検証(スレッド反映ラグ)

レビューが submit された直後は、レビュー(reviews)は取得できるのに、reviewThreads へのコメントの反映が遅れることがある(実測)。
未解決のスレッドが 0 件というだけで「指摘なし」と判定すると、コメント付きのレビューを取りこぼす。

レビューは `references/state-query.md` の 1 段目(review の索引。comments { totalCount } を含み、body は取らない)で取得し、レビュー済みかの判定と、この突き合わせの両方に使う。
本文は、同じファイルの 2 段目で、対象のレビューだけを取得する。

  • HEAD への作成者以外のレビューの comments.totalCount が 1 以上なのに、そのレビューのコメントを reviewThreads から取得できなければ、反映が遅れているとみなす。
    Copilot なら、レビューの本文の「generated N comments」でも件数を確かめられる(実測)。
    間隔を空けて再取得し(「ポーリングと待機」の上限に従う)、合うまで収束の判定をしない。
  • 上限までに合わなければ、「スレッドがまだ反映されていない可能性」を残りの作業として書いて報告する。警告なしに「指摘なし」と結論しない。

スレッド外に置かれた指摘(レビュー本文・トップレベルコメント)

指摘が書かれる場所はスレッドだけではない。集める対象は次の 3 つである。

  1. レビュースレッド(reviewThreads)
  2. レビューの本文(reviews[].body)
  3. PR のトップレベルのコメント(issues/<番号>/comments)

2 と 3 は reviewThreads にも comments.totalCount にも現れない。
そのため、未解決のスレッドが 0 件で、作られたコメントが 0 件でも、対応していない指摘が残っていることがある。実測で見つかった形は次の 2 つである。

  • レビューの本文: Copilot は、確信度の低い指摘を本文の <details> の中に ### Comments suppressed due to low confidence (N) として入れ、ヘッダには Comments generated: 0 new と書く。
    本文の冒頭には、### 🟡 Not ready to approve のような総合の判定も入る。
  • トップレベルのコメント: Claude の GitHub Action(review_tool: claude-code)は、総評と軽い指摘をトップレベルのコメントに置き、reviews[].body を空、state を COMMENTED にする。
    この形では、指摘がスレッドにも本文にも現れない。

取得は、`references/state-query.md` の 2 段の取得に従う。索引(1 段目)で本文を読む対象を決め、その本文だけを個別に取得する。

# 2 系統目: レビュー本文(索引で対象と決めた review だけ)
gh api repos/<owner>/<repo>/pulls/<番号>/reviews/<review-database-id> \
  --jq '{id, user: .user.login, commit_id, submitted_at, state, body}'

# 3 系統目: トップレベルコメント(索引で新規・更新と決めたものだけ。本文は切り詰めない)
gh api repos/<owner>/<repo>/issues/comments/<comment-id> \
  --jq '{id, login: .user.login, type: .user.type, created_at, updated_at, body}'
  • 反復ごとに、索引から本文を読む対象(HEAD への作成者以外のレビュー、前回の取得より後に届いたレビュー、未処理のレビュー)を決めて、body を読む。state が COMMENTED でも、本文に指摘や総合の判定が入る。
  • トップレベルのコメントも、反復ごとに、索引で新しいものと更新されたものを見つけて読む。
    特に review_tool が mention で依頼する方法(claude-code・codex)のときは、レビュアーが総評と指摘をここに置くものとして扱う。reviews[].body が空でも指摘はある。
    対象は、自分(PR の作成者。このスキルが書いた依頼のコメントや対応の記録を含む)以外の投稿すべてである。
    select(.user.type=="Bot") で bot に絞らない。人のレビュアーが総評をトップレベルに置くこともあるので、絞ると取りこぼす。
    .user.type は bot か人かを区別するためだけに使い、集める対象の絞り込みには使わない。
  • 切り詰めずに読む。「レビュー進行中の検出」の補助のシグナルは同じ API を body: .body[:200] で取得するが、それは進行中か完了かの判定のためである。
    その取得を指摘の収集に使い回さない。200 文字より後ろの指摘を取りこぼす。
  • 2 と 3 の指摘には返信するスレッドが無く、resolve もできないので、PR のトップレベルのコメントで返す(手順 4 の 4)。
    指摘の側には対応の記録が残らないので、対応したかどうかは、自分のコメントだけを証跡として扱う。
  • レビュアーが次の回の総評で、前の指摘を「対応されていない」として載せ直すことがある(実測)。載せ直された指摘も対応していない指摘として扱い、自分の証跡のコメントと突き合わせて、対応済みかを判断する。
  • 総合の判定(Not ready to approve など)が残ったまま完了するときは、その根拠(どの指摘に基づくのか、直したのか見送ったのか)を報告に書く。
    必須チェックに影響しない判定でも、利用者がマージしてよいかを判断する材料になる。

レビュー進行中の検出

レビューを依頼する直前(収束を判定するときと、手順 6 で対応の後に依頼するときの両方)と、各反復で状態を取得するときに、必ずこの検出をする。進行中なら依頼せず、結果を待つ。
対象は別のエージェントに限らない。設定したレビューツール自身の進行中のレビュー(PR の作成時や push のときの自動レビューを含む)も含める。

  • 自動依頼のシグナル(タイムライン。review_tool: copilot のとき): リポジトリの設定によっては、PR の作成時や push のときに、Copilot へのレビューの依頼が自動で出る(実測)。
    Copilot 宛ての review_requested イベントの created_at を基準の時刻と比べて、現在の HEAD への依頼かを判定する。
    基準の時刻より後のイベントがあり、その HEAD への作成者以外のレビューがまだ無ければ、依頼済みでレビューが進行中であるとみなし、新しく依頼しない。
    mention で依頼する方法(claude-code・codex)は review_requested を使わないので、自動レビューは下の補助のシグナル(進行中の bot のレビューかコメント)で見つける。

    gh api --paginate repos/<owner>/<repo>/issues/<番号>/timeline \
      --jq '[.[] | select(.event=="review_requested" and .requested_reviewer.login=="Copilot")] | last | .created_at'
    • 最新のイベントの日時だけでは判定できない。基準の時刻より後の created_at だけを自動で依頼された根拠にする。
      前の HEAD への依頼のイベント(PR の作成時など)で「自動で依頼済み」と誤って判定し、再依頼を飛ばさない。
    • 基準の時刻には、手順 6 で push した反復では、push が終わった直後に記録した時刻を使う。
      push しなかった反復(返信と解決だけ)では、この反復で最後に投稿した返信やコメントの createdAt を使う。HEAD は変わらないので、commit の時刻を使うと、対応の前のレビューを対応の後のレビューと誤って判断する。
      ループを始めたときなど、基準を記録していない場合は、HEAD の commit の committedDate(git log -1 --format=%cI)を下限に使う。--amend も force push もしないので、push はこの時刻より後になる。
  • 主なシグナル(check-run): 現在の HEAD の未完了のチェックに、別のエージェントのレビューを示すものが無いかを見る。
    gh pr checks だけで「進行中でない」と結論しない。このコマンドはレビューの bot の check-run を一覧に出さないことがある。
    実測では、copilot-pull-request-reviewer が in_progress でも、gh pr checks の pending に現れなかった。pending が 0 件でも、無い証拠にはならない。
    現在の HEAD の commit の check-runs の endpoint も、必ずあわせて見る。

    check-run の名前の扱いは review_tool によって分かれるが、この方法そのものは飛ばさない。
    copilot は名前が決まっている(copilot-pull-request-reviewer。実測)ので、名前が一致するもので絞る。
    mention で依頼する方法(claude-code・codex)は名前が決まっていないので、1 つの名前を推測して照会しない。
    ただし、`references/review-tool.md` が定めるとおり、check-run はレビューが進行中かを示す共通のシグナルである。指摘が 0 件のときに、結果を check-run だけに載せることもある(同じファイルの出典を参照)。
    照会そのものを省くと、bot のコメントを伴わないレビューを無いものと誤って判定し、同じ mention を重ねて投稿する。
    名前が決まっていないツールでは、現在の HEAD の未完了の check-run を候補として取得し、app・name・output の内容から、レビューのエージェントのものだと確かめられたものだけを数える(`references/state-query.md` の 2 段の取得と同じ形)。
    確かめられない候補は特定できたものとして数えないが、完了するか分類できるまで、「無い」という結論も保留する(後述)。

    # copilot: 名前が固定なので完全一致で絞る。
    gh api --paginate "repos/<owner>/<repo>/commits/<headRefOid>/check-runs?filter=all&per_page=100" \
      --jq '.check_runs[]
            | select(.status != "completed")
            | select(.name == "copilot-pull-request-reviewer")
            | {name, app: .app.slug, status, started_at, title: .output.title, summary: .output.summary}'
    
    # claude-code / codex: 名前を固定できないので未完了の候補を列挙し(1 段目。output は返さない)、app / name で仕分ける。
    # 絞り込みは gh の --jq 内で完結させる(外部 jq へパイプしない。前提ツールを増やさず、gh api の終了コードも保てる)。
    gh api --paginate "repos/<owner>/<repo>/commits/<headRefOid>/check-runs?filter=all&per_page=100" \
      --jq '.check_runs[]
            | select(.status != "completed")
            | {id, head_sha, name, app: .app.slug, status, started_at}'
    
    # 2 段目: 仕分けに output が要る候補と未同定の候補は id を保持し、同じ run を id で取り直す
    # (未完了だけの照会では完了した run が消えて追跡できない)。
    gh api "repos/<owner>/<repo>/check-runs/<id>" \
      --jq '{id, head_sha, name, app: .app.slug, status, conclusion, title: .output.title, summary: .output.summary}'

    ここで数えるのは、レビュー用の check-run だけにする。
    この endpoint には通常の CI も入るので、未完了のものを無条件にレビューが進行中と読むと、gh pr checks に pending として出ない関係の無い run が、再依頼をいつまでも止めてしまう。
    名前の部分一致で拾わない。dependency-review や security-review のような通常の CI まで、進行中のレビューに数えてしまう。
    数える条件は、名前が決まっているかどうかで分け、片方の規則をもう片方に当てない。片方だけを厳しくすると、もう片方で誤って判定する。

    • 名前が決まっているツール(copilot): check-run の名前がそのまま一致したものだけを数える。
    • 名前が決まっていないツール(claude-code・codex): 完全な一致を求めない。参照する文書が名前を定めていないので、候補が常に 0 件になり、実行中のレビューを無いものと誤って判定して、同じ依頼を重ねて投稿してしまう。
      上の仕分けで、app・name・output から、レビューのエージェントのものだとはっきり特定できた候補だけを数える。名前に review を含むといった部分一致は、特定の根拠にしない。
    • 特定できなかった未完了の候補が残っている間は、特定できた候補が 0 件でも「進行中のものは無い」と結論しない。
      その候補が完了するか、app・name・output から仕分けられるまで、「ポーリングと待機」の「進行中のレビューの完了を待つ」と同じ上限で待つ。
      取得し直しを重ねても曖昧さは解けないので、回数ではなく、候補が完了するか分類できるのを待つ。
      特定できなかった候補は、run の id と head_sha を記録して持っておき、完了したか分類できたかは、同じ id を check-runs/<id> で取得し直して判定する。
      未完了のものだけを返す照会では、完了した run が一覧から消え、「候補が残っていない」と誤って読んで、重ねて mention を投稿することがある。
      head_sha が現在の headRefOid と一致することも確かめ、完了したら、その出力でレビューか通常の CI かを判定する。
      記録した候補は、完了したか分類できたことを確かめるまで、「残っている特定できない候補」として数え続ける。
      上限までに完了も分類もできなければ、その反復では依頼しない。mention は繰り返すと結果が変わるので、特定できない run がレビューだった場合に、レビューが重ねて起動するからである。
      後述の「進行中のレビューの完了を待つ」にある「当てにならないとみなして依頼の判断に戻る」は、この状態には当てない。
      特定できない run の名前と「依頼を保留した」ことを残りの作業として記録し、次の反復で状態を取得するときに判定し直す(完了したか分類できていれば、通常どおり判定する)。
      最後の反復まで残ったら、レビュー未着・依頼の保留として、止まったときの報告に run の名前を書く。
      待ちがいつまでも続かないのは、待つ時間が反復ごとに上限を持ち、反復の回数も --max-iterations で限られているからである。止まった通常の CI があっても、有限の時間で止まる。

    output があることを条件にしない。進行中の check-run は、output.title や output.summary を持たないことがある(実測)。
    出力は、届いたレビューが実際に行われたかを確かめる材料であって、進行中かの判定に必須の条件ではない。

    gh api が 0 以外で終わったときは、空の結果を「進行中のものは無い」証拠にしない。権限の不足、ref の誤り、一時的な API の失敗でも空になる。
    終了コードを確かめ、失敗していれば、無いと判定せずに再取得する。判定できないときは失敗として扱う。

    「進行中のものは無い」と結論できるのは、次のすべてを満たすときだけである。
    gh pr checks と上の check-run の照会の両方が成功している。数える条件(上)を満たすレビューの候補が 0 件である。特定できない未完了の候補も残っていない。
    名前が決まっていないツールでは、「レビューの候補が 0 件」と判断するのに仕分けが要る。依頼した直後に何も見えないことを無いと取り違えないよう、「ポーリングと待機」の上限の中で間隔を空けて数回取得し直す。
    どの回でも候補が出ないことと、補助のシグナル(進行中の bot のレビューかコメント)も空であることを確かめてから結論する。
    待つ時間の上限を超えたことを根拠に再依頼に進む前に、この 2 つの方法で、進行中のシグナルが本当に無いことを確かめる。
    上限は、実測した届くまでの時間から決めた目安にすぎず、超えただけではレビューが止まった証拠にならない。

    # review_tool: copilot のときは Copilot 自身のチェックを別エージェント判定から除外する。
    # copilot 以外(claude-code / codex / none)のときは末尾の `and .name!=...` を外し、除外しない。
    gh pr checks <番号> --repo <owner>/<repo> --json name,bucket,workflow \
      --jq '.[] | select(.bucket=="pending" and .name!="copilot-pull-request-reviewer")'
    • workflow の名前やジョブの名前がレビューのエージェントを示すもの(例: workflow「Claude Review」やジョブ auto-review)が pending なら、進行中とみなす。
      名前はリポジトリごとに違うので、決まった一覧ではなく名前から判断する。
    • 除くものの条件は、review_tool によって変える。
      review_tool: copilot のとき、Copilot 自身のチェック(チェックの名前は copilot-pull-request-reviewer。実測)は、別のエージェントではなく、設定したレビューツールのレビューが進行中であることのシグナルとして扱う。
      そのため、上のコマンドで、別のエージェントの判定から除く。pending なら新しく依頼せず、完了を待つ。
    • review_tool が copilot 以外(claude-code・codex・none)のときは、Copilot は設定したツールではないので、pending の Copilot のチェックは、別のエージェントの進行中のレビューにあたる。
      このときは除かずに(jq の and .name!="copilot-pull-request-reviewer" を外して)進行中として扱い、保留して完了を待つ。
  • 補助のシグナル(bot の進行中のコメント): check-run として現れないレビューのエージェント(クラウドで実行するものなど)のためのシグナルである。bot による直近のコメントが作業中を示していないかを見る。
    見る対象は、今の反復(直近の push より後)に作られたか更新された、レビューのエージェントのコメントだけである。レビューと関係の無い bot(カバレッジなど)や古いコメントは、進行中の根拠にしない。

    gh api --paginate repos/<owner>/<repo>/issues/<番号>/comments \
      --jq '.[] | select(.user.type=="Bot") | {login: .user.login, created_at, updated_at, body: .body[:200]}'
    • この body: .body[:200] は、進行中かの判定のためだけに使う。指摘の収集にこの取得を使い回さない(前述の「スレッド外に置かれた指摘」。切り詰めた分の指摘を取りこぼす)。
    • Claude の GitHub Action は、始めたときにコメントを作り、終わったときに同じコメントを「finished」の表記に編集する(進行中は working の表記。実測)。
      進行中でも、タスクの一覧の更新などで編集されて updated_at は進むので、編集されたかどうかで完了とみなさず、本文の表記で判定する。
      文言は実装によって変わりうるので、特定の文字列との一致ではなく、本文が作業中か完了かという内容で判断する。
  • 依頼した直後に何も見えないことに注意する。手順 6 の依頼(push したかに関わらない)の直後は、別のエージェントのチェックがまだ登録されておらず、始めたことを示すコメントもまだ投稿されていないので、両方のシグナルが空になることがある(no checks と同じ現象)。
    両方のシグナルが空でもすぐに「進行中でない」と確定せず、間隔を空けて数回確かめ直してから依頼する。

  • 見つけたときの動き: レビューを依頼せず、上限のあるポーリング(「ポーリングと待機」)で、チェックの完了、コメントが finished になること、レビューが届くことのどれかを待つ。
    完了したら、「HEAD のレビュー済み判定」と「レビュー内容との整合検証」をやり直し、それでも HEAD がレビューされていないときだけ依頼する。

再レビュー依頼

review_tool: none のときは依頼しない(この手順を丸ごと飛ばす)。
それ以外では、現在の HEAD がレビューされておらず、進行中のレビューも無いときだけ依頼する。設定したツールの自動レビューも、別のエージェントのレビューも、進行中のレビューに含める(上の「HEAD のレビュー済み判定」と、前述の「レビュー進行中の検出」)。
push した反復では、デフォルトでは push の直後に(CI の再実行の完了を待たずに)依頼し、CI とレビューを並行して進める。
--wait-ci-before-review を指定したときだけ、push と CI の再実行が終わるのを待ってから依頼する。失敗している HEAD にレビューを始めさせないためである。
デフォルトでは、CI の失敗が分かった HEAD にレビューが付くことがあるが、直して push し直せば新しい HEAD にレビューを依頼し直すので、害は無い。

依頼の方法と成立の確かめ方は、設定した review_tool ごとに違う(`references/review-tool.md`)。

  • copilot: requested_reviewers API に copilot-pull-request-reviewer[bot] を渡す。成立は、タイムラインの Copilot 宛ての review_requested イベントで確かめる。requested_reviewers が空でも、すぐに成立しなかったとはしない(実測)。
  • claude-code・codex: PR のトップレベルのコメントに @claude review か @codex review を投稿して依頼する。成立は、依頼のコメントを投稿したことと、その後の進行中の bot のレビューかコメントと、レビューが届いたことで確かめる。

タイムラインなどで確かめられないときも、上限のあるポーリング(「ポーリングと待機」)でレビューが届くのを待てば、成立を確かめられる。どちらでも確かめられなければ、成立しなかったとして報告する。
レビューが付くまでの待ちは、「ポーリングと待機」の上限のあるポーリングに従い、止まったままにしない。

commit の扱い

  • commit message は、「ブランチ運用・commit 規約の参照」で決めた規約に従う。
    commit-msg の検証(commitlint や lefthook など)があれば、それにも従う。本文の行の長さに上限があれば守り、長い本文は git commit -F <file> で渡す。
  • 関係の無い変更を同じ commit に入れない。CI の修正とレビューへの対応で触ったファイルだけを stage する。既存の worktree に関係の無い差分があれば、入れない。
  • pre-commit フック(lefthook など)や kaizen の commit 前のチェックがあれば実行される。チェックで止まったら、指示に従って kaizen --current を実行してから commit し直す。
  • commit の --amend と force push はしない。

妥当性の判断ガイド

CI の失敗もレビューの指摘も、機械的にすべて直すことも、すべて退けることもせず、事実に基づいて 1 件ずつ判断する。

  • レビューの指摘がコードの今の状態と合っていて、バグ・リスク・読みにくさなどの実害があるかを見る。別の仕組みですでに対処しているなら、直さずに根拠を返信する。
  • 外部のツール・API・ライブラリの仕様についての指摘(特に「常に失敗する」という指摘)は、直す前に、公式のドキュメント・実際の出力・テストで確かめる。
    自信ありげな誤った指摘をそのまま「修正」すると、その修正が新しい不具合になる。
  • CI の失敗は、失敗のログの事実から原因を特定して直す。結果が不安定なテストが疑われるときも、まず再実行や原因の確認で切り分け、テストやコードの本当のバグと取り違えない。
  • 直し方が複数あって影響が大きいとき、コードだけでは妥当かを判断できないとき、設計の判断が絡むときは、「人の判断が要る指摘」として扱う。その 1 件だけ利用者に確認してから、ループに戻る。

追加確認が必要な条件

ループの間は自律して進めるが、次のときだけ確認する。最初の 2 つは止まり、3 つ目は着手する前に確認し、最後の 1 つは確認した後でループに戻る。

  • 現在の repo と、PR の owner・repo が一致しない(着手する前に止まる)。
  • 現在のローカルブランチが、PR の head ブランチと違う(着手する前に止まる)。
  • 自分が PR の作成者でも担当者でもない(着手する前に 1 回確認し、続けるならループに入り、中止なら止まる。`references/pr-ownership.md`)。
  • レビューの指摘が妥当かをコードだけでは判断できない、直し方が複数あって影響が大きい、または設計の判断が絡む(その 1 件を確認し、反映した後でループに戻る)。