1. Executive Summary

  • 文脈: drp のテレメトリー書込 (saveTelemetryRecord = テレメトリー記録をデータベースに挿入する関数) は Workers Workflows の finalize step 内で inline 呼び出しされている。
  • 課題: テレメトリー書込が失敗してもエラーログ出力のみで処理が成功終了し、電帳法 KPI (= 電子帳簿保存法に対応するための観測指標) 「終端 run 数 = テレメトリー行数」が silent に乖離する。
  • 対策: テレメトリー書込を独立 Workflows step (persist_telemetry = テレメトリー永続化専用のステップ) に分離し、retry 3 回・exponential backoff・timeout 10s を載せる。
  • 効果: silent drop を alarm 経由で可観測化し電帳法 KPI の分子と分母の乖離を早期に検知でき、transient 失敗 (D1 rate limit / network flap) を retry で吸収し電帳法 KPI 分子の欠落を減らせる。
  • 代償: 実装 3 時間・retry backoff 込で p95 latency +200-500ms 悪化し、alarm 集計は初期 console.log 運用で将来 Analytics Engine 移行が別途必要。

2. 何を解決するか

2.1 直面していること

信頼性:

  • drp/src/audit/persistence.ts:213-219 の catch 節が telemetry 書込の SQL 構文エラー・列 drift・SQLITE_MISUSE を吸い込み run 終端は成功として返す。
  • 失敗した run は telemetry 0 行で残り、観測 SQL 側から見て「run 終端したが未計上」= 電帳法 KPI の分子分母乖離が silent に進行する。

2.2 放置すると起こること

信頼性:

  • workflows-e2e (ADR-0197 系) が assert する KPI 「run 終端率 = telemetry 行数 / trigger 総数」は本番 D1 の telemetry を数える設計のため、silent drop が起きると分子が減り率が下振れする。
  • monitor は「率下振れ」と読むが真因は「観測欠落」であり、誤診断で修正方向が意図と異なる方向 (run 側の障害調査) に流れる。

2.3 潜在リスク (実害未発生 · 発生確率不明)

信頼性:

  • Workers Workflows の他 step (gate node) は Workflows retry 最大 3 回を活かす一方、finalize step 内 inline の saveTelemetryRecord は step の一部として retry されるが直後 catch で吸われるため実質 no-retry になっている。
  • 結果として transient (network flap / D1 rate limit) を吸収できない非対称性が残っている。

3. 採用したい方針

3.1 対策方針

drp/src/workflows/pipeline_run_workflow.ts (= 審査 pipeline の Workflows entry) の finalize 直前に persist_telemetry step を独立 step として挿入し、retry 3 回・exponential backoff・timeout 10s を載せる。最終 retry でも失敗した場合のみ silent-degrade catch を残し、alarm/metric emit した上で workflow 終端は継続する (電帳法 KPI を優先する既存の設計意図を維持しつつ観測欠落を可視化)。

  • 信頼性: finalize 直前に doStep('persist_telemetry', PERSIST_STEP_CONFIG, saveTelemetryRecord) を挿入し PERSIST_STEP_CONFIG は retry 3 回・exponential backoff・timeout 10s とする。
  • 信頼性: 最終 retry でも失敗した場合のみ silent-degrade catch を残し alarm/metric emit した上で run 終端は継続する。

3.2 守るべき設計制約

  • 信頼性: silent-degrade は最後の retry でも失敗した場合のみ許容し、alarm/metric emit で観測欠落の存在を可視化する (run 終端は継続 · 電帳法 KPI を優先する既存の設計意図を維持)。
  • 運用性: ADR-0120 の「1 step.do = 1 Workers request」制約 (= per-step subrequest 上限 1000) を維持し、persist_telemetry step は D1 execute 1 回のみで subrequest 数 = 1 に収める。
  • 適合性: 98 箇所の位置 bind を builder 化する際、builder の bind 追加順序と SQL 文字列の列順が 1 対 1 で対応することを保証する (順序変更で列値ずれ = 列 drift を新規発生させない)。

