ADR-0084: Gate 4 スコアリング閾値の KV 外部化
- Status: Accepted
- Mode: Standard
- Kruchten Type: Property/Executive
- Scope: platform
- Implementation Status: Done
- 起案者: [email protected]
- 起案日時 (JST): 2026-05-28 06:01
- 承認日時 (JST): 2026-06-21
- Deciders: [email protected] (単独)
コンテキスト
1.1 背景
Gate 4 (scoring.ts) の合否閾値が Light=35 / Standard=40 / Critical=45 とハードコードされている (scoring.ts:33)。これまで閾値調整の要望が運用側から複数回上がっており、本 ADR で外部化を検討する。
1.2 現状
scoring.ts に THRESHOLDS 定数と SYSTEM_PROMPT テキストの 2 箇所に閾値が埋め込まれている。閾値変更にはコード変更と wrangler deploy が必須。
1.3 課題
閾値調整にコード変更 + wrangler deploy が必要であり、運用上の反応速度が遅い。また 2 箇所に閾値が散在しており、片方更新漏れリスクがある (単一ソース原則違反)。
1.4 制約・要件
- PROMPTS_KV の既存 Active Pointer パターン (ADR-0042) と整合
- フェイルセーフ: KV 取得失敗時は hardcoded fallback (35/40/45)
- SYSTEM_PROMPT はテンプレートリテラル化し、閾値を動的注入 (単一ソース原則)
- ランタイムバリデーション: loadThresholds で取得した値に対し、各閾値が 0-50 の範囲内かつ Light ≤ Standard ≤ Critical の順序制約を検証。違反時は fallback 値を使用しログ出力。これにより KV に不正値が書き込まれても全件通過/全件失敗は発生しない
- KV 書き込みアクセス制御: 閾値変更は prompt-kv-push.mjs 経由のみ (バリデーション内蔵)。Workers KV の管理 API は wrangler CLI のみアクセス可能で、Web UI からの直接編集は Workers ダッシュボード権限で制限。Runbook に「KV 直接編集禁止」を明記
- 整合性保証の設計意図 (盲点#1 反映): Workers KV は同一リクエスト内の read-after-write を公式保証しない。同一 invocation 内では loadThresholds の戻り値を単一変数に束縛し、SYSTEM_PROMPT 生成と採点判定の両方に同一参照を渡すコード設計で整合性を担保する。グローバル伝播は最大 60 秒の遅延があり、閾値更新直後は旧値で採点される可能性がある (Runbook 明記要件)
1.5 目標
PROMPTS_KV から Gate 4 閾値を取得し、KV 未設定時は既存 hardcoded 値にフォールバック。SYSTEM_PROMPT を単一ソース化する。
Non-Goals: SYSTEM_PROMPT 本文自体の KV 管理、モデル名・temperature の KV 移行 (本 ADR スコープ外、§9 スコープクリープ防止)。
1.6 過去 ADR との関係
| ADR | 関係 |
|---|---|
| ADR-0042 (prompt lifecycle) | Extends |
| ADR-0056 (temperature 戦略) | Confirms |
| ADR-0077 (Telemetry) | Extends (盲点#2 反映: 監査ログ・fallback メトリクスを Telemetry 連携) |
Review After: 2026-08-28 (3 ヶ月後)
1.7 ステークホルダー
- 運用者: KV 更新のみで閾値調整可能
- Pipeline 利用者: 閾値変更の反映が即時 (ただし最大 60 秒の伝播遅延あり)
決定
PROMPTS_KV に gate4-scoring:thresholds キー (kv-keys.ts で定数化) で Gate 4 閾値を格納し、loadThresholds 関数で取得 + ランタイムバリデーション (0-50 範囲 + Light ≤ Standard ≤ Critical 順序制約) を実施する。SYSTEM_PROMPT はテンプレートリテラル化し閾値を動的注入。KV 取得失敗・バリデーション違反時は hardcoded fallback (35/40/45) を使用し WARN ログ + Telemetry カウンター送出。閾値変更は prompt-kv-push.mjs 経由のみとし、変更者・タイムスタンプ・旧値・新値を Analytics Engine (ADR-0077) に監査ログとして書き込む。
判断基準 (Decision Drivers)
3.1 評価軸
| # | 軸 | 重要度 (係数) | 案件特有の解釈 |
|---|---|---|---|
| 1 | #operable | Must (×2.0) | デプロイ不要で閾値調整可能か |
| 2 | #reliable | Must (×2.0) | 不正値・KV 障害時に全件失敗/通過が発生しないか |
| 3 | #maintainable | High (×1.0) | 単一ソース原則・キー名一元管理 |
| 4 | #secure | High (×1.0) | アクセス制御・監査証跡 |
| 5 | #efficient | Medium (×0.5) | 実装工数 |
K.O. criterion: Must 軸 (#operable, #reliable) の score < 3 は不採用。
3.2 評価軸 × 案スコア表
| 軸 | 係数 | 案A (採択) | 案B (vars) | 案C (D1) | 案D (現状維持) |
|---|---|---|---|---|---|
| #operable | ×2.0 | 5 | 2 | 4 | 1 |
| #reliable | ×2.0 | 4 | 4 | 4 | 5 |
| #maintainable | ×1.0 | 4 | 3 | 3 | 2 |
| #secure | ×1.0 | 3 | 4 | 4 | 5 |
| #efficient | ×0.5 | 4 | 4 | 2 | 5 |
| 加重和 (正規化) | 0.800 | 0.620 | 0.720 | 0.620 | |
| K.O. 通過 (Must ≥3) | ✓ | ❌ (#operable=2) | ✓ | ❌ (#operable=1) |
検討した代替案 (Alternatives Considered)
- 案A【採用】: PROMPTS_KV に
gate4-scoring:thresholdsキーで格納。loadThresholds + ランタイムバリデーション。SYSTEM_PROMPT テンプレートリテラル化。影響: scoring.ts, prompt_loader.ts, kv-keys.ts (新規)。工数 ~2h。 - 案B: wrangler.toml [vars] — 不採用: vars 変更もデプロイ必要 (#operable K.O.)。
- 案C: D1 テーブル — 不採用: 過剰な複雑性、本件 1 キー 3 値のみで RDB は不要。
- 案D: 現状維持 — 不採用: #operable K.O.。
- 案E (盲点#3 検討): KV 変更に Slack 2 名承認ワークフローを必須化 — 不採用: 本 ADR スコープでは prompt-kv-push.mjs バリデーションで業務範囲上限・下限 (例: Light は 25-45) を強制し、コードレビュー時に値域を確認する運用とする。承認ワークフロー導入は Review After 時点で再評価。
- 案F (盲点#4 検討): KV 書き込み専用の内部 Worker を中継 (Write-through Validator) — 不採用: 工数 ~8h で本 ADR の費用対効果を超過。本 ADR では「不正書き込みの最終防衛線はランタイムバリデーションのみ」とリスクを明示的に受容し、Logpush で KV 書き込みイベントを ADR-0077 Telemetry と連携する。
影響 (Consequences)
5.1 正の影響 (Good)
- 閾値変更がコード変更 + デプロイ不要となり、運用反応速度が向上
- SYSTEM_PROMPT と THRESHOLDS の単一ソース化により更新漏れリスク解消
- ランタイムバリデーション + fallback により KV 障害・不正値混入時も全件失敗/通過を回避
- 監査ログ (Analytics Engine 連携) により Gate 4 合否率急変時の原因特定が可能
- KV キー名の kv-keys.ts 定数化により push スクリプトと loader のタイポ不一致を防止
5.2 負の影響 (Bad)
- KV 伝播遅延 (盲点#1): 閾値更新後最大 60 秒間は旧値が混在する可能性。閾値厳格化直後に旧閾値で誤通過するウィンドウが存在。Runbook に明記必須
- アクセス制御の技術的弱さ (盲点#4): Cloudflare KV REST API は KV_WRITE スコープ API Token で直接書き込み可能。Runbook の「直接編集禁止」は技術的強制力を持たない。不正書き込みの最終防衛線はランタイムバリデーション (0-50 範囲 + 順序制約) のみ
- ガバナンス低下リスク (盲点#3): 変更コストの心理的障壁が下がり、十分な影響評価なしに閾値変更されるリスク。prompt-kv-push.mjs に業務範囲上限・下限 (Light: 25-45 等) を組み込み緩和
- LLM 採点挙動の非決定論的変化 (盲点#8): 閾値を SYSTEM_PROMPT に動的注入することで、プロンプト文字列が変化し LLM の採点傾向に副作用を与える可能性。閾値変更前後でプロンプト diff を自動ログ出力し、スコア分布の統計的変化を ADR-0077 Telemetry で監視
5.3 中立・トレードオフ (Neutral / Trade-offs)
- スコアスケール (盲点#5): scoring.ts のスコアレンジは 0-50 (Gate 4 採点ロジック準拠)。バリデーション上限 50 はこのスケールに基づく。Critical=45 はすでに 90% 相当の厳格設定。prompt-kv-push.mjs のバリデーションエラーメッセージに許容範囲を明示し、fallback 発動時のログレベルは WARN 以上
- ADR-0042 との位置関係 (盲点#7): Active Pointer パターンは SYSTEM_PROMPT 本文のバージョン切り替え用。本 ADR は閾値のみ KV 注入し SYSTEM_PROMPT 本体はコード内テンプレートリテラルに保持する。理由は「Gate 4 プロンプト本文は安定しており KV 管理不要、閾値のみ変更頻度が高い」。将来 SYSTEM_PROMPT 本文も KV 化する場合は別 ADR で二重管理問題を整理
- スコープクリープ防止 (盲点#9): KV 外部化の判断基準を「変更頻度が月 1 回以上かつデプロイコストが正当化できない設定」と明文化。Review After 時点で KV キー数と変更頻度を棚卸し評価
- fallback サイレント発動の可観測性 (盲点#6): fallback 発動時は WARN ログ + Telemetry カウンターメトリクス送出 + 閾値アラート設定により、タイポ等による無音フォールバック常態化を検知
撤退条件 (Rollback Plan)
| 撤退トリガ | 判定指標 | 期限 | 代替案 |
|---|---|---|---|
| KV 取得失敗率 > 1% | Telemetry fallback カウンター | Review After (2026-08-28) | scoring.ts を hardcoded に戻す (PR Revert) |
| 閾値変更によるスコア分布の異常変動 | Gate 4 合否率の前週比 ±20% 逸脱が 2 週連続 | 即時 | 直近の KV 値を旧値に戻し原因調査 |
| 不正書き込みインシデント発生 | 監査ログ (Analytics Engine) で範囲外値の書き込み検知 | 即時 | 案F (Write-through Validator Worker) へ移行検討 |
| KV キー数が 10 を超え設定 DB 化の兆候 | Review After 時点の棚卸し | 2026-08-28 | D1 移行 (案C 再評価) |
撤退手順: ① feature flag (USE_KV_THRESHOLDS) を false に切替 → ② hardcoded THRESHOLDS にフォールバック動作確認 → ③ scoring.ts から KV 参照コード除去 PR をマージ。
Confirmation (準拠確認 / Fitness Function)
- F1: ランタイムバリデーション準拠
- 検証手段: scoring.test.ts に「KV から範囲外値 (例: -1, 60) / 順序違反 (Light > Standard) を返した場合に fallback 値が使用され WARN ログが出ること」のユニットテスト
- 実行頻度: CI (PR ごと)
- 違反時: PR ブロック、test fail を修正
- F2: 単一ソース原則準拠
- 検証手段: scripts/adr-lint.mjs に「scoring.ts 内に
THRESHOLDSの数値リテラル (35/40/45) が SYSTEM_PROMPT テンプレートリテラル外に二重定義されていないこと」を AST チェックで追加 - 実行頻度: CI (PR ごと)
- 違反時: lint fail、二重定義を解消
- 検証手段: scripts/adr-lint.mjs に「scoring.ts 内に
- F3: KV キー名一元管理
- 検証手段: kv-keys.ts 外で文字列
gate4-scoring:thresholdsがハードコードされていないことを grep ベース lint で検証 - 実行頻度: CI (PR ごと)
- 違反時: lint fail、kv-keys.ts 経由に修正
- 検証手段: kv-keys.ts 外で文字列
- F4: 監査ログ送出
- 検証手段: prompt-kv-push.mjs 実行時に Analytics Engine へ変更者・タイムスタンプ・旧値・新値が送出されることを統合テストで確認
- 実行頻度: 月次手動 QA + Review After
- 違反時: prompt-kv-push.mjs を修正、未送出期間の監査ログを Git 履歴から復元
- F5: fallback 発動メトリクス監視
- 検証手段: Telemetry ダッシュボードで fallback カウンターが 0 でない場合のアラート設定
- 実行頻度: 常時監視
- 違反時: KV キー名タイポ・KV 障害を調査し、根本対応
参照 (References)
- 関連 ADR: ADR-0042 (Extends), ADR-0056 (Confirms), ADR-0077 (Extends)
- 関連 PR/Issue: (要追記)
- 外部資料:
- Cloudflare Workers KV consistency model (公式ドキュメント) — read-after-write 非保証・最大 60 秒伝播遅延の根拠
- scoring.ts:33 (現行 THRESHOLDS ハードコード箇所)