skeptical-triage について
Skeptical Triageは、レビューやセキュリティ監査、QA回帰、アーキテクチャ判断における重大な指摘を再検証するスキルです。証拠を重視した3回のレビューと中立的な裁定者が、最終判断と信頼度を示します。
主な機能
- 01順次行う3回のレビュー
- 02引用された防御策の証拠確認
- 03中立的な最終裁定者
- 04投票に基づく信頼度スコア
- 05追記専用のトリアージログ
活用シーン
- 01セキュリティレビューの誤検知候補を選別
- 02テスト失敗が不安定か回帰かを判定
- 03アーキテクチャ上の選択肢の対立を整理
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ avelikiy/ great_cto --skill skeptical-triageインストール後、Claude Code で/skeptical-triageを入力して読み込まれたか確認します。
詳細
Skeptical Triage
多角的なレビュー、セキュリティ監査、QA のリグレッション判定、または重大な判断がブロッカーになる前に、誤検知を除外します。
懐疑的なセルフレビューを3ラウンド実施し、公平な裁定者が投票から信頼度スコアを算出します。
呼び出すタイミング
| 呼び出し元 | 指摘の種類 | トリアージを適用するか? |
|---|---|---|
/review | 角度2/4/7/9のP0/P1(セキュリティ、SQL、プライバシー、並行性) | はい |
/review --deep | すべての角度のP0/P1 | はい |
security-officer | CSO 監査のP0/P1 | はい |
security-officer | ソース/git内のシークレット、確認済みのCVE | いいえ — 確定した指摘 |
qa-engineer | 不安定なテストの判定(リグレッションか、不安定なテストか?) | はい |
architect | ADR のトレードオフに関する論争(両方妥当に見える場合の選択肢A対B) | はい |
| すべて | P2/助言的な指摘 | いいえ |
4ステップのパターン
順番に実行します。各ラウンドでは、それまでの推論を確認します。裁定者はすべてのラウンドを確認します。
ラウンド1 — 到達可能性/前提
質問:前提は正しいですか?
- セキュリティ/信頼性の場合:信頼できない入力を使って、外部の攻撃者がこのコードパスに到達できますか?バグの箇所から入力元まで、入力フローを逆方向にたどってください。信頼できる内部呼び出し元しかない場合は、INVALID 寄りと判断します。
- リグレッションの場合:対象ブランチで、クリーンな状態から問題の挙動を再現できますか?
- ADR のトレードオフの場合:選択を迫る制約は、実際に選択を拘束していますか?(例:「p99 を10ms未満にする必要がある」—これは実際の要件ですか、それとも単なる目標ですか?)
出力:{round: 1, verdict: VALID|INVALID|UNCERTAIN, reasoning: "...", crux: "単一の重要な事実"}
ラウンド2 — 引用された防御策/反証を検証
質問:主張されている防御策は実在し、十分ですか?
- 引用された防御策はすべて、
Grepを使って実際の実装箇所を探します。 - 定数名を数値に解決します。
MAX_BUF_SIZEは検証済みの上限ではありません。#define MAX_BUF_SIZE 64なら検証済みです。 - リグレッションの場合:「テストでカバーされている」という主張は、実際に適切な不変条件を検証していますか?
- ADR の場合:引用されたベンチマーク/先例は実在しますか(grep で検索し、内容を確認してください)。それとも単なる噂ですか?
防御策を適用する行を示せない場合、その防御策は存在しません。
出力:同じ JSON 形式で、grep_used: true/false を追加します。
ラウンド3 — 見落とした観点
質問:ラウンド1〜2で考慮されなかった点は何ですか?
- エラーパス、整数オーバーフロー、競合が起きるタイミング、異なる呼び出し元、プラットフォーム間の違い
- 以前のラウンドの内容を繰り返さないでください。新たな証拠を追加するか、認めてください。
- QA の場合:リトライロジックが失敗を隠していませんか?別のテストによるテスト汚染はありませんか?
- ADR の場合:どちらのレビュアーも挙げなかった選択肢Cはありませんか?
出力:同じ JSON 形式です。
裁定者
入力:3ラウンドすべての内容+元の指摘/質問+ソースコード。
質問:最終判断 — どちらの側の証拠がより強いですか?
- 単一の
verdict: VALID|INVALIDを出します(UNCERTAIN は不可。必ず判断してください)。 - 1文の
cruxを出します。これは判断を左右する重要な事実です。 - それまでの3ラウンドがすべて同じ結論の場合、圧倒的な新証拠があるときに限り結論を覆し、その理由を説明してください。
出力:
{
"verdict": "VALID",
"crux": "memcpy at auth.c:142 copies network-controlled len bytes into 64-byte stack buffer with no bound check",
"reasoning": "Rounds 1 and 3 verified attacker reach; Round 2 found no size check in 50 LOC radius; arbiter confirms no caller clamps len."
}
厳守事項
各ラウンドのプロンプトに、以下を必ず含めてください。
- 防御策が存在しない場合 → UNCERTAIN ではなく VALID。 防御策を検索して見つからなかったなら、それが答えです。「おそらく別のコードが処理している」は有効な防御策ではありません。
- 定数名は検証済みの上限ではありません。解決された値だけが検証済みです。
#define/constの宣言を grep してください。 - 行を示せないものは存在しません。 「このコードベースの前提」などの曖昧な参照は認められません。
- 同じ回答内で、自分の結論と矛盾しないでください。 防御策が不十分だと検証できたなら、それが判定です。結論を覆す理由を探すのはやめてください。
- コード品質の問題 ≠ セキュリティ脆弱性。 診断状態のデータ競合、内部専用 API の NULL チェック、デバッグビルドでのみ発生する UB → INVALID。
- 自分の推論を信頼してください。 最初に読んだ時点で要点が分かったなら、反論を無理に作り出さないでください。
確信度スコア
confidence = valid_rounds_before_arbiter / 3
100%(VVV)— 3/3 ラウンドで VALID です。新たな情報が見つからない限り、裁定者はそのまま承認します。67%(VVI または VIV または IVV)— VALID が多数です。裁定者は新たな根拠に基づいて判断します。33%(IIV または IVI または VII)— INVALID が多数です。裁定者は通常、INVALID を確認します。0%(III)— 3/3 ラウンドで INVALID です。裁定者が覆すことはほとんどありません。
裁定者は最終判定を覆すことがあります。確信度は、透明性を確保するためラウンドの投票を反映します。裁定者が異なる判断を下した箇所を人が確認できるよう、出力には両方を記録してください。
トリアージ結果を重大度に反映する
裁定者が判定を返したら、次のように処理します。
| 裁定者の判定 | 確信度 | 重大度への対応 |
|---|---|---|
VALID | ≥ 50% | 元の重大度を維持 |
VALID | < 50% | 引き下げる:P0→P1、P1→P2 |
INVALID | 任意 | ゲートの集計から除外し、監査用レポートに [FILTERED] として記録 |
UNCERTAIN(裁定者が判断できなかった場合のみ) | n/a | 元の重大度を維持し、CTO による手動レビューのためフラグを設定 |
出力スキーマ
すべての呼び出し元は、トリアージ結果を .great_cto/triage-log.jsonl に記録します(追記のみ、1 行につき JSON 1 件)。
{
"timestamp": "2026-04-19T12:34:56Z",
"caller": "review|security-officer|qa-engineer|architect",
"finding_id": "SEC-042",
"file": "src/auth.c:142",
"original_severity": "P0",
"rounds": [
{"round": 1, "verdict": "VALID", "crux": "..."},
{"round": 2, "verdict": "VALID", "crux": "...", "grep_used": true},
{"round": 3, "verdict": "INVALID", "crux": "..."}
],
"arbiter": {"verdict": "VALID", "crux": "..."},
"confidence": 0.67,
"final_severity": "P0"
}
このログを使って、トリアージが効果を上げているかどうかを測定します。毎週確認してください。
# False-positive rate: how many findings the arbiter flipped to INVALID
jq 'select(.arbiter.verdict=="INVALID")' .great_cto/triage-log.jsonl | wc -l
# Average rounds-to-consensus (did we need all 3 or did R1+R2 agree?)
jq '[.rounds[].verdict] | unique | length' .great_cto/triage-log.jsonl
FP 率が 50 回のトリアージ後に 10% 未満なら、トリアージによって、そもそも存在しなかったノイズを除去しています。しきい値を下げるか、その観点ではトリアージを省略してください。FP 率が 40% を超える場合は、元のレビュー用プロンプトが過剰に検出しています。観点のルールを厳しくしてください。
トークン予算
トリアージ対象の指摘 1 件あたり、約 4 回の LLM ターン(3 ラウンド+裁定者)です。一般的なレビュー規模(PR あたりトリアージ対象が約 5~10 件)では、合計予算は /review あたり 20~40 ターンの追加です。可能な場合はまとめて処理してください。論点が互いに独立していれば、1 回の呼び出しで 1 人の裁定者が複数の指摘を処理できます。
コストを重視する実行(巨大な PR で approval-level: auto を指定する場合)では、P0 のみをトリアージし、P1 はトリアージしないことを検討してください。.great_cto/triage-log.jsonl のデータに基づいて再調整してください。
アンチパターン
- P2/参考情報の指摘をトリアージしないでください。 目的はゲートの判断です。P2 は参考情報なので、作成者に提示して次に進んでください。
- 各ラウンドで同じ議論を繰り返させないでください。 ラウンド 3 のプロンプトには「新たな根拠を追加するか、認めること」と明記してください。3 ラウンドで同じ推論が繰り返されたなら、2 ターン分を無駄にしています。
- UNCERTAIN の場合に裁定者を省略しないでください。 3 ラウンドすべてが UNCERTAIN なら、裁定者の役割は霧の中に加わることではなく、判断を下すことです。
- 裁定者による覆しを隠さないでください。 裁定者が多数決を覆した場合は、投票を示す
confidenceと裁定者の判定を示すfinal_verdictの両方を記録してください。人が意見の相違を確認できるようにしてください。