TL;DR(このノードは何をする・専門語ゼロ): 起案された技術判断が 6 ヶ月後に大失敗した前提に立ち、「何が原因で失敗したか」を逆算して書き出す Gate 1 のもう片肺。失敗シナリオは技術・運用・ビジネス/規制・認知の 4 領域から最低 1 件ずつ出すルールで、起こりやすさの目安 probability も付ける。判定はせず、後段の Judge が DA の指摘と一緒にまとめて最終整理する。

実装: drp/src/nodes/socratic.tspmPromise ブロック プロンプト SSoT: prompts/production/gate1-pm/prompt.mdKV デプロイ・ADR-0042 Type 1 出力スキーマ: prompts/production/gate1-pm/output_schema.json テスト: drp/test-tc-socratic.mjs 基盤 ADR: ADR-0071 / ADR-0033 / ADR-0042 / ADR-0056


1. 役割と位置づけ

Gate 1 の 逆算役。半年後の失敗を仮定して原因を逆算するため、DA とは別ベクトルで盲点を露出させる。

  • 解決する課題: 採用判断の時点では見えない「採用後に効いてくる」失敗モードを事前に列挙する。技術的失敗だけでなく、運用・規制・認知バイアスも 4 カテゴリ強制で網羅する。
  • 設計思想: 情報提供型 + カテゴリ強制。1 種類のリスクに偏らないよう、category 列挙を必須化(4 領域それぞれから最低 1 件)。
  • DA との分担: DA は「現在の判断に対する反論」、PM は「採用後 6 ヶ月後の破滅シナリオ」。視点・時間軸が違うため Judge での重複は少ない。
  • 兄弟ノード: 並列に走る Devil's Advocate (DA) と、後段の Judge。本ノードを含む 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
6ヶ月後の失敗シナリオ] DA --> J[gate1-judge
統合・重複排除] PM --> J J -->|socraticPass=true
blindSpotFindings| B[body_generation] style PM fill:#fdd,stroke:#c33

PM と DA は Promise.allSettled で並列実行。PM 単独で失敗しても DA が成功すれば Judge は DA の findings のみで進行する。


3. トリガー条件

条件挙動
triageneedsAdr=true を返した実行
triageneedsAdr=false を返したスキップ — triage が END に飛ばす
blindSpotFindings.length > 0スキップ — 冪等性のため再実行しない

buildPreGraph() には含まれない。buildGraph() / buildGraphWithWebhook() の main graph 内でのみ動く。


4. 入力

State から

State フィールド用途
title任意
context必須。背景・決定内容
options任意。検討した代替案

LLM への user message

Title: {title}                ← title 空なら省略

Context:
{context}

Alternatives considered:      ← options 空なら省略
{options}

DA とは異なり、constitution.yaml 経由の観点ローテーションは行わない。プロンプト本文の「4 カテゴリ強制」が観点の代わりに機能する。


5. 処理ロジック

1. プロンプト取得: loadPrompt(env, 'gate1-pm', PM_FALLBACK_PROMPT)
2. LLM 呼出: claude-sonnet (MODELS.socratic), temperature=0.8, 90s timeout
3. JSON 抽出: parseJson() でコードフェンス除去 + JSON.parse
4. 整形: findings に source='premortem' を付与し、Judge への raw findings として返却
   - PM 独自フィールドの category / probability は raw findings に保持されるが、Judge の出力スキーマには
     直接は載らない(severity と evidence に吸収される設計)。

PM のプロンプトは 4 カテゴリ強制を ルール化しているが、LLM が 4 カテゴリを満たさないこともある。後段の Judge が dedupe / severity 分類で吸収する設計。

4 カテゴリ

category観点
technicalコード・インフラ・性能・セキュリティ起因の失敗
operationalデプロイ・監視・保守・オンコール負荷起因の失敗
business_regulatoryコスト超過・コンプラ違反・ステークホルダー拒否
cognitive埋没費用・確証バイアス・スコープ膨張・早すぎる最適化

probability ラベル

probability意味
likely半年以内に高確率で発生する
possible発生条件が揃えば起きる
unlikely起きにくいが影響が大きいので記録

6. LLM 設定

項目根拠
モデルclaude-sonnet (MODELS.socratic)ADR-0033 — 多様な失敗シナリオ生成のため
temperature0.8ADR-0056 — シナリオ多様性確保。DA より低いのは「4 カテゴリ強制」の制約があるため
maxRetries3createLlm の exponential backoff
timeout90 秒SAMPLE_TIMEOUT_MS
コスト目安約 $0.03 / ADR入出力合計 約 2〜4 KB
レイテンシ10〜30 秒DA と並列実行のため Gate 1 全体は max(DA, PM) + Judge

