12. Problem Space Pregate Node (Gate 0a)
TL;DR(このノードは何をする・専門語ゼロ): 受け取った起案が「1 つの決定」になっているかを入口でチェックする。複数の独立した決定が混ざっていたり、外へ送り出した課題の行き先が書かれていなかったら差し戻す。判定は LLM ではなくコードが下し、根拠は本文からの逐語引用と機械照合する。
実装:
drp/src/nodes/problem_space_pregate.ts判定コード (pure module):drp/src/nodes/problem_space_decide.tsプロンプト SSoT (KV デプロイ):prompts/production/gate0a-pregate-primary/prompt.mdとprompts/production/gate0a-pregate-secondary/prompt.mdmigrate:drp/migrate-v11-pregate.sql基盤 ADR: ADR-0142 位置づけ: triage → recall_pre_gate → abc_screen → cost_gate → problem_space_pregate → socratic 本番稼働: 2026-06-15
1. 役割と位置づけ
② 受付層は静的 4 検査だけで分析の意味検査が空白だった。本ノードは「起案が単一の決定として成立しているか」を 2 段判定で機械検査する。
- 解決する課題: 分析が崩れた起案(複数の決定が 1 本にまとまっている・外へ送った前提の行き先がない)が、受理後の人手対話まで検出されない問題。多重却下 ADR 7 本中 7 本がこの型の盲点移動を起こしていた。
- 設計思想: 2 段判定で受付コストを抑える。一次は軽量モデルで疑いを高再現で拾い、疑いがあるときだけ二次の構造化分解へ送る。
- 判定の置き場所: LLM は意味分類と逐語抽出だけを担い、A/B/C 確定や塊判定はコードが下す。ADR-0142 同型の
#reliable設計。 - 由来: ADR-0142 (Existence/Executive・Standard・2026-06-12 受理)。
2. フロー図
flowchart LR
CG[cost_gate] -->|rejected=false| P1[一次フィルタ
gemini-flash]
P1 -->|suspect=false| S[socratic]
P1 -->|suspect=true| P2[二次 IBIS 分解
claude-sonnet]
P2 -->|decide PASS| S
P2 -->|decide INVALID| S
P2 -->|decide FAIL| E[END 差戻し
pre-gate-block]
3. トリガー条件
| エントリポイント | 起動グラフ | 説明 |
|---|---|---|
POST /draft (フォーム再送信型) | buildGraphWithWebhook | cost_gate 通過後に実行 |
POST /chat/run (チャット型・full) | buildGraph | webhook を除く full pipeline |
スキップ条件:
- 既に判定済み (
state.pregateVerdict != null) は冪等化で no-op。 - env
PREGATE_ENABLED=falseで素通し。state はPASSを入れる。
buildPreGraph (チャット型・triage のみ) では実行されない。
4. 入力 (State)
| State フィールド | 型 | 必須 | 用途 |
|---|---|---|---|
title | string | 任意 | 起案タイトル |
context | string | 必須 | 背景・目的の自由記述 |
options | string | 任意 | 検討した代替案 |
プロンプトに渡す形式は triage と同形。buildPregateInput() が組み立てる。
タイトル: {title} ← title が空なら省略
背景・目的:
{context}
検討した代替案: ← options が空なら省略
{options}
逐語照合は本テキスト全体を対象にする。
5. 処理ロジック
0. 冪等化: state.pregateVerdict が決定済みなら no-op
1. env PREGATE_ENABLED='false' なら素通し (PASS で state 注入)
2. 一次プロンプト (gate0a-pregate-primary) を KV から取得し gemini-flash で 1 call
- 出力: 5 シグナル (independence_reversibility / decision_drivers / approvers /
rollback_kpi / type_crossing) と dangling_premise_suspected を boolean+逐語引用で
- 総合判定 suspect_multiple = いずれかが branched=true、または dangling 疑いあり
- parse 失敗時は安全側に倒し suspect=true として二次へ送る
3. suspect=false なら PASS で終了 (LLM 1 call で完了)
4. suspect=true → 二次プロンプト (gate0a-pregate-secondary) を claude-sonnet で 1 call
- 出力: IBIS 主張グラフ (issues / positions / arguments / premises_sent_out)
- 各ノードに verbatim_quote 必須
- parse 失敗は INVALID (評価不能) として通過させる
5. decide() (problem_space_decide.ts) がコードで判定
① 逐語引用照合: 全 verbatim_quote が本文に存在するか機械照合
- 1 件でも不一致 → INVALID (幻覚防止・評価から隔離)
② root 数: is_root=true の issue が 2 以上 → FAIL (理由 root_multiple)
③ 行き先解決: 行き先のない premise が 1 件でもあれば FAIL (理由 dangling_premise)
④ いずれも該当しなければ PASS
6. FAIL → rejected=true + triageRejectKind='pre-gate-block' + 差戻しメッセージ
PASS / INVALID → そのまま socratic へ通す
行き先の許容形 (ADR-0130 パターン): 外へ送った前提には次のどちらかが本文に要る。
- (i) 解決を所有する既存 ADR・文書の名指し
- (ii) 未起案なら起票義務 + 期限 + 撤退条件トリガーの 3 点明記
逐語照合の正規化: 連続空白 (改行・全角空白・タブ) を半角空白 1 個へ畳んで前後 trim する。文字そのもの (要約・言い換え) の相違は検出する厳密さを保つ。詳しい正規化は
normalizeForQuoteMatch()にある。
6. LLM 設定
| ノード | モデル | temperature / seed | コスト目安 | レイテンシ |
|---|---|---|---|---|
| 一次 (primary) | gemini-flash (MODELS.triage) | 0 / 42 | 1〜3 円/run | 1〜3 秒 |
| 二次 (secondary) | claude-sonnet (MODELS.socratic) | 0 / 42 | 1〜10 円/run (二次到達時のみ) | 3〜10 秒 |
- 一次は疑いを高再現で拾う軽量分類。二次は厳密 JSON schema での IBIS 構造化分解。
- どちらも temperature 0・seed 42 で同一起案には同一判定。
- プロンプトは KV-backed (
loadPrompt) + ノード内 FALLBACK。FALLBACK は production の prompt.md と一字一句同じ内容を維持する。
7. 副作用
なし。LiteLLM Gateway 経由の LLM 呼出のみ。GitHub API / KV 書込 / Webhook には触れない。
構造化ログ:
event: 'pregate_skipped'— env OFF で素通しevent: 'prompt_loaded'— KV / FALLBACK の出所event: 'pregate_complete'— stage / verdict / reasons / root_count / dangling_count / unmatched_countevent: 'pregate_primary_error'/'pregate_secondary_error'— LLM 例外
8. 出力 (State)
PASS (分析成立)
{
pregateVerdict: 'PASS',
pregatePass: true,
pregateStage: 'primary' | 'secondary',
pregateReasons: [],
pregateRootCount?: number, // 二次到達時のみ
}
INVALID (評価不能・通過)
{
pregateVerdict: 'INVALID',
pregatePass: true,
pregateStage: 'secondary',
pregateReasons: [],
pregateUnmatchedQuotes: string[], // 本文と照合できなかった逐語引用 (先頭 5 件)
}
INVALID は per-run では止めず通過させる。撤退条件 (3 件以上で設計見直し) で集計する。
FAIL (塊混在 or 宙に浮いた前提・差戻し)
{
pregateVerdict: 'FAIL',
pregatePass: false,
pregateStage: 'secondary',
pregateReasons: ['root_multiple' | 'dangling_premise', ...],
pregateRootCount: number,
rejected: true,
rejectionMsg: string, // 起案者向けガイド
rejectionReasonCode: 'pregate-root-multiple' | 'pregate-dangling-premise',
triageRejectKind: 'pre-gate-block', // ADR-0094 Phase C と同型
}
差戻しメッセージは FAIL_MESSAGES から理由ごとに連結して返す。triage の起案前ゲートと同形式。
9. 分岐 (次ノード)
graph.ts の conditional edge:
.addConditionalEdges('problem_space_pregate', (s) => s?.rejected ? END : 'socratic')
rejected | 次ノード | 起案者への表示 |
|---|---|---|
true (FAIL) | END | rejectionMsg を返却して終了。pre-gate-block 扱い |
false (PASS / INVALID) | socratic | 盲点検出フェーズへ |
10. エラー時の挙動
| 失敗パターン | 挙動 | 影響 |
|---|---|---|
| 一次 LLM 例外 / 一次 JSON parse 失敗 | 安全側に倒し suspect=true で二次へ送る | 取りこぼし防止優先 |
| 二次 LLM 例外 / 二次 JSON parse 失敗 | INVALID で通過させる | telemetry で別集計 |
| 逐語照合不一致 | INVALID で通過させる | 幻覚を評価から隔離 |
| 二次の parse は OK だが decide で FAIL | 差戻し (pre-gate-block) | 起案者が修正・再投入 |
設計方針は fail-safe-pass (一次は二次へ・二次は通過)。受付で止めるのは「分析の破れ」が機械的に確定したときだけ。
11. 既知の弱点・運用注意
ADR-0142 §5.2.1 盲点 + §5.3 リスクから抜粋:
- 誤判定由来の差し戻し記録が D-1 に残り続ける: 撤退で graph OFF にしても、precision 70% 未達時の誤判定記録が正典の人手検査基準として残る。OFF 発動時は該当記録に「参照停止」フラグを付与する運用追補が必要。
- 本 ADR 自身が検問 1 で排除する塊混在と同型: 「分析破れの機械検出」と「行き先規約の制度化」の 2 決定が同居している。独立撤退可能性で許容。将来分離は別 ADR。
- 代替効果: 審査者が「② で分析チェック済み」と過信し人手レビューが形式確認に退化する恐れ。pass は検問 4 つの通過のみを意味し、分析全正確性は保証しない。Verizon DBIR 2023 同型。
- 日本語並列節の false positive: 「〜であり、かつ〜」を独立 root と誤解釈しうる。golden eval に 10 件以上の境界例を入れて事前測定する。
- 逐語引用は実在保証のみ: 引用が判定根拠として論理的に妥当か (faithful but not factual) は担保しない。導入直後 20 run の人手確認で補完。
- 二次到達時のコスト: 一次で疑いが立った起案だけ二次 (claude-sonnet) を呼ぶ。通常はキャッシュ込みで月数百円規模だが、誤検知率が高いと膨らむ。
12. テストケース
- パイロット (実装前 K.O.): 受理済み ADR 20 本 + 人工生成陽性例 5 件以上。false positive 30% 超で実装に入らず不採用。
- golden eval (初期 3 ケース): ADR-0107 修正前 (塊 2 つ)・ADR-0107 修正後 (単一+行き先つき前提)・ADR-0136 (単一) の実検証。
- 日本語境界例: 「並列節を含む単一決定」起案 10 件以上を golden eval に追加し root 抽出 precision を事前測定。
実行: prompt-cicd フローの一部。詳しくは /Users/ts_kuma/projects/bizlp/doc/prompts/production/gate0a-pregate-{primary,secondary}/ 配下の eval セット。
13. 過去の設計判断ログ
| 日時 | 変更 | 経緯 |
|---|---|---|
| 2026-06-12 | ADR-0142 受理 (PR #1835 マージ) | ② 受付層の分析意味検査の空白を埋める受付ノードとして起案 |
| 2026-06-13 | Phase A パイロット runner で K.O. 通過 (PR #2038) | 受理済み 20 本 + 人工陽性例で false positive < 30% を確認 |
| 2026-06-15 | Phase B 本番稼働 (PR #2043) | graph 配線 + 受付ノード本体投入 |
| 2026-06-19 | 月次集計 SQL 整備 (PR #2198) | drp/queries/adr-0142-pregate-observation.sql で precision / evidence 一致率を観測 |
14. 関連リンク
- 前ノード: 11_webhook.md (graph 全体では前段は cost_gate)
- 次ノード: 02_socratic.md
- 同じ受付バンド: 13_abc_screen.md (harm を見る別検査・並立)
- State 定義:
drp/src/state.ts§ Gate 0a - 判定コード (pure):
drp/src/nodes/problem_space_decide.ts - migrate:
drp/migrate-v11-pregate.sql - 関連 ADR:
- ADR-0142 — 本ノードの起案 ADR
- ADR-0130 — 行き先許容形 (ii) の起票義務 + 期限 + 撤退トリガーのパターン参照元
- ADR-0030 — 複数型ラベル許容。検問 1 は「1 文圧縮・独立撤退」で判定
- ADR-0091 / ADR-0088 — ② 受付の静的 4 検査 (補完関係)
- ADR-0094 —
triageRejectKind='pre-gate-block'の意味論 - ADR-0109 — 差戻しは bounded rounds 枠内
- ADR-0138 — prompt + output_schema + golden eval 同一 PR パターン