3.3 仕様

  • 信頼性: PERSIST_STEP_CONFIG{ retries: { limit: 3, delay: '2s', backoff: 'exponential' }, timeout: '10s' } とする。
  • 信頼性: 最終 retry 失敗時の alarm は既存 log pattern と互換な console.log(JSON.stringify({ event: 'telemetry_persist_final_fail', session_id, error })) で emit する。
  • 信頼性: alarm 発火を D1 専用テーブル telemetry_persist_failures にも永続化し console.log 保持期間 (デフォルト 1〜7 日) 消失で電帳法 7 年遡及調査に対応できなくなるリスクを回避する。
  • 信頼性: 列 drift (migrate-v22 / v23 パターンの再発) に対する防御として deploy pipeline に「migration smoke test」(= 対象 D1 に対する INSERT dry-run を deploy 直前に実行し列不整合を事前検出する CI step) を追加する。
  • 適合性: builder の bind 追加順序は「SQL 文字列の列出現順と同じ順」で追加するルールとし、期待列値を全列アサートする unit test (drp/test/audit/persistence.builder.test.ts 新設) で保証する。
  • 運用性: alarm 集計先の Analytics Engine 移行は行き先を §11 に明記した上で別 ADR に送る。

4. 判断基準

4.1 評価軸

#軸 (Q42)日本語軸名重要度 (係数)案件特有の解釈
1#reliable信頼性Must (×2.0)電帳法 KPI 分子の silent drop を alarm/metric に 100% 出す · retry で transient を吸収
2#operable運用性Must (×2.0)ADR-0120 の 1 step.do = 1 Workers request 制約遵守 · alarm 発火時の対応手順が runbook に整備されている
3#suitable適合性Must (×2.0)「終端 run 数 = telemetry 行数」invariant の workflows-e2e が全 pass · builder 化で列値ずれを起こさない
4#efficient効率性Medium (×0.5)p95 latency 悪化幅 · Cloudflare Workflows step +1 の課金増
5#usable使いやすさMedium (×0.5)起案者体験 (run 終端可否) への影響

K.O. criterion: Must 軸 score < 3 は不採用。

4.2 評価軸 × 案スコア表

係数採択案 (独立 step + retry/alarm)案 A (fail-closed throw)案 B (Queues 非同期)
信頼性×2.0434
運用性×2.0432
適合性×2.0524
効率性×0.5342
使いやすさ×0.5423
加重和 (正規化)0.8270.5600.633
K.O. 通過 (Must ≥3)❌ (適合性 = 2)

5. 検討した代替案

  • 案 A (silent-degrade catch を fail-closed = throw に変える): run 終端が止まると電帳法 KPI 優先の既存設計意図に反する。

    • 適合性: 電帳法 KPI 優先で run 終端を止めないという既存設計意図に反するため設計意図の override は別 ADR での合意が必要になる。
    • 使いやすさ: run 終端が止まると起案者体験が悪化し LLM 課金コストが loss として残る。
  • 案 B (Cloudflare Queues に telemetry を投げて非同期永続化): consumer 実装・dead-letter 監視まで運用面の増加が広い。

    • 運用性: Queue 追加は consumer 実装・dead-letter 監視まで運用面の増加が広く、現行 D1 直書きに retry を足す変更に比べ観測性課題への対処として過剰。
    • 信頼性: producer は run 終端のみ確定できる利点はあるが、非同期化に伴う dead-letter 経路の設計が別途必要になる。ただし本案の再検討トリガーとして「Workflows instance expire (18 時間) 以内に D1 が回復する」前提が崩れた場合 (例: D1 障害が 18 時間超継続) は §8 撤退条件で本案への移行 ADR 起票を義務化する。

6. 影響

6.1 正の影響

  • 信頼性: 最終 retry 失敗時の alarm 経由で silent drop が可観測になり電帳法 KPI の分子分母乖離を早期に検知できる。
  • 信頼性: Workflows retry 3 回で transient (D1 rate limit / network flap) を吸収し電帳法 KPI 分子の欠落を減らせる。
  • 適合性: 98 位置 bind の builder 化で列順の SSoT が SQL 文字列側に集約され migrate-v22 / v23 パターンの列 drift 検出が容易になる。