7. 副作用

なし。LiteLLM Gateway 経由の LLM 呼出のみ。


8. 出力

Judge への raw findings(内部受渡し型)

{
  source: 'premortem',
  title: string,                                // 60 字目安・「(状況) すると、(具体的に何が起きるか)」形式
  severity: 'critical' | 'high' | 'medium' | 'low',
  evidence: string,                             // 最大 3 文
  suggestedAction: string,                      // 動詞始まり 1-2 文
  // 以下は LLM 生 JSON にあるが現状の内部型では Judge 入力時に落ちる:
  // category, probability
}[]                                             // 4 カテゴリ × 最低 1 件

注記: 現実装の pmPromise は category / probability を State 経由では保持しない(socratic.ts 内で source/title/severity/evidence/suggestedAction の 5 項目に絞って rawFindings に積む)。 category / probability は Judge へ JSON 文字列化されて user message 経由で渡されるため、 Judge プロンプト側で必要に応じて参照する。

LLM 生 JSON(PM プロンプト直結の生出力)

{
  "findings": [
    {
      "category": "technical | operational | business_regulatory | cognitive",
      "title": "...",
      "severity": "critical | high | medium | low",
      "probability": "likely | possible | unlikely",
      "evidence": "...",
      "suggested_action": "..."
    }
  ]
}

JSON スキーマは prompts/production/gate1-pm/output_schema.json を SSoT とする。


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

PM は socratic ノード内の Promise.allSettled([daPromise, pmPromise]) で集約される内部処理。LangGraph の addConditionalEdges での分岐はない。

PM 状態次の扱い
成功findings を rawFindings に追加 → Judge へ
失敗DA の findings のみで Judge を実行
DA + PM 両方失敗skip-through — socraticPass=true, blindSpotFindings=[] で body_generation へ

10. エラー時の挙動

障害パターン挙動影響
90s timeoutPromise.race で reject → PM を失敗扱いDA の findings のみで Judge が動く
Gateway 不達maxRetries=3 の exponential backoff 後に reject同上
JSON 以外を返すparseJson が throw → PM を失敗扱い同上
findings 配列欠落`data.findings
4 カテゴリ未充足検出せず通すJudge の dedupe / severity 分類で吸収。週次で category 分布を観測

エラーは event: 'blindspot_node_failed' で構造化ログ出力。


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

  • 4 カテゴリ強制の遵守率: LLM がプロンプト指示を守らず 2-3 カテゴリしか出さないことがある。週次で category 分布を集計し、特定カテゴリ欠落が続けばプロンプトを補強する。
  • category / probability が Judge 出力に直接出ない: 現実装の rawFindings 型では落ちる。観測の都合上、PM 生 JSON のログ出力で残す案は ADR-0102 後の検討事項。
  • 過剰な悲観: temperature 0.8 で「半年後の失敗」を強制するため、severity=critical が増えがち。Judge の dedupe + actionability 分類で抑制。
  • DA との重複: cognitive カテゴリ(確証バイアス・スコープ膨張)は DA の指摘と被ることがある。Judge の source='both' 統合で吸収。
  • 時間軸の固定: 6 ヶ月後を仮定するため、長期構造変更(数年スパンの会計制度改正など)は捉えにくい。長期 ADR では別途検討するか、context で明示する。

12. テストケース

ID内容期待
TC-BS01-PM情報十分な ADR ドラフトfindings.length >= 4 かつ 4 カテゴリそれぞれから最低 1 件
TC-BS02-PMPM API エラー注入event: 'blindspot_node_failed' ログ・DA 単独で Judge が動く
TC-BS-PM-CATcategory 欠落シナリオ観測ログから category 分布の偏りを検出可能

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


13. 過去の設計判断ログ

日時変更経緯
2026-05-27ADR-0071 採択 + PR #1042Socratic を盲点検出 DAG に再定義・PM を新設
2026-05-28プロンプト KV 化(PR #1090)loadPrompt(env, 'gate1-pm', ...) に切替・ADR-0085
2026-05-28temperature を 0.95 (DA 同等) → 0.8 へ4 カテゴリ強制の安定化のため少し下げた
2026-064 カテゴリ強制ルールプロンプト本文で「EXACTLY 4 categories (one per category minimum)」を明文化

14. 関連リンク