shakedown
実装者本人の盲点を突くための QA ランブックを生成する。対象は自動テストが構造的に拾えない欠陥である: 初見の操作者だけが引っかかる UI 挙動、本番で一度も実行されたことのない経路、非同期ジョブのスケール限界、使用中データへの破壊的操作。
成果物は文書だが、このスキルの責任範囲は文書生成で終わらない。QA の失敗は「文書に書いた」と「実際に実行・追跡される」の間のギャップで起きる。だから「Blocking 項目を実装者以外が実行する割り当て」と「発見した問題の Issue 化導線」までを文書構造として縛る。
原則(全 Step を支配する)
- 接地(anchor)必須: すべてのシナリオは diff のハンク、コードの file:line、または設計ドキュメントのセクションを根拠として引用する。LLM 生成テストの最大の失敗要因は「仕様に存在しない挙動の発明」であり、anchor はその防壁である。**Blocking は実在する anchor を必須とし、
[unanchored]のまま Blocking タグで合意ゲートに出さない。**接地できないが重要な横断リスク(キャッシュ不整合、下流消費者への影響など)は削除せず、タグを Should-verify に落として anchor 欄に[unanchored]と明記し、合意ゲートで見えるようにする。UI 要素(ボタン名・ラベル・遷移先)はソースに実在する文字列だけを引用する。見ていない要素の名前を発明しない。 - 反証可能な期待結果: 「正しく動作すること」のような失敗しようがない期待結果を書かない。観測可能な状態(表示文言、遷移先、DB 行、ログ行、レスポンス)を名指しする。失敗しえない項目は存在価値がないので削除する。
- 数値リスクスコアを出さない: 影響度・発生確率・可逆性・頻度は優先度タグを決める内部ヒューリスティックとして使い、出力は 1 行の監査可能な根拠にする(例:
Blocking — 不可逆(本番クーポンを直接更新する)・ゴールデンパス上)。人は文には反論できるが3×4×2=24には反論できない。不可逆な副作用を持つシナリオは他の要素に関わらず自動的に Blocking とする。 - やりすぎない: 「念のため」のシナリオを許容しない。すべてのシナリオはリスク根拠に紐づく。Blocking は最大 7 件(超えたら統合か降格を強制する。この圧力自体が品質を上げる)。マップは 15 ノード以内。該当しない機能タイプの観点は出さない。
- 合意ゲート後は formatting, not authoring: Step 7 は Step 6 までに提示・合意された事実だけを整形する。最終文書の生成中に新しいシナリオ・手順・制約を初出させない。
- 簡潔な文体で書く: 生成するすべての文書で括弧書きを避ける。補足したいことは本文の文として書くか、書く価値がなければ削る。1 シナリオ 1 文、チェックリスト項目は最短の文で書く。長い文書は読まれず、読まれないランブックは偽の安心を生む。
Step 1: 入力の解決
$ARGUMENTS を解釈する:
| 入力 | 取得方法 |
|---|---|
| PR 番号・PR URL | gh pr diff <n> + gh pr view <n> --json title,body,files |
diff 範囲(main..feature 等) |
git diff <range> |
.md パス |
design doc / 実装計画として Read する。diff は git diff origin/main...HEAD で補完する |
| 引数なし | git diff origin/main...HEAD。origin/main がなければ git symbolic-ref refs/remotes/origin/HEAD または gh repo view --json defaultBranchRef -q .defaultBranchRef.name でデフォルトブランチを特定し、そのブランチとの diff を取る |
ticket <ID> |
保存ファイル名と関連ドキュメント探索に使う |
- diff と設計ドキュメントの両方が得られない場合のみ停止し、対象の指定を求める。
.mdパスが指定され設計ドキュメントとして読み込めた場合は、diff が空でも Step 2 以降に進む。 - 文書にスタンプする基準 SHA を確定する。ブランチ作業なら
git rev-parse HEAD。PR を対象にする場合はgh pr view <n> --json headRefOidで取得した PR head の SHA を基準とし、anchor の file:line もこの SHA 時点の内容をgit show <SHA>:<path>で照合する。マージ後に main が先行していても、現在のファイル状態と混同しない。 - 基準 SHA より後の変更が対象の前提を覆していると気づいた場合は、黙って続行せず、その事実を [要確認] として Step 6 の合意ゲートで提示する。
- 変更に関連する design doc / 実装計画がリポジトリ内にあるか軽く探索する(
docs/配下をチケット ID・変更ディレクトリ名で rg)。あれば読む。diff とドキュメントの矛盾を見つけたら、それ自体を Blocking シナリオにする(「doc は X と言い、コードは Y をしている。どちらが意図か確認する」)。矛盾シナリオの期待結果は「どちらが正か判断され、正でない側の修正方針が記録されること」とする。doc を正と決めつけない。PRD や Figma は前提にしない(パスや URL が渡されたら補助情報として使ってよい)。
Step 2: 機能タイプの推定
diff のパスと内容から該当タイプを推定する(複数該当あり)。判定シグナルの詳細と各タイプの重点観点は references/viewpoints.md の該当セクションだけを読む。
| タイプ | 典型シグナル |
|---|---|
| カスタマー向け UI | mobile 系、顧客向け web ディレクトリ |
| 内部運用者向け管理画面 | ope / admin / internal 系 web ディレクトリ |
| 純バックエンド / API | server / services、proto・GraphQL 契約のみの変更 |
| 非同期 / バッチジョブ | jobs / batch ディレクトリ、*_job* ファイル、scheduler・cron 定義 |
| フィーチャーフラグ配下 | フラグ定義(環境変数 FEATURE_FLAG_* 等)の追加・変更・参照 |
リポジトリに .github/labeler.yml があればパス分類の正解表として参照する。
判定が曖昧な場合、およびリスク許容度など後の判断が割れそうな点は、ここで 1 回だけ AskUserQuestion にまとめて聞く(Step 6 の合意ゲートとは別。以降の Step に質問を分散させない)。自明なら聞かずに進む。
Step 3: 第 1 層 — クリティカルパス分析(毎回必須)
変更が影響する導線のマクロ構造を作る。これは描画物ではなく分析であり、フローが単純でも省略しない。
- ゴールデンパス 1 本: この変更の価値が通る主要導線を、ユーザーに見える操作・判断点の粒度で書く(画面単位でも内部状態単位でもない。マップの目的は検証対象の選択であってアーキテクチャ文書ではない)。
- リスク分岐: 各分岐点で最もリスクの高い分岐だけを追加する。全分岐網羅をしない。
- 隠れた導線: 「本番で一度も実行されたことのない経路」(新設の操作種別、create に対する delete などミラー方向の未検証側)をコードから探し、見つけたらマークする。
- 検証責任の切り分け表: 観点ごとに「自動テストで固定済み / 手動 QA 必須 / どちらにも落ちていない」を表にする。「Unit/E2E でカバーする前提」と書く場合は、そのテストが実在することを確認してから書く。実在しなければ「どちらにも落ちていない」に置く。この欄が空でないことが、検証責任の穴(どこにも落ちない境界値バグ)を防ぐ。
描画形式は分岐の実在で切り替える:
- 分岐が 2 つ以上ある → Mermaid
flowchart LR。15 ノード以内。diff が触るノードをclassDef changedでマークし、リスク分岐ノードには第 2 層のシナリオ ID(S1, S2, …)を添える。ノードラベル内の"は#quot;と書く(生の"はラベルを終端させ、\"は Mermaid が解釈できず描画が壊れる)。 - 線形フロー(小さな diff の大半) → Mermaid を使わず番号付きステップリストにする。分岐のない flowchart は装飾であり、読む価値を生まない。
Step 4: 第 2 層 — シナリオ候補の洗い出し
references/viewpoints.md の共通セクションと該当機能タイプのセクションを適用し、シナリオ候補の全量を作る。
各シナリオは 1 行で書く:
S<n> [タグ] <シナリオ名> — <1行根拠> — anchor: <file:line | docセクション>
タグは 3 種:
[Blocking]— 失敗したらリリースを止める。最大 7 件。anchor は file:line か doc セクションが実在すること必須。接地できなければ Blocking にしない。[Should-verify]— 確認すべきだが単独ではリリースを止めない。接地できない重要な横断リスクはここに置き、anchor 欄に[unanchored]と書く。[Wont-verify]— 意図的に検証しない。理由必須(この diff のスコープ外 / 自動テスト済み(テストへの参照付き) / コストがリスクを上回る)。これは優先度ではなくスコープ決定である。「検証しないと決めたものの一覧」こそユーザーが本当に承認する対象なので、雑に書かない。
ルール:
- 1 シナリオ = 1 ゴール・1 フロー。
- 不可逆な副作用(本番データ書き換え、外部 API での発行・課金、通知送信)を持つものは自動的に Blocking。ただし anchor が実在しない限り Blocking タグは付けない。
- 第 1 層の分岐ノードとシナリオ ID を相互参照させる。
Step 5: anchor 検証(Blocking のみ)
合意ゲートに出す前に、Blocking シナリオの捏造を独立した目で潰す。Agent ツールで読み取り専用のサブエージェントを 1 体起動し、対象リポジトリのパス・基準 SHA・Blocking シナリオの一覧を渡して次を依頼する。subagent_type: fork は使わない — fork は親の会話履歴をそのまま継承するため、シナリオを作った本人の判断を引き継いでしまい、独立検証の意味がなくなる:
以下の各シナリオについて、根拠(anchor)が実在するか反証を試みよ。anchor の file:line を実際に読み、引用された UI 文字列・関数・分岐が存在するか、シナリオの前提が diff の内容と整合するかを確認する。存在しない・diff と無関係なら REFUTED とし、理由を返す。
REFUTED が返った Blocking シナリオは、再アンカーして Blocking のまま残すか、再アンカーできなければ Should-verify に格下げして anchor 欄に [unanchored] と明記し、合意ゲートで見えるようにする。Blocking タグのまま [unanchored] で通過させない。黙って握り潰さない。
この検証を実施した日付と結果(全件 VERIFIED、または REFUTED の件数と対応)を、Step 7 で生成するランブックの概要表に 1 行で記録する。ランブック本体に検証の実施記録を残すことで、捏造ゼロの主張を成果物単体で確認できるようにする。
Step 6: 合意ゲート
以下を提示する。明示的な確認対象は Blocking と Wont-verify のみとする。ゲートは 1 分で読める量に保つ — 全量を確認対象にすると締切下で読まれなくなり、未読の承認が「合意済み」を偽装する。Should-verify は一覧表示するが既定承認とし、ユーザーは自由に追加・削除・タグ変更できる。
## shakedown 合意確認
### 対象
- diff: <SHA>, <base>...<head> / 機能タイプ: <types>
### Blocking <n> 件 — 要確認
- S1 <名前> — <1行根拠> — anchor: <file:line>
- ...
### Wont-verify <n> 件 — 要確認
- S8 <名前> — 理由: <理由>
- ...
### Should-verify <n> 件 — 既定承認・編集可
- S4 <名前> — <1行根拠>
- ...
### Blocking の一次実行者
Blocking は実装者以外の実行を推奨する。実装者は自分のコードのメンタルモデルを
既に持っているため、初見の操作者だけが引っかかる欠陥を構造的に見落とす。
生成するチェックリストはそのまま 15 分のデスクチェック台本として渡せる。
- 実行者: [要確認]
- 実装者本人しかいない場合はその旨と、実装から時間を置いて実行する宣言を記録する。
この構成でランブック生成に進んでよいですか。追加・削除・タグ変更・実行者の指定があれば教えてください。
End your response here and wait for the user's reply. Do not proceed to Step 7 until approval is received.
修正依頼があれば反映し、変更点だけを再提示して再度承認を待つ。
Step 7: 第 3 層 — ランブック生成と保存
references/template.md のテンプレートに、合意済みの内容だけを流し込む(formatting, not authoring)。
- Blocking = READ-DO 形式: 前提条件・番号付き手順・反証可能な期待結果・実行者・証跡欄を持ち、初見の他者が質問なしで実行できる自己完結性にする。
- Should-verify = DO-CONFIRM 形式: 1 行確認のチェックボックス。証跡不要。この形式差だけで文書の重さが半分以下になる。
- pass/fail に落ちない観察の置き場: 仕様どおりだが危険に見える挙動、判断を要する気づきは、チェック項目にせず問題台帳に種別「懸念」で記録する。チェックリストは二値で判定できる項目だけで構成する。
- メタ情報を発明しない: 実施環境・実装者名など生成時に確定できない概要表の項目は、値を推測せず [要確認] のまま残す。
- 問題台帳: 台帳直下に「問題を発見したらその場で create-github-issues スキルにより機能 Epic の Sub-issue として起票し、Issue 番号を台帳に記録する。自由記述のまま放置しない」という導線を明記する。
- 確認完了(sign-off): 完了基準を測定可能な形で埋め込む — Blocking 失敗 0 件、問題台帳に Issue 番号が空欄の行が 0 件、Blocking 実行者が記名済み。満たされない限り完了にできない旨をルールとして文書自体に書く。
- SHA スタンプ: 概要表に生成時 SHA を記録し、「HEAD がこの SHA から動いたら本ランブックは陳腐化している。再生成すること」の注記を入れる。実行されない古い計画書ほど危険な偽の安心はない。
- 再ベースライン: 同一チケットの旧ランブックが保存先に既にある場合、新版に「なぜ作り直すのか」節(旧実装と現行実装の差分表、旧版の結果のうち無効になったものの明示)を必ず設け、旧版の冒頭に新版へのリンクと陳腐化の注記を追記する。
保存先: docs/qa/shakedowns/<YYYYMMDD>-<チケットID or slug>-shakedown.md。ディレクトリがなければ mkdir -p で作成する。チケット ID がない場合の slug は変更内容を表す kebab-case の英小文字とする。例: coupon-admin-deactivation。
保存後、パスと次のアクション(Blocking 実行者への引き渡し)を報告して終了する。
棲み分け
- tdd-test-cases: 単体〜結合レベルのテストケース列挙はそちらが担当。第 1 層の切り分け表で「自動テストで固定すべきだがテストがない」と判明した観点は、本スキルで抱え込まず tdd-test-cases に回すことを報告に含める。
- /self-qa(対象リポジトリのコマンド): PRD(Notion)+ Figma 起点のチェックリスト生成。本スキルは拡張も置換もしない。出力形式・保存先も共有しない。
- 本スキルが出すのは「人間が実際に手を動かして変更を揺さぶる実行計画書」であり、自動テストの代替ではない。