最終更新: 2026/07/02 07:01
22. Gate 1 — Judge / Aggregator サブノード
基本情報
- 英語名 : Judge / Aggregator
- 位置 : Gate 1 サブノード (socratic 統合ノード内、DA + PM の下流)
- 状態 : Production
- 実装 :
drp/src/nodes/socratic.ts内 Judge ブロック- プロンプト SSoT:
prompts/production/gate1-judge/prompt.md— KV デプロイ・ADR-0042 Type 1- 出力スキーマ :
prompts/production/gate1-judge/output_schema.json(maxItems: 10)- テスト :
drp/test-tc-socratic.mjs- 基盤 ADR : ADR-0071 / ADR-0033 / ADR-0042 / ADR-0102
- 変更履歴 : このページ
エレベーターピッチ
- これは何? : 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 件にまとめ、
dedupe_groupを付与 - 重要度判定 —
severity(critical/high/medium/low) - 対応指示 —
actionability(block / revise_adr / add_to_risks / monitor) - 既知の対処済み指摘の除外 — 起案者が既に context で触れた論点は捨てる
最終出力は最大 10 件で、後段の body_generation を経て PR 本文に転記される。
- 設計思想: 情報提供型。
actionability=blockは「決定を覆すレベルの盲点」に限定し、極めて稀に発行する。pass/fail には使わない。 - 兄弟ノード: 上流の Devil's Advocate と Pre-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 / options | Original proposal として user message 末尾に再添付(除外判定の素材) |
triageMode | Light の場合 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_adr | ADR 本文の特定節を書き直すべき | 起案者が該当節を修正 |
| add_to_risks | 既知リスク節に追記すべき | 起案者が Risks セクションに追記 |
| monitor | 採用後に観測する | 受理後の運用観点として記録 |
6. LLM 設定
| 項目 | 値 | 根拠 |
|---|---|---|
| モデル | claude-sonnet (MODELS.socratic) | ADR-0033 — 統合・分類タスクで一貫性重視 |
| temperature | 0.2 | ADR-0056 — 分類タスクの安定性確保。同じ raw findings で出力ブレを抑える |
| maxRetries | 3 | createLlm の exponential backoff |
| timeout | 90 秒 | 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/null | END(現実装では発生しない) |
10. エラー時の挙動
| 障害パターン | 挙動 | 影響 |
|---|---|---|
| 90s timeout | Promise.race で reject → catch ブロックで fallback | rawFindings をそのまま使い、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-J | DA 4 件 + PM 4 件を入力 | findings.length <= 10、dedupe_group 重複の自動マージ確認 |
| TC-BS02-J | Judge API エラー注入 | fallback 経路で actionability='monitor' 一律出力、event: 'blindspot_judge_failed' |
| TC-BS-LIGHT | triageMode='Light' で critical/high が 6 件以上 | cap 後 5 件・blindSpotCountRaw は cap 前件数 |
| TC-BS-CAP0 | triageMode='Light' で critical/high が 0 件 | cap 後 0 件・lightCappedToZero=true |
実行: node drp/test-tc-socratic.mjs
13. 過去の設計判断ログ
| 日時 | 変更 | 経緯 |
|---|---|---|
| 2026-05-27 | ADR-0071 採択 + PR #1042 | Judge を Gate 1 の最終工程として新設 |
| 2026-05-28 | プロンプト KV 化(PR #1090) | loadPrompt(env, 'gate1-judge', ...) に切替・ADR-0085 |
| 2026-06 | ADR-0102 フェーズ③ | Light モードで critical/high のみ最大 5 件に cap・blindSpotCountRaw / lightCappedToZero 永続化 |
| 2026-06 | fallback 経路の actionability='monitor' 一律化 | Judge 失敗時に重大判定を勝手に付けない方針を明文化 |
14. 関連リンク
- 上位ノード: 02_socratic.md — Gate 1 統合ノード
- 兄弟サブノード: 21_gate1_da.md / 23_gate1_pm.md
- 前ノード: 01_triage.md
- 次ノード: 03_body_generation.md
- プロンプト SSoT:
prompts/production/gate1-judge/ - State 定義:
drp/src/state.ts - グラフ定義:
drp/src/graph.ts - 関連 ADR: