| name | issue-loop |
| description | issue 対応の 10 ステップ・ループ (Step 0-pre shift-left 調査 → 設計 → 実装 → 敵対的レビュー → メタレビュー → E2E → merge → 振り返り) を駆動する汎用 dev process skill。issue 番号 or URL を渡して起動する。Use when the user asks to run the issue loop / 10 ステップループ for a GitHub issue, or to 対応 an issue with the full review process. |
| user-invocable | true |
| disable-model-invocation | false |
Purpose
GitHub issue 1 件を、shift-left 調査から振り返りまでの 10 ステップで対応するプロジェクト非依存の dev process。品質担保の核は (1) 設計前の独立インパクト調査、(2) 実装とレビューの文脈分離 (クリーンなサブエージェント)、(3) レビュー finding の独立検証 (メタレビュー)、(4) 振り返りによるチェックリストへのフィードバック。
引数
issue 番号 or issue URL。省略された場合は対象 issue を確認してから開始する。
サブエージェント運用の原則
- 委譲先は常にクリーンな Opus 5 (
claude-opus-5) サブエージェント。メイン loop (主担当) の仮説・文脈を持ち込ませないことで、確証バイアスを避ける。
- brief は本 SKILL.md のテンプレから生成する。issue 番号と対象ファイルを埋めるだけで brief が完成する状態を保つ。
- メイン loop は orchestration と判断に徹し、調査・実装・レビューの実作業はサブエージェントに出す。
- バックグラウンドサブエージェントの orphan 防止: バックグラウンド委譲したエージェントは、セッションがアイドル化 (ユーザー離席等) すると一緒に停止し、完了通知も失われうる。長時間 (数分超) のエージェントを起動したターンでは必ずフォールバックタイマー等の完了待ち機構を併設してセッションを起こし続けるか、同期実行にする。再開時に停滞を疑う場合は、経過時間ではなくトランスクリプトの更新時刻・サイズで「実働中 / 停止済み」を判別し、死んでいた場合は部分トランスクリプトから完了済みの検証結果を回収してから (全部やり直さず) 差分だけ再委譲する。委譲先がさらに子エージェントへ再委譲して自分は停止するケースもある — その場合は委譲先へ追加メッセージを送って再開させ、「子の結果がもし揃っているなら統合、揃っていないならこれ以上再委譲せず自分で完遂」を指示するのが復旧の定石。API エラー (session limit 等) で途中死したエージェントは、リセット時刻を確認してから同一 brief で作り直してよい。
ユーザー判断のエスカレーション
メイン loop が自律で下してよいのは技術判断まで。以下の 3 点はユーザー (プロダクトオーナー) の判断領域であり、自律実行の明示的な許可 (「確認なしで進めて」等) がない限り、質問ツール等で確認してから先へ進む:
- 設計選択 (Step 0): 実装方針の候補が複数あり trade-off が非自明な場合 (issue に複数案が併記されている場合を含む)。Step 0-pre report の要点と推奨案 + 根拠を添えて選択を仰ぐ。
- プロダクト意図の変更: spec の要件文言の改訂、既存保証の縮小、既知限界の accept (修正せず文書化) など、機能の意図そのものに触れる判断。技術的整合性だけでは決められない。
- main への merge (Step 8): CI green と E2E 完了を確認した上で、merge 実行の直前に確認する。
確認時は、判断に必要な文脈 (選択肢 / 推奨 / 影響範囲) を質問自体に含め、ユーザーが過去ログをスクロールバックせずに答えられる形にする。確認待ちの間、ブロックされない他 Step の準備 (レビュー brief の生成等) は進めてよい。
起票ゲート (全 Step 共通 — finding を issue にする前に必ず通す)
処理は fix / 別 issue / accept / 起票しない の 4 値。どれを選ぶかの前に、この 1 問に答える。
この finding を、通常の使い方をしている外部ユーザーが踏むか?
| 答え | 処理 |
|---|
| A. 踏む — 文書どおりの手順・普通のリポジトリで発現する | 起票する。criticality:major。 ユーザーが最初に見る症状を 1 文で書く |
| B. 特殊な入力/設定なら踏む — CRLF / BOM / symlink / 非英語 / ID 衝突 / 特殊な markdown 形状など | 既存 issue を検索し、同じ root cause があればそこにコメント。無ければ起票して criticality:minor。 トリガを 1 文で書く |
| C. このリポジトリの開発しか困らない — dogfood / 自前 CI / 自前 skill / 自前 spec | 起票しない。 ループの報告に 1 行残す |
| D. 挙動の欠陥ではない — docs 不整合 / リファクタ / 「どちらが正しいか決めたい」 | 起票しない。 「決めたい」ものはそのループ内で決めるか、ユーザーに 1 問聞く |
- 「真だが些末」は誤検知ではない。それでも C / D なら起票しない。 finding を落としてよい理由は「偽」だけではない。
- accept の定義: A / B に該当し、かつ今回のスコープでは直さないと決めたもの。C / D は accept ではなく「起票しない」。
- B で既存 issue を探すのは必須。 同じ root cause の別症状を新規 issue にすると、1 つの問題が 3 件に増える。
- 1 ループで起票してよい上限は、そのループがクローズする issue 数。 超えるなら PR 本文に理由を書く。
なぜ上限が要るか (2026-08-01、全 238 issue / 41 日分の実測):
- モデル非依存の実績 — 直近 4 ループ (#235 / #387 / #422+#419 / #427) はクローズ 4 件に対し起票 17 件。時刻で切っただけで、帰属の推定を含まない
- 帰属を推定した比 (「親のクローズ ±1 日以内に、親を引用して起票された数」) は 0.9 → 2.75。帰属窓を 6 通り振ると絶対値は 0.5〜3.3 の幅で動くが、「3 倍前後に増えた」はどの窓でも変わらない
- この比が 1 を超えている限り、直す速度を上げるほど backlog は速く増える。実際、週 56 件クローズした週は純増 −2、週 8 件の週は +21 だった
同時に、その時点の open 61 件のうち通常利用で踏むものは 6 件 (9.8%)、挙動の欠陥ですらないものが 24 件 (39%)、うち約 11 件は既に修正済み・重複・非欠陥だった。増えていたのは欠陥ではなく観測で、それを止める規則が 1 つも無かった。
10 ステップ
Step 0-pre: shift-left インパクト調査
対象プロジェクトの AGENTS.md / CLAUDE.md に Step 0-pre 用のプロジェクト固有チェックリスト skill が定義されていればそれに従う (例: artgraph の artgraph-graph-primitive-impact)。無ければ以下の汎用チェックを brief にする:
- 変更対象関数の直接呼び出し元 grep
- 戻り値フィールド名での transitive consumer trace (関数名でなくフィールド名で追う)
- エントリポイント (CLI コマンド / API ルート / hook) 全網羅の使用マトリクス — 契約を「一様に適用される」と文書化する変更では、マトリクスの粒度をエントリポイント単位でなく「エントリポイント × 契約に関与する全呼び出し経路」まで下げる (issue が名指ししていない経路も対象に含める)
- fail の見逃しが高コストな経路 (gate / CI / 課金 / 認可) への到達可能性
- 判定/検知ロジックの状態空間: 二値 (or 少数値) 判定を新設・変更する場合、対象が実際に取りうる状態を全列挙し、想定外の中間状態 (異物混入・破損・部分適用・混成環境等) が既存の値のどれかに丸め込まれていないか確認する (例: 依存ライブラリの「ロードは成功するが呼び出しが常時失敗する」部分故障は、load 失敗/呼び出し失敗の二値分類のどちらに落ち、その帰結は意図どおりか)。5(補) 宣言側の過剰列挙監査: 状態を表す判別可能 union (CLI 出力の
action / status 種別等) を新設・拡張する場合、上記の「実際の状態が既存の値に丸め込まれていないか」に加え、逆方向 — 型・switch 等の消費側に列挙された variant のうち、生成側のどの入力パスからも到達不能な variant がないか — を、生成側コードと突き合わせて確認する。到達不能 variant は tsc の網羅性チェックが与える「ハンドリング済」保証を空証文化させ、JSON 消費側の誤解を誘発する (PR #367 LOW-4: 型定義と switch case には存在するが生成側は produce しない "skipped-not-selected" variant が残り、--format json 消費側が「非選択 agent はこの action で出てくる」と誤解しうる状態だった)
- 既存の決定的ツールとの重複: 新設する手作業チェックが、プロジェクト内の既存ツール (lint / doctor / check 等) と同じ情報を再実装していないか確認する
- 構造比較キーの invariant 監査: 集合演算 (diff / dedupe / 一意性判定) を新設・変更する場合、キーに使う各フィールドについて (a) 外部 API 由来で順序保証のないコレクション (array 等) をそのままキーに使っていないか、(b) tagged union の全 variant がキーの不変条件 (安定性・順序非依存・意味的一意性) を満たすかを個別に検証する。特に同一シリーズ内の直近 PR が新設した variant があれば優先的に再チェックする
- 新設ガード/validation/警告条件の fail-closed + 頑健性 + 兄弟対称性: 検知・ガード機構や入力 validation・警告条件 (CI job / lint / validator / CLI フラグ検証 / 条件付き warning 等) を新設する計画では、(a) 機構自体の失敗 (前段コマンドのエラー・入力取得失敗) が「違反なし」と区別されて fail-closed に倒れるか (
|| true や pipefail との相互作用に注意)、(b) 検出パターン・発火条件が大文字小文字・区切り文字・等価表記 (別綴りの同値アドレス等)・縮退値 (空文字・型違い — 配列を期待する入力への裸文字列等。従来無検証だったフィールドを新設コードが最初に消費する場合、その検証状態を先に確認する: PR #359 H1) に耐えるかを意図的なすり抜けサンプルの実測で確認し、(c) 同じ入力面の兄弟パラメータに同等の検証を付けたか (片側だけ厳格化すると、無検証側の縮退値が新設の警告条件そのものを素通りする) を横比較し、(d) 既存 fail-closed ガードを緩和する変更では、まず「実際に何が現在のパターンにマッチしていたか」を列挙し (git ls-files | grep -iE '<FORBIDDEN>' 等)、パターン/ルールそのものを削除・緩和するのではなく、対象だけを狙った最小スコープの例外 (pathspec 除外・許可リスト追加・narrow patterns 等) で対応しているかを確認する (PR #367 HIGH-1: SC-007 の \.codex/hooks は commit された対象 0 件・kiro.*hook は 1 テンプレのみで、パターン全削除ではなく pathspec 除外で足りたのに全削除して将来同種違反への保護を永続的に失わせるところだった)
brief テンプレ (Step 0-pre)
あなたは {{repo}} の調査担当です。issue {{issue}} で {{変更対象}} を {{変更の一行要約}} する変更を検討しています。実装はまだ存在しません。{{チェックリスト skill のパス or 上記汎用 4 チェック}} を順に実行し、「この変更で SILENT に破壊される経路」のランク付きリスト (HIGH/MEDIUM/LOW) を報告してください。各項目: (a) 経路 (b) 影響を受ける機能 (c) 該当テストの有無 — その経路を単体でカバーするテストと、他経路との組み合わせ (交差点) をカバーするテストを区別して報告する。マトリクスの交差セル (例: 「CLI 出力フォーマット × 複数エージェント混在」) は前者があっても後者がなければ後者は明示的に「なし」と書く (PR #367 MEDIUM-3: dispatch データ層と CLI 単一エージェントは各々 cover 済だが、両者の交差セルは未 cover でランタイム regression 検知不能だった) (d) 推奨 (本 PR で fix / 別 issue / accept)。「別 issue」を選ぶ前に起票ゲート (A/B/C/D) を通し、選んだ答えを併記すること。
Step 0-pre 報告の必須セクション (申し送りの減衰防止)
Step 0-pre で確立した事実が下流の Step で減衰する形の欠陥は、レビューで「既存チェックを正しく回せば出たはず」に分類されるものの大半を占める。チェックリストの不足ではなく申し送りの問題なので、報告の末尾に以下 2 表を必須で置き、Step 1 が各行に自分の判断を書いてから実装へ進む。
(1) 名指し箇所 × 4 値処理表 — ファイル:行 / 事実 / 起票ゲート (A/B/C/D) / 本 PR で fix・別 issue・accept・起票しない。Step 0-pre が行番号付きで名指しした箇所を全件。Step 1 はこの表を逐語で引き継ぎ、各行に判断を書く。「確認する」はどの値でもないので不可とする (動詞を弱めた瞬間に実装段階で「確認のみ」で終わり、レビューで再指摘される)。Step 2 は表の全行に結果を書く。
(2) 測定 × 対象案 × 転写可否表 — 測定内容 / 対象案 (候補 A / 候補 B / HEAD) / 結果 / 採用案でも成立するか (成立する・要再測・無関係)。調査段階で棄却した案について取った測定は、採用案へ自動的には引き継がれない。 Step 1 はこの表の「要再測」行を実装前タスクとして引き継ぐ。
前例: PR #423 (issue #387) — Step 0-pre が棄却した候補について「--diff 系ゲートは baseline を同一バイナリで再スキャンするので意味論変更は両側に効き、失われた signal は gate に出ない」を exit code 込みで実測していた。この性質は案に依存しないのに、採用した候補の設計文書が「この方向は fail-loud」と無限定に断定し、その文言が upgrade note まで到達した。表 (2) があれば Step 1 の断定と正面衝突していた。
Step 0: 設計 + デグレ調査
Step 0-pre の report を入力に、実装方針を決める。report の HIGH 項目は設計で必ず言及 (対処 or accept の理由) する。設計候補が複数あり trade-off が非自明な場合、および spec/プロダクト意図の変更を伴う場合は、決める前にユーザーに確認する (上記「ユーザー判断のエスカレーション」1/2)。
Step 1: 実装計画
タスク分解 + 7 観点セルフチェック (Step 4 と同じ観点で自分の計画を先に叩く): 境界条件 / 条件分岐の組み合わせ / 不正な状態遷移 / 例外系 / 実運用の事故 / エッジケース / 考慮漏れ。
新しい失敗/劣化シグナル (exit code・reject 経路等) を導入する計画では、既存の類似 sibling コマンド群の対応する契約を表にし、一致させるか意図的に変えるかの方針を brief に明記してから実装委譲する (単一コマンドの視点では正しく見える設計が、横比較で初めて非一貫と分かるパターンの防止)。この表の粒度は**コマンド単位でなく「コマンド × early-exit 経路」**まで下げる — 横断的不変条件 (「この条件はあらゆる早期 exit を覆う」型) を新設する計画では、sibling コマンドの既存 early-exit 経路にも同じ不変条件を適用するかを明示する (PR #353 L1: impact に導入した「resourceExhausted は全早期 exit を覆う」パターンが、お手本側 check の既存 early-exit 2 箇所に未適用のまま残った)。
重複計算を single-source 化する計画では、残存する duplicate 呼び出し箇所を全列挙し、削除するか「不整合検出の防御」を付けるかを明記する (PR #353 H2: ingest を scan() に統一した後も残した事前プローブが、統一先と食い違ったとき silent に結果キーが消える TOCTOU になった)。
「ある実行時挙動が起きるか」を判定する新設チェック (設定の有効性判定・保護の有無検査等) は、その挙動を実際に生む本物の評価器 (glob matcher / parser / resolver 等) を合成入力で呼ぶ設計を第一候補にし、文字列形状からの推定 (substring/segment 判定) は避ける (PR #359 H2: 文字列 heuristic は「機能しない除外を保護ありと誤判定」「機能する除外を保護なしと誤判定して実リークを完全沈黙で見逃す」の両方向に破れた。実評価器は既存依存に含まれていることが多く、切り替えコストは低い)。
既存 fail-closed ガード (CI regression guard / lint 禁則 / 許可リスト等) を緩和する計画では、着手前にまず現行パターンで「実際に何が commit 済で違反していたか」を実測し (git ls-files | grep -iE '<FORBIDDEN>' 等)、その結果を設計に織り込む — 実測せずに広く緩和すると、Step 4 レビューで「削除ではなく最小スコープ例外で足りた」と narrow 化を求められる往復コストが発生する (PR #367 HIGH-1: SC-007 の \.codex/hooks は commit 対象 0 件、kiro.*hook は 1 テンプレのみだったが、実測せずパターン全削除で先行し Step 4 で pathspec 除外への narrow を強いられた)。上記の Step 0-pre チェック 8(d) の裏返し — Step 0-pre は緩和の粒度を診断するチェック、Step 1 はその診断結果を設計に織り込む段階。
Step 2: 実装委譲
brief テンプレ (Step 2)
あなたは {{repo}} の実装担当です。issue {{issue}} の実装計画は以下です: {{Step 1 の計画}}。対象ファイル: {{files}}。計画に従い実装し、テストを追加・更新してください。計画にない設計変更が必要になった場合は実装せず報告してください。
brief 作成時の仕様網羅性チェック (Step 0-pre では原理的に検出できない「まだ存在しないコード」の欠陥は、brief の仕様精度で防ぐ):
- 変換/フィルタ関数の出力仕様: ID 解決・degrade・フォールバックを含む関数を計画する場合、「残す/残さない」の判定だけでなく**「残した場合にどの値 (元の値 or 解決後の値) を返すか」まで brief に明記**する。判定に使った解決結果を出力に反映しないと、下流が非実在 ID を観測する類のギャップが生まれる。
- 新規の正当化コメント: 「〜だから安全」「〜は構造的に起きない」等の正当化コメントを追加する実装には、「同ファイル内の既存の不変条件コメントと矛盾しないか確認してから書くこと」を brief に含める。実装エージェントが自分のコードを正当化する説明を創作するリスクへの歯止め。
- Step 0-pre caveat の逐語引用: Step 0-pre report に安全性・境界条件に関する注記 (例外条件・既知の制約) がある場合、brief 作成時に要約・パラフレーズせず該当箇所を逐語引用する。要約は例外条件の脱落を誘発する (orchestrator の転記ロスは実装エージェント側では検出できない)。
- フラグ意味論の不変条件の逐語転記: Step 1 の sibling コマンド契約表で「フラグ (
--force, --strict, --all 等) の意味論を複数 writer/format/経路で対称化する」設計判断が確定した場合、その不変条件 (「全 format で --force は既存ファイルを上書きしない」等) を 1 文の断定形で brief に逐語添付する (「全て対称です」等の要約でなく)。実装エージェントが CLI メッセージ・ドキュメント文字列・エラー remediation を書く際にこの不変条件を手元に持っていれば、"--force" で上書きされるかのような誤誘導文言を自分で弾ける (PR #367 LOW-5: Kiro conflict remediation が "...re-run with --force to let artgraph write its own"と--forceで上書きされるかのような誤誘導になり、file-per-hook writer は--force` を参照しない不変条件と食い違った)。
- コマンド案内の失敗モード: brief が SKILL.md 等の指示書に CLI コマンドの実行案内を書かせる場合、「実行後の exit code / stderr 確認」と「完了後の再検証手順」を brief 自体に明記させる。
- 核心シナリオの結線テスト: issue が問題視した経路そのもの (例: 設定読み込みのフォールバック分岐) は、ユニット直呼びでなく実際の入口 (loadConfig / CLI 等) を通すエンドツーエンド形で最低 1 本テストさせることを brief に明記する。ユニットテストだけだと統合点の結線が壊れても検知できない (PR #359 L1: 全テストが構築済みオブジェクト直渡しで、issue の核心だった
?? フォールバック経路が未検証だった)。
- 否定形テストの到達性: 「〜の場合に警告/エラーが出ない」ことを検証するテストを書かせる場合、テスト入力が検証対象のコードパスを実際に通ることを brief で要求する (前段の parse エラー等で早期 exit する入力だと、アサーションが自明に真になり判別力ゼロのテストになる)。前段エラーだけでなく縮退入力にも注意 — 対象機構の適用機会自体が生まれない入力 (例: 正パターンを持たないパターンリストが prefilter の早期 return を踏み、負パターンが一度も適用されない) も同じく判別力ゼロになる。fixture が対象機構の適用機会を実際に持つことを、同一テスト内の可観測信号 (対照ケースの assert 等) で担保させる (PR #355 M3)。
テスト実行条件の継承監査 (Step 2 / Step 6 共通のセルフチェック 8 番目)
テストの実行条件を変える変更 — it() → beforeAll/beforeEach への移動、describe 本体 → hook、別 suite / 別 config への移動、pool / fileParallelism / retry / env の変更 — は、以下を実行する。ローカルと CI で負荷条件が違うために片方でだけ落ちるクラスを、ループの他のどの段も構造的に拾えない (Step 7 の E2E は実機 CLI を見るのでテストスイートの実行条件を見ない)。
「CI と同じコマンドを回せ」では捕まらない。 判別要因はコマンドではなくランナーの負荷であることが実測されている — ローカルで CI と同一コマンドをコールドキャッシュで回しても全 pass、別 OS の CI job も同じコマンドで pass、という形で片側だけが落ちる。捕まえられるのは静的な問いだけ:
-
移動先が継承する既定値を config ファイルから読み取る。
grep -n 'testTimeout\|hookTimeout\|retry\|pool\|fileParallelism\|env' vitest*.config.ts
config が設定している軸と、設定せず runner の既定に任せている軸を区別する。 未設定の軸へ管轄が移ると budget が黙って縮む。
-
姉妹 config に同じ罠の記録がないか grep する。
git grep -n 'Timeout\|timeout' -- vitest.e2e.config.ts vitest.perf.config.ts
-
所要時間にローカル単体実行の値を使わない。同じ作業をしている既存テストの CI 実測値を使う。 CI ログの per-file 行 (tests/x.test.ts (N tests) NNNNms) がそれ。
-
budget ≥ 4 × CI 実測でなければ明示引数を置く (beforeAll(fn, 120_000))。明示引数は config / CLI の値を上書きするので、config を直すより局所的で安全。
-
判定オラクル (スイープ): pnpm exec vitest run --hookTimeout=<CI 実測の 1.2 倍>。落ちたファイルが「既定に頼っていて実際に遅い hook」。明示引数を置いた後は落ちない。
-
重い作業は hook より it() に置く方を既定にする。 config が curate している軸に乗るため。hook に置く理由 (collection 時 throw を防ぐ、複数 it() で共有する) があるときだけ hook にし、そのとき step 4 の明示引数を必ず付ける。
前例: PR #423 (issue #387) — Step 6 がレビュー指摘の正しい修正として buildGraph(REPO_ROOT) を describe 本体から beforeAll へ移した瞬間、config が curate している軸 (testTimeout: 30000) から curate していない軸 (hookTimeout 未設定 → vitest 既定の 10s) へ管轄が移り、budget が 30s → 10s に縮んだ。ローカル単体実行 2.5s に対し CI (ubuntu) は 12.1s で、Hook timed out in 10000ms が ubuntu の job だけで発生し macOS job は緑だった。同じ罠の記録が vitest.e2e.config.ts に前の PR 由来で逐語であり、同種テストの CI 実測値 12.1s は、落ちた CI ジョブのログの中にそのまま印字されていた。修正後のツリーで step 5 のスイープを --hookTimeout=300 まで振っても 124 ファイル全 pass = このスイープはノイズを出さない。
Step 3: 差分確認 / commit / push / PR 作成
メイン loop が diff を確認し、プロジェクトの規約 (commit 規約 / PR テンプレ / CI ゲート) に従って PR を作る。実装報告の定量主張 (「件数は 0→0 で不変」等) を PR 本文に載せる場合、集計粒度を 1 段変えた再計測 (テスト単位→生ペア単位等) で裏取りしてから載せる — 粗い粒度の「不変」は細かい粒度の大変化 (PR #363 M1: dogfood テスト 0→0 の裏で生ペア 1140→605) を覆い隠し、レビュアーが信頼する数値として独り歩きする。Step 2 実装エージェントの報告に「逸脱」「関連 follow-up」等のフラグがあれば、PR 作成前にメイン loop が直ちに triage し、起票ゲートを通した上で fix now / 別 issue 化 / accept / 起票しない のいずれかを明示する。silent に次 Step へ進めない (検出済みの情報が orchestration 側で握りつぶされるのを防ぐ)。
triage で「fix now」を選んだ項目は、orchestrator が自分で書かない。 Step 2 と同じ形式の brief (対象ファイル / 変更内容 / 該当するセルフチェック項目) を作ってクリーンなサブエージェントに出す。委譲が割に合わない小ささなら、その差分に対して発火するチェックだけを orchestrator が明示的に実行し、実行したチェック番号と結果を PR 本文に書く。
orchestrator 自身が書いた差分は、Step 2 brief のセルフチェック群を 1 つも通らずに PR へ着地する — この経路はループの構造上、レビュー以外のどの層にも捕捉されない。1 行の修正でも、それが「認識規則の受理集合を変える」なら消費者の全数列挙が、「新しい正当化コメント / 断定文を書く」なら反例探索が、「テストを追加する」なら判別オラクルの明記が発火する。
判定オラクル: fix now で入れた差分について「この変更単独で Step 0-pre のどのチェックが発火するか」を 1 行で答えられること。答えが「なし」なら本当に無害。
前例: PR #429 (issue #422) — Step 2 が「認識と書き換えが ATX closing sequence で乖離する。候補修正は 1 行だが計画外なので実装しない」と正しく報告し、orchestrator が Step 3 でその 1 行を自分で入れた。消費者を全数列挙していれば git grep -n '(#+' -- src の 5 行に specDefinitionId が出ていた (実測)。結果、rename --merge が exit 0 で成功を報告しながら spec を半適用し、直後に check --gate が 0→2 になる回帰をその PR 自身が持ち込んだ。同時に添えたテストコメントの「the two sides can disagree here and nowhere else」も実測 12 形状で偽だった。
「全 N 箇所」「他に無い」型の完全性主張を PR 本文・issue・コードコメントに載せる場合、その根拠の横断 grep は NUL バイト入りファイルを無言で除外しないツールで実行する — ripgrep および ripgrep 実装の検索ツールは -l / -c の一覧・件数モードでも既定でバイナリ判定したファイルを結果から落とし、stdout・stderr・exit code のどこにも痕跡を残さない。grep -a / git grep を使うこと。この失敗モードは「検索がヒット 0 件」ではなく「検索対象からファイルごと消える」ため、件数が減ったことに気づく手掛かりが原理的に存在しない (前例: PR #390 が「lastIndexOf は 5 箇所」と書いたが真値は 6 ファイル 7 箇所。無言で落ちた 2 ファイルの片方はその PR 自身が編集していたファイルだった。同種の見落としは PR #376 でも発生しており、「注意する」型の対策では 2 回とも防げていない)。
Step 4: 敵対的レビュー
別のクリーンな Opus 5 に、実装文脈なしで PR diff だけを渡す。
brief テンプレ (Step 4)
あなたは {{repo}} の敵対的レビュアーです。PR {{pr}} の diff を、以下の 7 観点で「壊す」つもりでレビューしてください: (1) 境界条件 (2) 条件分岐の組み合わせ (3) 不正な状態遷移 (4) 例外系 (5) 実運用の事故 (6) エッジケース (7) 考慮漏れ。各 finding にランク (HIGH/MEDIUM/LOW) と再現手順を付けること。褒める必要はありません。
Step 5: 敵対的メタレビュー
さらに別のクリーンな Opus 5 が Step 4 の findings を独立検証する。単なる検証にとどめず、レビューアが生産的だった seam の second-look (横展開探索) を brief に含める — 同じ seam の兄弟箇所に同型欠陥がないかを探索させる。
brief テンプレ (Step 5)
あなたは {{repo}} のメタレビュアーです。PR {{pr}} に対する以下のレビュー findings を独立に検証し、各 finding を 妥当 / 誤検知 / 要追加調査 に分類してください: {{Step 4 findings}}。加えて、妥当な finding が出た seam (同一ファイル・同一パターンの箇所) について、同型の欠陥が他に残っていないか横展開で探索してください。
Step 6: 妥当な指摘の反映
クリーンな Opus 5 に、Step 5 で妥当と判定された findings のみを渡して修正させる。修正指示の brief には、上記「テスト実行条件の継承監査」を Step 2 と同じくセルフチェックとして含める — 正しい修正が副作用でブロッカーを持ち込む経路がここに集中する。
Step 6 が Step 4/5 の測定をやり直して反する結論を出す場合、(a) 使った入力の逐語バイト列を並べて Step 4/5 のものと同一であることを先に示す、(b) 異なるなら「別形状の測定であって訂正ではない」と明記する、(c) 件数が動いた場合は測定範囲 (対象ファイル集合) を併記する。 段間の「訂正」は、実際には別の対象を測っているだけのことが多い (前例: 6 形のうち 2 形を「再現しない」とした訂正は両方とも別 fixture を測っていた / conjunct mutation の「20 件」と「68 件」の差は測定範囲がサブシステム限定かフルスイートかの違いだった)。誤った訂正がそのまま issue の authoritative な NOTE として公開された実例がある。
Step 6 の修正が (a) テストを別の実行文脈へ移す、(b) config / 環境変数を触る、(c) 新しい I/O を導入する のいずれかを含む場合、Step 7 へ進む前に push して CI を 1 回通す。 Step 7 の実機確認は数十分かかるので、その前に数分の CI で潰せるものは潰す。判定は「テスト実行条件の継承監査」step 1 の grep 1 本でつく。
Step 7: E2E 実機確認
クリーンな Opus 5 が、テストではなく実際の入口 (CLI / アプリ / API) から変更後の挙動を確認する。ここで新 finding が出たら Step 4 相当として扱い Step 5 に回す。
Step 8: PR 反映 → CI 監視 → merge
修正を push し、CI green を確認して main へ merge する。merge の実行直前にユーザーに確認する (上記「ユーザー判断のエスカレーション」3)。
Step 9: 振り返り
issue-retro skill を起動する (対象: 本 loop の PR と各 Step の findings)。「Step 4/5/7 が見つけた finding のうち Step 0-pre で検出できたはずのもの」を特定し、プロジェクト側チェックリスト skill への追加を提案する。
出力
- PR URL
- 各 Step の成果物へのポインタ (Step 0-pre report / 設計 / findings 一覧 / E2E 結果)
- Step 9 振り返りレポート
スキップ条件
docs-only など明白に低リスクな変更では Step 0-pre / Step 5 / Step 7 を省略してよい。ただし省略した Step は出力に「skipped (理由)」と明記し、silent skip にしない。