6.2 負の影響 / リスク

  • 効率性: workflow step 追加で run 全体の p95 latency が retry backoff 込で +200-500ms 程度悪化する可能性がある。
  • 運用性: alarm/metric の集計先は初期 console.log + D1 telemetry_persist_failures テーブルの二本立てで運用し、Analytics Engine 移行の受け皿 ADR 起票が別途必要になる (§11 に行き先を明記)。
  • 信頼性: builder の bind 追加順序変更で列値ずれが発生するリスクは残る (§3.3 の unit test で最終的に検出する設計)。

6.3 中立・トレードオフ

  • 信頼性: retry と alarm の導入で「観測性は解決済み」という確証バイアスが生まれ Analytics Engine 移行 ADR が期限を過ぎても放置される可能性がある (§11 で自動 issue 化の受け皿を明記)。

7. コスト試算

7.1 前提条件

項目根拠
実装工数3 時間step 分離 2h + config/test 1h
追加 step 数+1 (~10 → ~11)finalize 手前に persist_telemetry を挿入
p95 latency 悪化+200-500msretry backoff 込 · 稀な transient 時のみ
Logpush / D1 失敗テーブル実装 1hCloudflare Logpush 設定 + telemetry_persist_failures migration
migration smoke test実装 1hdeploy pipeline に INSERT dry-run step 追加

7.2 月コスト試算

  • Cloudflare Workflows: step +1 の追加分は定額課金の範疇で $0-2/month 増。
  • ランタイム: 通常時は retry を発火しないので overhead は無視可能。
  • D1 追加テーブル telemetry_persist_failures: 想定書込 < 月 100 行で $0/month。
  • 実装にかかる一次コスト: 3 + 1 + 1 = 5 時間 (単発)。

8. 撤退条件

  1. Shipping 後 1 週間で workflow run の p95 latency が fix 前より 1000ms 超悪化した場合、retry 回数を 3 → 1 に減らして retry-storm 疑いを排除する。
  2. alarm 発火数 (telemetry_persist_final_fail) が月 5 件超となった場合、D1 rate limit hit の原因調査を行った上で consumer 分散 (Queues 化 等) への移行 ADR を起票する。起票義務: alarm 月 5 件超を観測した時点で ADR-0130 パターンで別 ADR 起票 · 期限: 観測から 2 週間以内 · 撤退トリガー: 起票せず放置した場合は本 ADR の retry 設定を 3 → 1 に戻し観測性優先方針を再合意する。
  3. D1 rate limit がバースト状に発生し数分間で alarm 5 件を超過した場合、staging 負荷試験で実測した backoff 上限値が回復時間をカバーしていないことが証明されたと見なし、backoff 上限を再設計 (delay 2s → 5s or limit 3 → 5) するか案 B (Queues 非同期) への移行 ADR を起票する。
  4. Cloudflare D1 障害が 18 時間超継続し Workflows instance expire で retry 機会が消滅する事象が 1 度でも発生した場合、案 B (Queues 非同期) への移行 ADR を 1 週間以内に起票する。放置した場合は本 ADR を supersede 予約とする。
  5. Analytics Engine 移行 ADR の起票期限 (shipping 後 3 か月) を過ぎても未起票の場合、本 ADR §11 の GitHub Actions scheduled workflow が自動 issue 化する。issue 化後 1 か月未対応で本 ADR の Confirmation 月次レビューを止める。

