• Status: Accepted
  • Mode: Standard
  • Kruchten Type: Existence/Executive
  • Scope: platform
  • Implementation Status: In Progress — Phase a 完了 (PR #1467: checkpoint 基盤 envelope/DoCheckpointSaver/gate_runner 抽出 + ADR-0116 Superseded 化 / PR #1470: PipelineRunWorkflow = 1 step.do = 1 gate・[[workflows]] binding・本番 dormant デプロイ済) + Phase b 完了 (PR #1476: 入口 feature flag 切替 WORKFLOW_ENTRYPOINT_ENABLED + キャンセル 3 層 (terminate 併用/cancel-finalize 条件付き終端/step 内 1 秒 polling + AbortSignal の in-flight LLM 中断) + gateProgress gateId+seq idempotency・本番 flag 既定 OFF = 挙動不変)。Phase c 完了 (c-1 = PR #1481: fault-injection mocked e2e 5 シナリオ 20 assertion を CI 毎 PR ゲート化 / 本番ステージング検証 = 実 Workflows runtime で並列 3 run・step retry 自然発生時の完了済み step 再実行ゼロ実測・キャンセル ≤1s abort — 本番切替の前提ゲート PASS 判定 2026-06-05 / c-2 = PR #1484: instance status API アダプタ層 + CI 週次フィールドアサート = 決定 4・盲点 5 / c-3 = PR #1487: running>20 リアルタイムアラート = 決定 5・盲点 7・§Corrigendum 参照)。本番切替済み (2026-06-05 21:45 JST・WORKFLOW_ENTRYPOINT_ENABLED=true・切替直後の /runs 実機で engine=workflows + telemetry + instance Completed を確認)。リアルタイムアラートも有効化済み (WORKFLOWS_READ_API_TOKEN / OPS_ALERT_WEBHOOK 投入・Google Chat 着信確認・heartbeat 稼働)。残: 移行 4 週の撤退条件監視 (〜2026-07-03 目安・①telemetry 喪失 1 件 ②gate 重複実行 = 二重課金 1 件で即時停止 ③新規障害 3 件 — 週次 telemetry レビューに追加。rollback は同 secret に false を put するだけ)
  • 起案者: [email protected]
  • 起案日時 (JST): 2026-06-05 00:30
  • 承認日時 (JST): 2026-06-05 (PR #1462 merge = 受理・JST 00:51)
  • Deciders: [email protected] (単独)

コンテキスト

§1.1 背景

Decision Pipeline のフル 10 gate 審査 (~16-24 分) は Cloudflare Queues consumer の 1 invocation 時間上限を超え、worker kill → at-least-once 再配信で telemetry 喪失・LLM 多重課金が発生する構造を抱える (session bedb9912 実測: 全 gate 3 周再実行・kill 2 周分の telemetry 0 行)。ADR-0116 はこれを gate 単位 chunk 化 (案B) で封じ込める決定をしたが、同 ADR は案C (Workflows 移行) を「加重和最高 (0.943) だが LangGraph 統合障壁が未調査」という理由のみで見送り、撤退条件に「Phase 0 spike の結果次第で案C 先行 ADR の起案判断へ切り替える」を置いていた。

Phase 0 spike (2026-06-04・ADR-0116 §Phase 0 調査記録に全結果) で前提が変わった:

  • ② LangGraph 1.3.2 の公式 checkpoint API (interruptAfter + BaseCheckpointSaver) のみで 1 実行単位 = 1 gate の打ち切り・復元が成立 (独自 state 直列化層・streamEvents の非公式打ち切りは不要)
  • ③ wrangler 4.94 ローカル実機で WorkflowEntrypoint 内の LangGraph 実行が完走 (1 step.do = 1 gate・checkpoint JSON を step 戻り値で持ち回り・status: complete)
  • ① state サイズ実測 (本番 122 run): 最大 gate 出力 23.9KB・run 合計 MAX 74.9KB・checkpoint オーバーヘッド +1% → Workflows step 戻り値上限 (1MiB) に余裕で収まる
  • ⑥ 案B→案C の migration cost 粗上限 ~4-5 人日 = 案B を先に作ると同規模の捨て作業が発生する

代表取締役判断 (2026-06-04): 案B 続行ではなく案C 先行起案へ切替。同 (2026-06-05): Workflows の課金発生は許容 (Paid plan 前提で設計してよい)。

§1.2 現状 (As-Is)

queue consumer がフル run を 1 invocation で実行し、kill → at-least-once 再配信で全 gate 再実行・telemetry 喪失・LLM 多重課金が発生する。冪等性は手製 (seq テーブル・CAS ロック・isInflightRedelivery ガード網) を前提とする ADR-0116 案B が次の対応として未着手。

§1.3 課題

  • 16-24 分 run が worker invocation 上限を超え kill 必至 (session bedb9912 で全 gate 3 周再実行・kill 2 周分の telemetry 0 行)
  • 案B を先行すると ~4-5 人日相当が案C 移行時に捨て作業化
  • ADR-0116 が案C を「LangGraph 統合障壁未調査」のみで見送っており、Phase 0 spike で前提が反転した

§1.4 制約・要件

  • 電帳法整合 KPI: 「全 gate の試行回数が run ごとに記録される」を維持
  • ADR-0089 (進捗表示) / ADR-0101 (キャンセル) / ADR-0103 (shared triage) との互換維持
  • feature flag で旧 Queue 経路への即時 rollback 可能
  • Workers Paid plan 前提 (代表取締役 2026-06-05 課金許容)
  • 実装見積もり上限 7 人日 (超過時は中間 HITL チェックポイント)

§1.5 目標 (To-Be)

queue consumer によるフル run 実行を廃止し、Workflows に 1 step.do = 1 gate で durable execution を委譲。冪等性は Workflows ランタイムに委譲し手製ガード網を削除。Non-Goals: gate ロジック自体の改修・shared triage (ADR-0103) の変更・LLM 課金構造の変更。

検証済みの前提 (公式ドキュメント実査・2026-06-05)

初回審査 (2026-06-05) の critical 盲点 2 件「本番 Workflows の同時実行上限・instance 保持期間が未検証」に対し、Cloudflare 公式ドキュメント (developers.cloudflare.com/workflows/reference/limits/) を実査した:

制約公式値 (Free / Paid)DRP 要件との突合
同時実行 instance 数100 / 50,000DRP は週 5-15 run・1 件ずつ直列運用 (同時 1-3 instance、バースト worst 10-20)。Paid 前提で 3 桁以上のマージン (Free でも 5 倍以上)
上限到達時の挙動エラーではなく queued (waiting → queue に遷移し、空き次第 resume)「無音失敗」ではなく観測可能な queued 状態。既存 EC-3 watchdog (queued 30 分監視) がそのまま検知機構として流用できる
workflow 全体の実行時間上限無制限 (step の CPU 制限・step 数上限の範囲内)16-24 分 run に上限リスクなし
永続 state 保持 (= step キャッシュ)100MB・3 日 / 1GB・30 日run 中 (16-24 分) の step キャッシュ expired は保持期間に対し 3 桁のマージンがあり構造上起きない (checkpoint 実測 ~104KB は容量にも 4 桁マージン)
step 戻り値サイズ1MiBcheckpoint worst ~104KB で余裕
step 数上限1,024 / 10,0001 run = 10 step + retry 分で問題なし
GA 状態GA 済み (Free/Paid プランで一般提供。beta ではない)「beta のまま仕様変更」前提は陳腐化。ただし仕様変更検知の CI テストは防御として維持する

決定

queue consumer によるフル run 実行を廃止し、審査 run の実行基盤を Cloudflare Workflows に移行する:

  1. 1 step.do = 1 gate: WorkflowEntrypoint.run が 10 gate を step 単位で実行。LangGraph は interruptAfter + checkpoint 持ち回り (step 戻り値) で gate 境界停止・復元する (spike ②③ の実証構成)。checkpoint JSON には schemaVersion フィールドを必ず埋め込み、step 復元時にバージョン不一致を検出した場合は retry せず即 failed 終端 + telemetry 記録する安全弁を実装する (盲点 1 緩和)。LangGraph upgrade は「進行中 run 0 件を確認してからマージ」をデプロイ手順として運用化する
  2. 冪等性は Workflows ランタイムに委譲: kill/retry 時は完了済み step がキャッシュから返るため、ADR-0116 案B が手製実装予定だった seq 冪等テーブル・CAS ロック・再 enqueue 配線は作らない。isInflightRedelivery() 等の既存ガード網は移行完了後に削除 (feature flag で旧 Queue 経路を温存し即時 rollback 可能にする)。
  3. 入口とキャンセル: /chat/start・/runs は Workflows instance create に切替 (shared triage = ADR-0103 は不変)。進捗表示は step 内から既存 PipelineSessionDO への gateProgress patch を継続 (ADR-0089 partial 互換)、キャンセルは Workflows の terminate + DO cancelRequested 併用 (ADR-0101 互換)。Workflows terminate は実行中 step を完走させる仕様のため、step.do 内で cancelRequested を polling する間隔 (1 秒) と、LLM HTTP 呼び出しへの AbortSignal 伝播の実装方針を本決定で確定する (盲点 2 緩和)。gateProgress patch API は gateId + seq ベースの idempotency key で重複書き込みを排除する設計を必須化 (ADR-0089 で保証されない場合は本 ADR で追加実装) (盲点 3 緩和)。
  4. telemetry: 終端 step で従来同様に D1 へ 1 行書込。step 単位の試行/retry 履歴は Workflows の instance status から取得可能になるため、chunk skip イベントの独自記録 (ADR-0116 案B 設計) は簡素化する。ただし「全 gate の試行回数が run ごとに記録される」電帳法整合 KPI は維持し、retry 発生時に step 名 + 回数を telemetry 列へ記録する。instance status API への依存箇所は単一のアダプタ層に集約し、取得フィールドの型・存在チェックを CI で毎週アサート (盲点 5 緩和)。
  5. 同時実行上限・受付失敗の防御 (初回審査 critical ① への緩和機構): instance create が例外/エラーを返した場合は /chat/start・/runs が 503 + ユーザー可視のエラーメッセージで fail-loud に終端する (無音失敗を作らない)。上限到達時の queued 遷移は公式仕様で観測可能であり、既存 EC-3 watchdog (queued 30 分閾値) をそのまま検知機構として流用する。バースト検知として「同時 running instance 数 > 20」をリアルタイムアラート (Cloudflare Analytics Engine + scheduled trigger 1 時間おき) に格上げし、通知先は #ops-alert を本決定で確定。週次 telemetry レビューは趨勢確認に留める (盲点 7 緩和)。
  6. 保持期間・キャッシュ expired の防御 (初回審査 critical ② への緩和機構): 公式値 (実行時間無制限・state 保持 Paid 30 日) に対し run は 16-24 分で 3 桁マージンがあり中途 expired は構造上起きないが、防御として①run 開始時刻と各 step 実行ログの突合で「先頭再実行」を検知する統合テスト (step キャッシュ無効化検知・CI 組込) ②万一の expired 検知時は failed 終端 + telemetry 記録 (無音の先頭再実行をさせない) を実装する。
  7. Cloudflare ロックインの明示受容 (テナント層審査の条件解消・決定への格上げ): 冪等性責務 (Workflows durable execution) と監査記録経路の一部 (instance status API) を Cloudflare ランタイムへ委譲することを意識的に受容する。受容根拠: ①実行基盤は既に全面 Cloudflare (Workers/DO/Queues/D1/KV) でありロックインの限界費用は小さい ②公式 limits の実査で要件充足を定量確認済み (§検証済みの前提) ③feature flag による旧 Queue 経路 rollback と ADR-0116 案B 復帰経路の二重の撤退先を確保 ④アダプタ層で吸収しきれない構造変更が発生した場合は撤退条件に従い案B へ復帰する。
  8. ADR-0116 を Supersede する (Phase 0 調査記録は本決定の根拠として参照)。

判断基準 (Decision Drivers)

3.1 評価軸

#重要度 (係数)案件特有の解釈
1#reliable[Must] (×2.0)kill/retry 起因の telemetry 喪失・LLM 多重課金が構造的に発生しないこと
2#maintainable[High] (×1.0)手製冪等ガード網を削除しランタイム責務に委譲できること
3#operable[High] (×1.0)バースト・キャンセル・キャッシュ expired・スキーマ不一致を観測可能で fail-loud に扱えること
4#efficient[Medium] (×0.5)実装人日 (~4-5 人日) と LLM 再実行コスト (max 1 gate 分)
5#suitable[Must] (×2.0)電帳法 KPI (全 gate 試行回数記録)・ADR-0089/0101/0103 互換維持

K.O. criterion: Must 軸 (#reliable, #suitable) の score < 3 は不採用。

3.2 評価軸 × 案スコア表

各案 0-5 で評価。加重和 = (Σ score × 係数) / (満点 × Σ 係数) で正規化。

係数採択: 案C (Workflows 移行)案B (ADR-0116 chunk 化)案A (現状維持)
#reliable (Must)×2.0541
#maintainable (High)×1.0532
#operable (High)×1.0442
#efficient (Medium)×0.5435
#suitable (Must)×2.0542
加重和 (正規化)0.9430.7430.300
K.O. 通過 (Must ≥3)

検討した代替案 (Alternatives Considered)

  • 案B (ADR-0116 chunk 化): queue consumer を残し gate 単位 chunk 化 + 手製 seq 冪等テーブル/CAS ロックで再配信を封じ込め — 不採用理由: Phase 0 spike で Workflows + LangGraph 公式 checkpoint API のみで durable execution が成立することが実証され、案B 実装 ~4-5 人日が案C 移行時に捨て作業化する。#maintainable で劣後。
  • 案A (現状維持): queue consumer のフル run 継続 — 不採用理由: Must 軸 #reliable で K.O. (kill 起因の telemetry 喪失と LLM 多重課金が構造的に解消されない)。

影響 (Consequences)

§5.1 正の影響 (Good)

  • kill/retry 起因の telemetry 喪失と LLM 多重課金が durable execution によって構造的に解消
  • 手製の seq 冪等テーブル・CAS ロック・isInflightRedelivery ガード網を削除でき保守負荷低減
  • 公式 checkpoint API のみで成立するため LangGraph 独自 fork・streamEvents 非公式打ち切りが不要
  • Workflows step 課金は週 500 run シナリオで ~2.2 万 step/月 (同梱枠内)・checkpoint DO write は月 $0.11 以下で実質増分ゼロ

§5.2 負の影響 (Bad)

  • LangGraph minor upgrade 時の checkpoint スキーマ不一致リスク (盲点 1) — schemaVersion 安全弁 + 進行中 run 0 件確認デプロイで緩和するが運用手順が増える
  • Workflows terminate は実行中 step を完走させるためキャンセル後最大 1 gate 分の LLM 課金が継続 (盲点 2) — AbortSignal 伝播実装で短縮するが完全排除は不可
  • Cloudflare 依存度が増大 (Workflows API・instance status API のフィールド変化リスク) — アダプタ層集約 + CI 毎週アサートで緩和
  • 4-5 人日のスケジュール圧力下でステージング検証が省略されるリスク (盲点 6) — ステージング検証を本番移行の必須ゲートとして本 ADR で明文化
  • Workers Paid plan 課金が発生 (代表取締役承認済)
  • 1 人運用での監視タスク累積 (テナント層指摘): 本 ADR で増える定常監視は ①週次 telemetry レビューへの撤退条件 3 指標追加 (5 分/週) ②CI 週次アサート (instance status API フィールド・自動) ③リアルタイムアラート対応 (発火時のみ)。合計 **0.4 人時/月** の増分で、削除されるガード網の保守 (isInflightRedelivery 系の障害切り分け・実績 ~1-2 人時/月) より小さく、純減を見込む。移行 4 週後のレビューで実測を検証する

§5.3 中立・トレードオフ (Neutral / Trade-offs)

  • 冪等性責務をアプリケーション層から Cloudflare ランタイムへ移譲 (ベンダーロックインと保守簡素化のトレードオフ)
  • telemetry の retry 履歴取得経路が独自記録 → Workflows instance status API へ変化 (API 安定性に依存するがアダプタ層で吸収)
  • ADR-0116 を Supersede (Phase 0 調査記録は本 ADR の根拠として参照継続)
  • telemetry 改ざん検知 (hash chain 等) の要否 (テナント層指摘): 本 ADR では電帳法 KPI の記録経路を D1 直接 append (決定 4) に置き、instance status API は補助情報源に格下げすることで API 依存リスクを縮小する。記録自体の改ざん検知 (hash chain・別ストレージ退避) は 98_audit_log の改ざん防止検討 (既存の将来課題) と論点が同一のため、合流させて別 ADR で扱う (本 ADR のスコープ外と明示)

撤退条件 (Rollback Plan)

  • feature flag (入口の Workflows/Queue 切替) で即時 rollback 可能とし、移行後 4 週で以下のいずれかで旧 Queue 経路へ rollback:
    • ① kill/retry 起因の telemetry 喪失が 1 件でも再現
    • gate 重複実行 (LLM 二重課金) が 1 件以上発生した時点で即時調査フリーズ (新規 run 受付停止) + rollback 判断 (盲点 4 緩和: 当初「2 件以上」から引き下げ。許容損失額上限は 1 run あたり LLM 課金最大想定 ~数百円規模を踏まえ「1 件 = 即時停止」を閾値とする)
    • ③ Workflows 起因の新規障害が 3 件以上
  • 本番 Workflows の制約 (同時実行数・instance 保持期間・terminate 挙動) が実装中に要件を満たさないと判明した場合は実装を中断し ADR-0116 案B へ復帰 (Phase 0 資産は流用可能)
  • 実装見積もりが 7 人日を超過した時点で中間チェックポイント (継続/撤退の HITL 判断)
  • ステージング検証 (並列 3 run・kill 注入・LLM 429・DO 書込競合) を本番移行の必須ゲートとし、CI pass のみでの本番移行を承認条件から除外 (盲点 6 緩和)

コスト試算

(パイプライン生成時に欠落した §コスト試算 H2 を起案者生テキスト v2 から復元・HITL 追補)

項目工数 / コスト
Workflow 定義 + 入口切替 + DO-backed progress patch 互換~2-3 人日
DO-backed BaseCheckpointSaver (channel 分割保存・zod/schemaVersion 検証)~1 人日
e2e (mocked + 実 LLM) + kill/retry 注入 + ステージング検証~1 人日
実装合計~4-5 人日 (上限 7 人日超過で中間 HITL チェックポイント)
旧ガード網削除 + 監視移行 (移行安定後の別 PR)~0.5 人日
運用: Workflows step 課金 (週 500 run シナリオ ~2.2 万 step/月・Paid 同梱枠内) + checkpoint DO write月 $0.11 以下 — 実質増分ゼロ
LLM 課金不変 (gate 実行回数は変わらない。retry 時の再実行は最大 1 gate 分)
監視タスク増分 (週次レビュー 3 指標 + CI 週次アサート + アラート対応)~0.4 人時/月 (削除されるガード網保守 ~1-2 人時/月 より小さく純減見込み)

Confirmation

検証手段 / 実行頻度 / 違反時対応 の 3 要素で記述:

  • 実 LLM full-run e2e (drp-real-e2e.yml) — リリースブランチごと / CI fail で merge ブロック: 16 分級 draft の単発完走 + 全 gate telemetry 記録 (kill 起因 telemetry 喪失 0 件/月)
  • kill/retry 注入テスト — 週次 + 移行 4 週監視期間中は日次: step 中断 → retry で二重 LLM 実行 0・完了済み step のキャッシュ返却を確認 / 違反時は撤退条件①②に該当判定
  • 「終端 run 数 = telemetry 行数」一致 + retry 発生時の step 名・回数記録 100% — 週次 telemetry レビュー / 不一致時は電帳法 KPI 違反として即時調査
  • ADR-0101 キャンセル (terminate + DO 併用) と ADR-0089 進捗表示の回帰 e2e — CI 毎回 / fail で merge ブロック
  • ステージング検証 (並列 3 run 同時実行・LLM 429 注入・DO 書込競合シミュレーション・キャンセル後の LLM 呼び出し継続時間計測patch 重複送信時の最終状態一致確認) — 本番移行前 1 回 + 重要変更時 / ローカル spike と本番ステージング検証を明示的に分離し、ローカルのみでの pass は本番移行の承認条件から除外 (盲点 6)
  • LangGraph minor upgrade 時の checkpoint スキーマ再検証 — lockfile 差分検出時に CI でスキーマ互換テストを実行・依存バージョンは lockfile 固定 / 加えてデプロイ手順として「進行中 run 0 件を確認してからマージ」を運用化 (盲点 1)
  • checkpoint schemaVersion 不一致時の failed 終端 + telemetry 記録 の単体テスト — CI 毎回 (盲点 1)
  • step キャッシュ無効化 (先頭再実行) を検知する統合テスト — CI 毎回 (決定 6 と対応)
  • Workflows instance status API フィールド型・存在チェック — CI 週次アサート / フィールド変化検知時は telemetry 記録経路の修正を実施 (盲点 5)
  • 「同時 running instance 数 > 20」リアルタイムアラート (Cloudflare Analytics Engine + scheduled trigger 1 時間おき・通知先 #ops-alert) — 常時 / 閾値超過時は即時調査 (盲点 7)
  • Jr 向け引継ぎドキュメント整備 (テナント層指摘・2026-10 入社予定者の認知負荷対策) — 実装完了時 1 回 / 未整備なら Implementation Status を Done にしない: DRP 層別文書体系 (ADR-0117) に「Workflows 実行基盤」ページを追加し、Workflows + LangGraph checkpoint + DO idempotency + AbortSignal 伝播の関係を 1 ページで説明。drp-ops Skill の運用手順も同期
  • 移行後 4 週の撤退条件監視 (上記 3 指標) を週次 telemetry レビューに追加 / 撤退条件②は 1 件検知時点で新規 run 受付停止の自動アクション

長期的影響 (Long-term)

  • Review After: 2026-12 月初 (移行 ~6 ヶ月後)。再評価指標: ①Workflows step 課金実績 vs 試算 (2.2 万 step/月) ②retry 発生率と step 名分布 (LangGraph/LLM 起因の切り分け) ③LangGraph upgrade 対応回数と checkpoint スキーマ非互換の実発生数 (盲点 1 の事後検証) ④Cloudflare Workflows 仕様変更件数とアダプタ層の吸収実績 (ロックイン受容判断の再評価) ⑤監視タスク実測 (0.4 人時/月 見込みとの突合)
  • LangGraph minor upgrade は lockfile 固定 + スキーマ互換 CI の運用が続く限り安全だが、メジャーアップグレード (2.x) 時は checkpoint 互換の全面再検証を要する (Review After で採用継続を判断)
  • ADR-0116 案B への復帰経路は Phase 0 資産 (state 実測・spike 知見) が陳腐化するまで有効 — Review After 時に復帰経路の现実性も再評価する

Corrigendum (本文不変の訂正追記)

  • 決定 5 の計数機構変更 (2026-06-05・代表取締役承認): 「同時 running instance 数 > 20」アラートの計数機構を、本文記載の Cloudflare Analytics Engine + scheduled trigger 1 時間おき から Workflows REST API count (アダプタ層 instance_status.ts 経由) + scheduled trigger 1 時間おき に変更して実装した (PR #1487)。理由: REST API で正確な現在値を直接取得でき、イベント計装 (Analytics Engine への書込側実装) が不要で単純。閾値 >20 (env RUNNING_ALERT_THRESHOLD で上書き可・既定 20)・1h cron は本文どおり。本文 §決定 5 は原文のまま保持し、本節を正とする。
  • 決定 5 の通知先汎用化 (2026-06-05・corrigendum 第 2 項): 通知先を本文記載の Slack #ops-alert から Google Chat の ops-alert スペース webhook に変更した (PR #1489・Workspace 運用に整合)。secret 名は OPS_ALERT_SLACK_WEBHOOKOPS_ALERT_WEBHOOK に改名。{"text": ...} POST 互換のため Slack incoming webhook URL を投入してもそのまま動く (URL 差し替えだけで戻せる)。

参照 (References)

  • 関連 ADR: ADR-0116 (Supersede 対象・Phase 0 調査記録の参照元)、ADR-0089 (進捗表示 partial 互換)、ADR-0101 (キャンセル互換)、ADR-0103 (shared triage 不変)
  • 関連 PR/Issue: -
  • 外部資料: Cloudflare Workflows 公式ドキュメント (developers.cloudflare.com/workflows/reference/limits/)、LangGraph GitHub PR #1893 / Issues #1891, #2034 (checkpoint スキーマ無告知変更の実績)、『Accelerate』ch.4 (sunk cost 効果)