18. Perspective Selector (補助モジュール)
TL;DR(このノードは何をする・専門語ゼロ): Socratic が「採用案の弱点は?」「代替案の不採用理由は妥当か?」のような問いを投げる際に使う観点リストの中から、起案ごとに 3 つの観点を選ぶ補助モジュール。同じ起案には毎回同じ 3 観点を返す決定性を持ちつつ、似たヘッダ構造の起案群でシード空間がぶつかっても 3 観点全部が連動して固着しないよう、軸ごとに独立シードで選ぶ。AI は使わず、文字列ハッシュと PRNG の純粋関数だけで決める。
実装:
drp/src/nodes/perspective_selector.ts呼び出し元:drp/src/nodes/socratic.ts(3 観点を pick して socratic プロンプトへ注入) プロンプト: なし (LLM 呼出なし) テスト:drp/test/perspective_selector.test.ts(決定性回帰 + カバレッジ分布) 基盤 ADR: ADR-0109 (§5.2 #6 シード衝突による永続的視点固着の緩和) / ADR-0102 (Light cap / Gate 1 観点選択)
1. 役割と位置づけ
Socratic / Cross-Validation で使う観点リスト CONSTITUTION_PERSPECTIVES (現行 22 項目) から、起案ごとに重複なしで 3 観点を選ぶ。
- 解決する課題: 観点の固定だけでは「同じ起案には同じ問い」が出ず、Cross-Validation の goalpost が観測しづらかった。決定性を持たせて再現性を確保しつつ、シード衝突 (類似ヘッダ構造の ADR 群が同じ 3 観点に固着する) を緩和する。
- 設計思想: graph には独立ノードとして addNode されない補助モジュール。
socratic.ts内からselectRandomPerspectives(3, deterministic ? userInput : undefined)の形で呼ばれる pure 関数。langchain 非依存で workerd プールから単体テスト可能。 - 由来: ADR-0109 Part 3 (決定性 PRNG 導入) + §5.2 #6 緩和 (a) 軸インデックス XOR 混合。
2. フロー図
flowchart LR
SO[socratic] -->|userInput| PS[selectRandomPerspectives]
PS -->|3 indices + 3 perspectives| SO
SO --> LLM[Gate 1 LLM 呼出]
3. トリガー条件
graph の独立ノードではないため graph 上の edge 条件はない。socratic.ts:204 で以下のとき呼ばれる:
| 呼び出し条件 | 挙動 |
|---|---|
SOCRATIC_DETERMINISTIC=true (本番既定) | selectRandomPerspectives(3, userInput) で決定性 pick |
SOCRATIC_DETERMINISTIC=false (旧経路 / 開発時) | selectRandomPerspectives(3, undefined) で Math.random 単一ストリーム |
4. 入力 (引数)
| 引数 | 型 | 用途 |
|---|---|---|
count | number | pick する観点数。min(count, 22) でクリップ |
seedStr | string | undefined | シード文字列 (本番は起案者の userInput を使う)。undefined なら Math.random 単一ストリーム |
外部入力なし。
5. 処理ロジック
1. available = CONSTITUTION_PERSPECTIVES のインデックス配列 [0..21] のコピー
2. n = min(count, 22)
3. seedStr=undefined (旧経路):
- n 回ループで Math.random から pick → available から splice
4. seedStr!=undefined (決定性経路):
- base = hashSeed_(seedStr) // FNV-1a 32bit
- 各 pick i で rng = mulberry32_((base ^ AXIS_SALTS[i % 5]) >>> 0)
- pick = floor(rng() * available.length) → available から splice
5. indices と CONSTITUTION_PERSPECTIVES[indices[*]] を返す
AXIS_SALTS (5 個・golden-ratio / SplitMix64 系の撹拌定数):
0x9e3779b9/0x7f4a7c15/0x94d049bb/0xbf58476d/0x2545f491
各 pick を独立シード (base ^ AXIS_SALTS[i]) の PRNG で行うため、類似シード (類似ヘッダ構造の ADR 群) がシード空間でクラスタリングしても pick 系列が相関しない。単一 PRNG ストリームでは base シードの近接が 3 観点全部の近接に直結するが、salt 混合により各軸の選択が独立化する。
ADR の緩和 (a) は「ADR カテゴリタグ・軸インデックス」の XOR を挙げるが、ADR カテゴリの taxonomy が現状未定義 (state にカテゴリフィールドなし) のため、実装可能な軸インデックス混合を先行導入。カテゴリタグ混合は Review After (2026-12-02) で再評価。
6. LLM 設定
LLM 不要 (純粋関数)。FNV-1a と mulberry32 の数値演算だけで決まる。同一 seedStr → 同一 3 観点 (Part 3 決定性の回帰テストで固定)。
7. 副作用
なし。引数のみで結果が決まる pure 関数。
8. 出力
{
perspectives: string[], // CONSTITUTION_PERSPECTIVES から重複なしで pick した文字列 (count 個)
indices: number[], // pick した index (audit / 分布可視化に使う)
}
socratic.ts は perspectives を Gate 1 LLM プロンプトへ注入し、indices を telemetry へ載せる。
9. 分岐 (次の処理)
graph の独立ノードではないため graph edge を持たない。socratic.ts は本モジュールの戻り値を Gate 1 LLM 呼出に渡すだけ。
10. エラー時の挙動
エラー無し (deterministic)。
count > 22でもn = min(count, 22)で safeseedStrが空文字列でもhashSeed_は2166136261(FNV-1a offset basis) を返し有効- 数値演算のみで例外を投げる経路がない
11. 既知の弱点・運用注意
- 意味的多様性は保証されない: 22 観点の中身は人間が決めた集合で、似た観点 (例: 「コスト試算は最悪ケースか」と「最悪のケースを過小評価していないか」) が同じ起案で同時 pick される可能性がある。CI のカバレッジ分布テストで全軸の出現を検証するが、意味的近接は無視。
- AXIS_SALTS の周期: 5 個で循環 (
i % 5) するため、count>5 では同じ salt が再利用される。現行は count=3 固定で問題なし。count を増やすときは salt 数も増やす。 - カテゴリ混合は未実装: ADR が示す緩和 (a) のうち「カテゴリタグ XOR」は ADR カテゴリ taxonomy が未定義のため未着手。観測で固着パターンが残るかを 2026-12-02 まで観測し、必要なら追加実装。
SOCRATIC_DETERMINISTIC=false経路の温存: 開発時の挙動検証用に Math.random 経路を残している。本番は常に true 固定。- 観点リスト改訂時の互換:
CONSTITUTION_PERSPECTIVES配列順序を変えると同一 seedStr でも違う 3 観点が pick される (= 過去 run との比較が壊れる)。末尾追加 で互換性維持。
12. テストケース
drp/test/perspective_selector.test.ts (vitest workerd プール):
| 観点 | 期待 |
|---|---|
| 同一 seedStr → 同一 3 観点 (Part 3 決定性の回帰) | indices と perspectives が一致 |
| 異なる seedStr → 異なる 3 観点 | 出現分布のばらつき |
| 合成コーパス (一様 + クラスタ) で全軸の出現 | 22 軸すべてが出現する (カバレッジ分布テスト) |
count > 22 | min(22, count) でクリップ |
seedStr=undefined | Math.random 経路で重複なし |
hashSeed_ | FNV-1a 32bit の既知ベクタ |
CI ログに分布テーブルを出力 (ADR-0109 §5.2 #6 緩和 (b)(c))。
13. 過去の設計判断ログ
| 日時 | 変更 | 経緯 |
|---|---|---|
| ADR-0109 Part 3 | Math.random → 決定性 PRNG (FNV-1a + mulberry32) | sub の goalpost 観測再現性を確保 |
| ADR-0109 §5.2 #6 緩和 (a) | 軸インデックス XOR salt 混合 | 類似シード起案群で 3 観点固着する盲点に対処 |
| ADR-0109 §5.2 #6 緩和 (b)(c) | カバレッジ分布テスト + CI 分布表 | 全軸出現を機械的に検証 |
| Review After 2026-12-02 | カテゴリタグ混合の再評価 | taxonomy が定義されたら追加実装を検討 |
14. 関連リンク
- 呼び出し元: 02_socratic.md (
socratic.ts:204で 3 観点を pick) - 関連 ADR:
- 観点リスト SSoT:
drp/src/nodes/perspective_selector.tsのCONSTITUTION_PERSPECTIVES