9. Confirmation

  1. 電帳法 KPI 分子分母乖離のゼロ化 — 検証手段: SELECT COUNT(*) FROM telemetry_records WHERE created_at >= '2026-07-15' と workflows-e2e の trigger 総数を月次比較 / 実行頻度: 月次 / 違反時対応: 差分 ≥ 0.5% で telemetry_persist_final_fail log と telemetry_persist_failures テーブルを突合し原因特定 · alarm 未発火なら silent drop 経路 (catch 節の想定外 path) を PR で修正。
  2. transient 吸収率 — 検証手段: SELECT COUNT(*) FROM logs WHERE event='telemetry_persist_retry_recovered' を月次計上 · retry で救えた件数を可視化 / 実行頻度: 月次 / 違反時対応: retry 3 回内での recovery 率 < 95% で backoff 設定を再設計。
  3. 列 drift 検出 — 検証手段: deploy pipeline の migration smoke test (INSERT dry-run) が全 column に対して pass すること · builder unit test (drp/test/audit/persistence.builder.test.ts) が全列 assert で pass すること / 実行頻度: 全 PR CI / 違反時対応: dry-run fail で deploy を blocking · builder unit test fail で PR merge blocking。
  4. alarm SLA — 検証手段: telemetry_persist_alarm_runbook.md に定義した「alarm 発火後 24 時間以内に対象 run_id を特定し補記 INSERT または再 trigger する」SLA を月次レビュー / 実行頻度: 月次 / 違反時対応: SLA 逸脱 1 件で runbook 手順の見直し PR を起票。
  5. Analytics Engine 移行期限監視 — 検証手段: GitHub Actions の scheduled workflow (.github/workflows/adr-followup-issue.yml 新設) が shipping 後 3 か月時点で未起票なら自動 issue 化 / 実行頻度: 月次 cron / 違反時対応: issue 発行 1 か月未対応で撤退条件 5 発火。

10. 参照

10.1 関連 ADR

  • ADR-0120 (1 step.do = 1 Workers request の制約 · persist_telemetry step 追加時の subrequest 上限との互換確認)
  • ADR-0197 (auto-consume inter-clone inbox · 電帳法 KPI 系 workflows-e2e の設計)
  • ADR-0130 (受け皿未起案の前提を「起票義務 + 期限 + 撤退トリガー」で外へ送るパターン)

10.2 関連 PR/Issue

  • 依存 memory: telemetry-100-column-limit-reached
  • 過去 shipping: migrate-v22 (citation_details_json) · migrate-v23 (paraphrase_details_json) — silent drop 候補期間の観測対象

10.3 外部資料

11. 実装配線

  • lint 配線: drp/src/workflows/pipeline_run_workflow.tspersist_telemetry step を追加 · drp/src/audit/persistence.ts の 98 位置 bind を builder 化 · drp/test/audit/persistence.builder.test.ts (新設) で全列 assert unit test · drp/migrations/024_telemetry_persist_failures.sql (新設) で alarm 永続化テーブル追加 · .github/workflows/deploy-worker.yml に migration smoke test step 追加 · .github/workflows/adr-followup-issue.yml (新設) で Analytics Engine 移行 ADR 起票期限の自動 issue 化 · Cloudflare Workers Logpush 設定を wrangler.toml に追記し telemetry_persist_final_fail のプッシュ通知経路を確保。
  • 起案フロー配線: 本 ADR は Pipeline 通常経路で起案 · shipping は .github/workflows/deploy-worker.yml (= Workers 本番 deploy の GitHub Actions workflow) 経由の即本番 deploy · merge 前に memory drp-workflow-instances-check-before-merge に従い実行中審査 run 有無を確認する (deploy は run を kill するため)。
  • docs SSoT 同期: docs/_internal/06_ops/telemetry_persist_alarm_runbook.md (= alarm 発火時の対応手順を書く新設 runbook) を新設し alarm log 形式・対応 flow・エスカレーション先・「alarm 発火後 24 時間以内に対象 run_id を特定し補記 INSERT または再 trigger する」SLA・対象 run_id 特定 SQL (SELECT session_id FROM telemetry_persist_failures WHERE created_at >= ?)・安全な再 insert 手順 (INSERT OR IGNORE パターン) を記載する · Analytics Engine 移行 ADR の受け皿は ADR-0130 パターンで起票 · 起票義務: alarm が定常運用に入った時点 (月 1 件以上が 3 か月連続 or shipping 後 3 か月時点のいずれか早い方) で起票 · 期限: 契機観測から 2 週間以内 · 撤退トリガー: 起票せず放置した場合は本 ADR §8 撤退条件 5 が発火。