基本情報

エレベーターピッチ

  • これは何?  : DA と PM が出した raw findings を統合・重複排除し、severity と actionability を付けて最大 10 件に絞る Gate 1 の最終工程。
  • だれのため? : PR 本文の Blind-spot Report と、後段の body_generation。
  • なにが起きる?: pass/fail 判定はしない。起案者が既に context で触れた論点は捨てる。最終判断は人間に委ねる。
  • 譲れない一線 : actionability=block (決定を覆すレベルの盲点) は極めて稀にしか発行しない。
  • だから    : 重複と既出論点を除いた最大 10 件の盲点 report が、人間レビュアーの最終判断材料になる。

1. 役割と位置づけ

Gate 1 の 統合・分類役。DA と PM の raw findings を入力に、次の 4 つを実施する。

  1. 重複の検出と統合 — 同じ核となる懸念を 1 件にまとめ、dedupe_group を付与
  2. 重要度判定 — severity (critical/high/medium/low)
  3. 対応指示 — actionability (block / revise_adr / add_to_risks / monitor)
  4. 既知の対処済み指摘の除外 — 起案者が既に context で触れた論点は捨てる

最終出力は最大 10 件で、後段の body_generation を経て PR 本文に転記される。

  • 設計思想: 情報提供型actionability=block は「決定を覆すレベルの盲点」に限定し、極めて稀に発行する。pass/fail には使わない。
  • 兄弟ノード: 上流の Devil's AdvocatePre-mortem。本ノードを含む 3 サブノードは LangGraph 上は socratic 1 ノードに統合されている。

2. フロー図

flowchart LR
    T[triage] -->|needsAdr=true| S[socratic 統合ノード]
    S --> DA[gate1-da
Devil's Advocate] S --> PM[gate1-pm
Pre-mortem] DA --> J[gate1-judge
統合・重複排除
最大 10 件 cap] PM --> J J -->|socraticPass=true
blindSpotFindings| B[body_generation] style J fill:#fdd,stroke:#c33

Judge は DA / PM のどちらか片方でも成功すれば実行される。両方失敗時のみ Judge をスキップして空 findings で skip-through。


3. トリガー条件

条件挙動
rawFindings.length > 0(DA か PM の少なくとも一方が成功)実行
rawFindings.length === 0(両方失敗)スキップ — socraticPass=true, blindSpotFindings=[] で skip-through

4. 入力

上流サブノードから

ソース用途
daPromise の戻り値{source: 'devil_advocate', title, severity, evidence, suggestedAction}[]DA の生 findings
pmPromise の戻り値{source: 'premortem', title, severity, evidence, suggestedAction}[]PM の生 findings(PM は更に category / probability を含む)

State から

State フィールド用途
title / context / optionsOriginal proposal として user message 末尾に再添付(除外判定の素材)
triageModeLight の場合 Judge 通過後に cap を発動(§5 step 5)

LLM への user message

[Adversarial findings to judge]
{JSON.stringify(rawFindings, null, 2)}

[Original proposal]
{userInput と同じ整形済み原稿}

5. 処理ロジック

1. rawFindings 集約: settled.filter(fulfilled).flatMap(r.value)
2. 全失敗時は skip-through: socraticPass=true, blindSpotFindings=[]
3. LLM 呼出: claude-sonnet (MODELS.socratic), temperature=0.2, 90s timeout
4. JSON 抽出: parseJson() でコードフェンス除去 + JSON.parse
5. ADR-0102 Light cap (env.LIGHT_GATE1_CAP !== 'false' && triageMode === 'Light'):
   a. dedupeGroup ごとに最重要 1 件を残す
   b. critical/high のみ残す
   c. 重要度順 sort 後、先頭 5 件を採用
6. telemetry 永続化: blindSpotCountRaw, lightCappedToZero
7. State 更新: blindSpotFindings = finalFindings

Judge の判定軸は次の表に従う。

severity意味
criticalシステム全停止級・採用前提を覆す盲点
high主要機能の劣化・撤退条件の不備など
medium回避策あり・要追記レベル
lowコスメティック・経過観察で足りる
actionability意味期待される運用
block決定そのものを差し戻すべき極めて稀。起案者は決定を再検討
revise_adrADR 本文の特定節を書き直すべき起案者が該当節を修正
add_to_risks既知リスク節に追記すべき起案者が Risks セクションに追記
monitor採用後に観測する受理後の運用観点として記録

6. LLM 設定

項目根拠
モデルclaude-sonnet (MODELS.socratic)ADR-0033 — 統合・分類タスクで一貫性重視
temperature0.2ADR-0056 — 分類タスクの安定性確保。同じ raw findings で出力ブレを抑える
maxRetries3createLlm の exponential backoff
timeout90 秒SAMPLE_TIMEOUT_MS
コスト目安約 $0.04 / ADR入力に raw findings JSON + 原稿を抱えるため DA / PM より入力サイズが大きい
レイテンシ10〜30 秒DA + PM 並列実行後の直列ステップ

