ADR-0082: Telemetry スキーマ v2 — trigger 情報・ノード別コスト記録の追加
- Status: Accepted
- Mode: Standard
- Kruchten Type: Existence/Property
- Scope: platform
- Implementation Status: Done
- 起案者: [email protected]
- 起案日時 (JST): 2026-05-28 04:41
- 承認日時 (JST): 2026-06-21
- Deciders: [email protected] (単独)
コンテキスト
1.1 背景 (Background)
PR #1079 で POST /runs エンドポイント追加時に、PipelineSessionState に triggerSource / modeOverride / dryRun / draftId フィールドが追加された。しかし TelemetryRecord(audit/types.ts)にはこれらのフィールドが存在せず、D1 の telemetry_records テーブルにも記録されない。
1.2 現状 (Current State / As-Is)
(1) TelemetryRecord v1 スキーマには trigger_source / mode_override / dry_run / draft_id カラムがない。pipeline_consumer.ts の saveTelemetryRecord 呼び出しでもこれらのフィールドは渡されていない。 (2) LLM API 呼び出しのトークン使用量・コストがノード単位で記録されていない。gate_timings(所要時間)は記録されているが、各ゲートが消費する input/output tokens は不明。
1.3 課題 (Problem)
(1) triggerSource の欠落により、Web UI / CLI / GitHub Actions のどのトリガーがパイプラインを起動したかをテレメトリで区別できない。ADR-0064 の撤退条件「CI 経由比率 30%」の測定が不可能。 (2) dry_run フラグの欠落により、テスト実行と本番実行の分離分析ができない。 (3) LLM コスト最適化のデータがない。Gate 3 (3 モデル並列) が全体コストの 60% を占める仮説があるが検証手段がない。
1.4 制約・要件 (Constraints & Requirements)
- D1 スキーマ変更は ALTER TABLE ADD COLUMN(破壊的変更なし)
- schema_version を v2 に bump し、v1 レコードの後方互換を維持
- LangChain response.usage_metadata からトークン数取得可能
- /audit/runs API でこれらの新フィールドを返す
1.5 目標 (Goals / To-Be)
TelemetryRecord に (1) trigger_source / mode_override / dry_run / draft_id カラム追加 (2) per-node token/cost tracking 用の node_metrics JSON カラム追加。 Non-Goals: 既存 v1 レコードのバックフィル、別テーブルへの分離、PII を含むプロンプト本文の記録。
決定
TelemetryRecord v2 を採用する。D1 telemetry_records テーブルに ALTER TABLE で (1) trigger_source / mode_override / dry_run / draft_id の 4 カラム、(2) node_metrics JSON カラムを追加する。schema_version を 2 に bump し、v1 レコードは新カラム NULL のまま後方互換維持。node_metrics は allowlist 方式の Zod スキーマで保存可能フィールドを明示的に制限し、プロバイダー差異吸収アダプタ層を介して書き込む。trigger_source は exhaustive enum として型定義する。
判断基準 (Decision Drivers)
3.1 評価軸
| # | 軸 | 重要度 (係数) | 案件特有の解釈 |
|---|---|---|---|
| 1 | #suitable | [Must] (×2.0) | ADR-0064 撤退条件「CI 経由比率 30%」測定、Gate 3 コスト 60% 仮説検証ができるか |
| 2 | #maintainable | [Must] (×2.0) | スキーマ変更影響範囲・v1/v2 混在期間運用・型安全性 |
| 3 | #secure | [High] (×1.0) | PII 混入リスク・GDPR/個人情報保護法対応・データ分類 |
| 4 | #reliable | [High] (×1.0) | usage_metadata 取得失敗時の NULL 汚染回避、D1 行サイズ上限耐性 |
| 5 | #efficient | [Medium] (×0.5) | 書き込みコスト・集計クエリ性能 (1 テーブル vs JOIN) |
K.O. criterion: Must 軸の score < 3 は不採用。
3.2 評価軸 × 案スコア表
| 軸 | 係数 | 採択案 (A: v2 + JSON + allowlist) | 案 B (別テーブル telemetry_node_metrics) | 案 C (gate_timings 相乗り) |
|---|---|---|---|---|
| #suitable | ×2.0 | 5 | 4 | 3 |
| #maintainable | ×2.0 | 4 | 3 | 2 |
| #secure | ×1.0 | 4 (allowlist 必須) | 4 | 2 |
| #reliable | ×1.0 | 4 (status フラグ要) | 4 | 2 |
| #efficient | ×0.5 | 4 | 3 (JOIN コスト) | 3 |
| 加重和 (正規化) | 0.864 | 0.736 | 0.464 | |
| K.O. 通過 (Must ≥3) | ✓ | ✓ | ❌ (maintainable=2) |
検討した代替案 (Alternatives Considered)
- 案 A【採用】: TelemetryRecord v2 — trigger 4 フィールド + node_metrics JSON カラム追加。ALTER TABLE で段階移行、v1 レコードは新カラム NULL。影響: audit/types.ts, audit/persistence.ts, pipeline_consumer.ts, index.ts。工数 ~3h (ただし盲点 #6 を踏まえ API/テスト/ダッシュボード分を含めると要再見積もり、要追記)。
- 案 B: 別テーブル telemetry_node_metrics を新設 — 不採用理由: JOIN コスト、D1 の JOIN 性能制約。1 テーブルに JSON カラムで持つ方が効率的。ただし盲点 #1 で指摘されたとおり SQLite 特性上 CROSS-RUN 集計ではインデックス付き別テーブルが優位の可能性があり、不採用根拠は計測ベースの補強が必要(要追記)。
- 案 C: gate_timings JSON に token/cost を相乗り — 不採用理由: 名前が不適切 (timings ≠ costs)、型安全性低下。K.O. 不通過 (maintainable=2)。
影響 (Consequences)
5.1 正の影響 (Good)
- ADR-0064 撤退条件「CI 経由比率 30%」の測定が可能になる (trigger_source enum + 分母定義の明文化が前提)。
- Gate 3 3 モデル並列のコスト 60% 仮説を node_metrics で検証可能になる。
- dry_run と本番実行の分離分析、draft_id 紐付けでの下書き処理監査が可能になる。
- allowlist 方式の Zod スキーマ + プロバイダー差異吸収アダプタにより、型安全性と集計クエリの再現性が確保される。
5.2 負の影響 (Bad)
- (盲点 #1) LangChain usage_metadata のフィールド名がプロバイダー間で異なる (Anthropic: inputTokens / OpenAI: prompt_tokens 等)。正規化アダプタ層の実装コストが追加発生。
- (盲点 #2) node_metrics JSON が open-ended だと将来 prompt_snippet / intermediate_steps が混入し GDPR 削除権・保存期間対応が困難化。allowlist の CI 強制が必須。
- (盲点 #3) ストリーミング / function calling / タイムアウト時に usage_metadata が返却されないケースがあり、NULL 混入のまま集計すると Gate 3 60% 仮説の検証で系統的誤差を生む。
- (盲点 #6) 工数 3h はスキーマ ALTER のみの見積もりであり、API レスポンス型変更・クライアント修正・既存テスト・ダッシュボード更新を含めると 3-5 倍に膨らむ可能性。
- (盲点 #7) Gate 3 並列ノード × 長パイプラインで node_metrics が数十 KB に達し、D1 行サイズ上限超過で書き込みサイレント欠落のリスク。
- (盲点 #8) コスト可視化により経営層への想定外 LLM 費用露見でパイプライン廃止議論が誘発される可能性。
5.3 中立・トレードオフ (Neutral / Trade-offs)
- (盲点 #4) dry_run の意味論 (LLM API コール有無 / DB 副作用有無 / 監査上の本番扱い) は ADR 本文で確定させる必要があり、定義によって分析クエリの設計が変わる。
- (盲点 #5) trigger_source は exhaustive enum (
'web_ui' | 'cli' | 'github_actions' | 'api_direct' | 'unknown') として TS 型で Required にすることで未更新呼び出しサイトをコンパイルエラー検出する。将来トリガー追加時は ADR 改訂を伴う。 - (盲点 #9) ノード別コスト可視化はマイクロ最適化への過集中を招きうるため、利用目的を「Gate 3 並列化の妥当性検証」に限定し、3 ヶ月後に並列化廃止・統合の意思決定レビューをスケジュールする。
- v1/v2 混在期間のメトリクス算出は全クエリで
WHERE schema_version = 2明示を規約化する。混在期間終了基準は「デプロイ後 30 日経過 or v1 レコード比率 1% 未満」を採用 (要 ADR 本文明記)。
撤退条件 (Rollback Plan)
- 判定指標 1: node_metrics の usage_metadata 取得成功率が 70% 未満で 2 週間継続 → アダプタ層の根本見直し or 案 B (別テーブル) へ移行検討。
- 判定指標 2: D1 行サイズ超過による telemetry 書き込み失敗率が 0.1% を超える → node_metrics をノードレベル集計値のみ保存するフォールバックを恒久化、または案 B へ移行。
- 判定指標 3: node_metrics への PII 混入が CI / 監査で検出された場合、該当カラムを即時 NULL クリア + allowlist Zod スキーマの強制範囲を縮小。
- 判定指標 4: Review After 日 (起案日 + 3 ヶ月、要追記) に Gate 3 並列化の意思決定レビューを実施し、コスト 60% 仮説が反証されなければ並列化見直しを別 ADR で起票。
- 代替案: 案 B (telemetry_node_metrics 別テーブル + インデックス) への移行。schema_version v3 で JSON カラムを deprecation。
Confirmation (準拠確認 / Fitness Function)
- 検証手段 1 (自動 / CI): audit/types.ts に Zod スキーマで node_metrics の allowlist (
tokens_in/tokens_out/cost_usd/model_id/latency_ms/metrics_collection_status) を定義し、saveTelemetryRecord 呼び出し前にバリデーション実行。allowlist 外フィールド混入時は CI テストで失敗させる。 - 検証手段 2 (自動 / CI): TypeScript 型レベルで trigger_source を exhaustive enum + Required にし、pipeline_consumer.ts の全 saveTelemetryRecord 呼び出しサイトで trigger_source 未指定をコンパイルエラー化。
- 検証手段 3 (自動 / CI): D1 行サイズ負荷テスト (10KB / 50KB / 100KB の node_metrics) を CI に組み込み、書き込み成功 + フォールバック動作を検証。
- 検証手段 4 (手動レビュー): PR レビューチェックリストに「node_metrics に prompt 本文・intermediate_steps を含めていないか」「schema_version WHERE 句が集計クエリに含まれているか」を追加。
- 実行頻度: 検証手段 1-3 は全 PR の CI で毎回実行。検証手段 4 は telemetry / audit 関連 PR 毎。Review After 3 ヶ月後に取得成功率・行サイズ・PII 検出件数のメトリクスレビュー。
- 違反時の対応: CI 失敗時はマージブロック。本番で PII 検出時は即時カラムクリア + Incident チケット起票。usage_metadata 取得成功率 70% 未満継続時は撤退条件に従う。
参照 (References)
- 関連 ADR: ADR-0064 (CI 経由比率 30% 撤退条件)、(要追記: trigger_source 導入元 ADR)
- 関連 PR/Issue: PR #1079 (POST /runs エンドポイント追加、PipelineSessionState 拡張)
- 外部資料: LangChain JS usage_metadata 仕様 / プロバイダー別フィールド名差異 (Anthropic inputTokens, OpenAI prompt_tokens 等) / D1 (SQLite) 行サイズ制限ドキュメント (要追記: URL)