7. 副作用

なし。LLM 呼出のみ。


8. 出力

State 更新(正常完了)

{
  socraticPass: true,
  socraticQuestions: [],           // 後方互換のため空配列を維持
  blindSpotFindings: [
    {
      source: 'devil_advocate' | 'premortem' | 'both',
      title: string,
      severity: 'critical' | 'high' | 'medium' | 'low',
      actionability: 'block' | 'revise_adr' | 'add_to_risks' | 'monitor',
      evidence: string,
      suggestedAction: string,
      dedupeGroup: string,         // 重複統合用のグループキー
    },
    // ... 最大 10 件、Light 時は更に critical/high 最大 5 件に絞る
  ],
  blindSpotCountRaw: number,       // Light cap 前の件数(観測用)
  lightCappedToZero: boolean,      // Light cap で 0 件になった健全性フラグ
}

LLM 生 JSON

{
  "findings": [
    {
      "source": "devil_advocate | premortem | both",
      "title": "...",
      "severity": "critical | high | medium | low",
      "actionability": "block | revise_adr | add_to_risks | monitor",
      "evidence": "...",
      "suggested_action": "...",
      "dedupe_group": "..."
    }
  ],
  "summary": "1-2 sentence overall assessment"
}

summary は現状 State には保存していないが、観測ログに残す余地あり。

Judge 失敗時の fallback

{
  socraticPass: true,
  socraticQuestions: [],
  blindSpotFindings: rawFindings.map(f => ({
    ...f,
    actionability: 'monitor',      // 一律 monitor で受け流す
    dedupeGroup: f.title,
  })),
  blindSpotCountRaw: rawFindings.length,
  lightCappedToZero: false,
}

9. 分岐(次サブノード)

Judge は socratic ノード内の最終ステップ。LangGraph の addConditionalEdges での分岐はノード境界の socraticPass のみ。

.addConditionalEdges('socratic', (s) => s?.socraticPass ? 'body_generation' : END)
条件次ノード
socraticPass=true(常態)body_generation
socraticPass=false/nullEND(現実装では発生しない)

10. エラー時の挙動

障害パターン挙動影響
90s timeoutPromise.race で reject → catch ブロックで fallbackrawFindings をそのまま使い、actionability=monitor 一律で出力
Gateway 不達maxRetries=3 の exponential backoff 後に fallback同上
JSON 以外を返すparseJson が throw → fallback同上
findings 配列欠落`judged.findings

エラーは event: 'blindspot_judge_failed' で構造化ログ出力。fallback ルートは event: 'blindspot_complete' を出さないため、ダッシュボードでは fallback 率を blindspot_judge_failed / 起案数 で観測する。


11. 既知の弱点・運用注意

  • severity 誤分類: temperature 0.2 でも medium ↔ high の振れは観測される。actionability=block を稀にする運用と「最終判断は人間」設計で吸収。
  • 既知対処の見落とし: 「context で既に触れている」判定は LLM 任せ。proposal の表現と raw finding の表現がズレると除外漏れが起きる。
  • Light cap の副作用: critical/high が 0 件だと lightCappedToZero=true で出力ゼロ。連続発生は健全性アラート対象(DA/PM が medium ばかり出している可能性)。
  • blindSpotCountRaw 観測: cap 前件数を telemetry に永続化(ADR-0102 フェーズ③ Confirmation #6)。Light モードで raw が多いのに cap 後ゼロが続く場合は Light 判定の妥当性を再検討する。
  • block 濫用の早期検知: actionability=block の発行率は週次でモニタする。LLM の挙動変化で増えたら ADR-0102 / プロンプト見直し。
  • dedupe_group の粒度: LLM が同じ概念に違うキーを振ると同種が複数残る。週次で重複検出して dedupe ルールを補強する。

12. テストケース

ID内容期待
TC-BS01-JDA 4 件 + PM 4 件を入力findings.length <= 10dedupe_group 重複の自動マージ確認
TC-BS02-JJudge API エラー注入fallback 経路で actionability='monitor' 一律出力、event: 'blindspot_judge_failed'
TC-BS-LIGHTtriageMode='Light' で critical/high が 6 件以上cap 後 5 件・blindSpotCountRaw は cap 前件数
TC-BS-CAP0triageMode='Light' で critical/high が 0 件cap 後 0 件・lightCappedToZero=true

実行: node drp/test-tc-socratic.mjs


13. 過去の設計判断ログ

日時変更経緯
2026-05-27ADR-0071 採択 + PR #1042Judge を Gate 1 の最終工程として新設
2026-05-28プロンプト KV 化(PR #1090)loadPrompt(env, 'gate1-judge', ...) に切替・ADR-0085
2026-06ADR-0102 フェーズ③Light モードで critical/high のみ最大 5 件に cap・blindSpotCountRaw / lightCappedToZero 永続化
2026-06fallback 経路の actionability='monitor' 一律化Judge 失敗時に重大判定を勝手に付けない方針を明文化

14. 関連リンク