• Status: Accepted
  • Mode: Standard
  • Kruchten Type: Existence/Property
  • Scope: platform
  • Implementation Status: Not Started
  • 起案者: [email protected]
  • 起案日時 (JST): 2026-05-14 02:17
  • 承認日時 (JST): 2026-05-14 02:25
  • Deciders: [email protected] (単独)

1. コンテキスト

1.1 背景 (Background)

ADR-0035 で drp/public/chat.html にローカル draft JSON ロードボタンを実装したが、ロード対象はあくまで起案者ローカルのファイル選択方式である。本日 (2026-05-14) の ADR-0036 投入時、ファイル選択ダイアログ (macOS Finder) が /tmp/ を非表示にしており、起案者は cp /tmp/adr0036_draft.json ~/Downloads/ で手動コピーを実施した。

また現在の /tmp/adrNNNN_draft.json 運用には以下の構造的弱点がある:

  • 端末横断不可: PC で python3 等で draft を生成しても、tablet / phone から投入できない (ローカルファイルのため)
  • PR 作成後の残骸: Pipeline /draft 投入で PR が作成されても /tmp/adrNNNN_draft.json は残存、次回起案時に古い draft と新規 draft の混同リスク
  • 再投入時の整合性管理: /draft が中途失敗した時、起案者は同じ /tmp 上のファイルを再読み込みするが「最新版か旧版か」をファイル内部の context 文字数で判断する手作業発生
  • 複数端末での協調不能: 複数の draft を準備して「他端末で確認しながら投入」のワークフローが現状ない

1.2 現状 (Current State / As-Is)

  • ADR-0035 (basic + R2/R3/R5) 本日 2026-05-14 01:43 JST に main マージ + 本番デプロイ済
  • 本日 2026-05-14 の ADR-0035/0036 投入: ローカルパス起因の手作業 1 件発生 (Downloads コピー)
  • /tmp/ に残存している draft JSON: 2 件 (adr0035_draft.json / adr0036_draft.json、本日の作業で生成)
  • 同名 draft の再生成: ADR-0035 で 1 回発生 (起案当初のスコープが GitHub 読み込みボタンだったため書き直し)
  • ADR-0035 hidden field loaded-from-file 利用率: 未測定 (Pipeline backend が payload に含めるか別作業)
  • Cloudflare KV の既存利用状況: drpSTATE (Socratic session) / RATE_LIMIT などで利用中、新規 namespace 追加に技術ブロックなし

1.3 課題 (Problem)

  1. ファイル picker の探索コスト: 起案者がファイル選択ダイアログで /tmp 等の非表示パスを毎回探す。本日のように Finder 制約に当たると手動コピーが必要、起案フローが分断される
  2. 端末横断不可: PC で起案準備 (CLI で /tmp に書き出し) → phone で投入確認 のフローが現状不可能、起案者の作業端末固定化
  3. PR 作成後の残骸: 投入完了済 draft が /tmp に残り、3 ヶ月後に新規起案で「あれ、これ古いやつ?」と混同。月次クリーンアップ運用も負担
  4. 失敗時の再投入難: /draft 失敗 (本日 ADR-0035 投入 1 回目の JSON escape error) で起案者は手元の /tmp を再読み込みするが、「Pipeline で何が起きて再投入が必要か」のコンテキストがファイル内部に残らない

1.4 制約・要件 (Constraints & Requirements)

  • 既存 ADR-0035 (ローカル draft JSON ロードボタン) を Supersede しない: 補完関係として共存、ローカルファイル投入も継続可能
  • 既存 Basic 認証 (chat UI 全体に適用済) で保護、追加認証不要
  • Cloudflare KV を新規 binding として追加 (既存 KV namespace と分離して DRAFTS_KV を作成)
  • KV 利用料: 100k reads / day 無料枠内、月 10-30 件起案では問題なし
  • failed /draft 時の draft は KV に keep (削除しない、起案者が再試行できる状態を維持)
  • 実装規模 6-7 時間 (Backend 3 endpoint + frontend プルダウン UI + auto-delete hook)
  • draft の機微情報リスク: 既存ローカル draft と同等 (取引先名 / 金額等は事前マスク前提)、KV 側に PII フィルタは別 ADR で検討

1.5 目標 (Goals / To-Be)

  • 起案者が draft をアップロード → chat UI のプルダウンに列挙 → 選択 → 4 フィールド一括 populate のフロー確立
  • /draft 投入で PR 作成成功時に該当 draft を Cloudflare KV から自動 DELETE (auto-cleanup)
  • /draft 失敗時 (Pipeline エラー / PR 作成失敗) は KV に残し、起案者が再試行可能
  • 端末横断: PC でアップロード、tablet / phone から投入 (Basic Auth は両方で同じ)
  • 残骸 draft 件数: 目標 1 ヶ月平均 ≤ 1 件 (auto-delete が機能)

2. 決定

Cloudflare KV ベースの draft staging を Decision Pipeline に導入する。新規 KV namespace DRAFTS_KVdrp/wrangler.toml に binding 追加し、POST /drafts / GET /drafts / DELETE /drafts/:id の 3 endpoint を src/index.ts に実装する (既存 Basic 認証 middleware を継承)。chat.html に「サーバー draft (KV staging)」プルダウン + アップロード / 読み込み / 削除の 3 ボタンを追加 (ADR-0035 のローカル投入ボタン直下に配置、共存)。/draft 内部に auto-delete hook を追加し、PR 作成成功時のみ payload の draft_idenv.DRAFTS_KV.delete(draft_id) を実行する (failed 時は KV に残し再試行可能)。

2.1 KV binding 追加

drp/wrangler.toml に新規 KV namespace DRAFTS_KV を binding:

[[kv_namespaces]]
binding = "DRAFTS_KV"
id = "<wrangler kv:namespace create で発行>"

2.2 新規 endpoint (drp/src/index.ts)

3 つの endpoint を追加 (いずれも既存 Basic 認証 middleware を継承):

  • POST /drafts: body = {id, author, title, context, options} の JSON。KV DRAFTS_KV.put(id, JSON.stringify(payload), { metadata: { mtime: Date.now(), title } })。サイズ上限 1 MB、4 キー検証で fail なら 400 返却
  • GET /drafts: KV DRAFTS_KV.list() で全件取得、metadata から [{id, title, mtime}] 配列を返却 (mtime 降順)
  • DELETE /drafts/:id: KV DRAFTS_KV.delete(id) を実行、204 返却

2.3 chat UI 拡張 (drp/public/chat.html)

ADR-0035 で追加した「📂 ドラフト JSON を読み込む」ボタンの直下に以下を追加:

<div class="field">
  <label>サーバー draft (KV staging):</label>
  <select id="draft-select"><option value="">-- 選択 --</option></select>
  <button type="button" id="load-server-draft-btn">📥 サーバーから読み込み</button>
  <button type="button" id="upload-draft-btn">⬆️ ローカル JSON をアップロード</button>
  <button type="button" id="delete-server-draft-btn">🗑️ 削除</button>
</div>
  • ページロード時に GET /drafts<select> を populate (id + title + mtime 表示)
  • 「読み込み」: 選択 id を GET /drafts/:id (実装方法 1 案) または GET /drafts のキャッシュから取り出し、4 フィールドに自動投入 + hidden field loaded-from-file=server:<id> set
  • 「アップロード」: ローカルファイル選択 → ADR-0035 既存 FileReader で読み → POST /drafts で KV 投函 → プルダウン再構築
  • 「削除」: 確認ダイアログ + DELETE /drafts/:id → プルダウン再構築

2.4 /draft 内部の auto-delete hook

/draft の Pipeline 処理完了 + PR 作成成功時に、payload 内の draft_id (request body から取得、optional) が存在すれば await env.DRAFTS_KV.delete(draft_id) を実行。PR 作成失敗・Pipeline エラー時は削除しない。

2.5 判断基準 (重み付き)

  1. 端末横断 + 自動削除の構造化 (最重要) — 残骸 draft / 古い draft 混同を構造的に防止
  2. ADR-0035 との共存 (高) — ローカルファイル投入も継続可、Supersede 不要
  3. 既存認証 + KV インフラの最大活用 (高) — Cloudflare KV / Basic Auth / wrangler の既存パターン踏襲、新規認証層なし
  4. failed 時の冪等性 (中) — 失敗時は KV に残し、再試行可能

3. 検討した代替案 (Alternatives Considered)

  • 案 A (採用): Cloudflare KV ベースの draft staging (POST/GET/DELETE /drafts) + /draft auto-delete hook + chat.html プルダウン UI

    • Good: 端末横断 + 自動削除を構造的に実現、ADR-0035 と共存
    • Good: 既存 Cloudflare KV / Basic Auth / wrangler パターン踏襲、新規認証層なし
    • Good: failed /draft 時に KV に残し再試行可能、冪等性を維持
    • Bad: KV の eventual consistency (最大 60 秒) で端末横断時に列挙遅延の可能性
    • Bad: draft が server 経由で外部送信、ローカル保持より機微情報リスクがやや上がる
  • 案 B: 現状維持 (ADR-0035 のローカル draft 投入のみ) — 不採用理由: 実装コストゼロだが、端末横断不可、PR 後の残骸が累積、ファイル picker 探索コストが継続。本 ADR の主目的を全く解決しない。

  • 案 C: drag-and-drop UI のみ追加 (ADR-0035 拡張、server 不要) — 不採用理由: Finder からの直接ドラッグで探索コスト削減できるが frontend 完結のため端末横断不可、auto-delete 不可、本 ADR の主目的 (lifecycle 管理) を満たさない。

  • 案 D: File System Access API (showDirectoryPicker) で起案者がフォルダを指定 + 自動スキャン — 不採用理由: frontend 完結で KV 不要だが、Chrome 専用 (Safari/Firefox 未対応)、端末横断不可、auto-delete も実現困難。

  • 案 E: GitHub Gist にアップロード → Gist URL を chat UI に貼り付け — 不採用理由: GitHub 既存インフラ活用で端末横断可能だが、private Gist でも GitHub への外部送信、PII リスクが KV より高い。GitHub API レート制限の管理も別途必要。

4. コスト試算

項目工数金額
KV binding + wrangler.toml 更新 + namespace 作成0.5 h$0
3 endpoint (POST/GET/DELETE /drafts) 実装1.5 h$0
/draft auto-delete hook 追加0.5 h$0
chat.html UI (プルダウン + 3 ボタン + JS)1.5 h$0
ローカル wrangler dev + 本番デプロイ + 動作確認1.5 h$0
ADR-0037 起案 + Accepted + マージ1 h$3
合計約 6.5 時間約 $3 (≈ [MASKED:AMOUNT])

機会費用換算: 6.5 h × Jr 想定時給 [MASKED:AMOUNT]/h = [MASKED:AMOUNT] + LLM [MASKED:AMOUNT] ≈ [MASKED:AMOUNT] 投資

年間削減効果:

  • ファイル picker 探索コスト削減: 月 5-10 件 × 15-30 秒 = 月 1.25-5 分 × [MASKED:AMOUNT]/h × 12 ヶ月 = 年 [MASKED:AMOUNT]-4,000
  • 残骸 draft 混同回避 (月次クリーンアップ廃止): 月 5 分 × 12 ヶ月 = 年 1 時間 = 年 [MASKED:AMOUNT]
  • 端末横断 (PC 作成 → 移動先で確認 + 投入): 月 1-2 件 × 30 分 × [MASKED:AMOUNT]/h × 12 ヶ月 = 年 [MASKED:AMOUNT]-48,000
  • 失敗時再投入の簡略化: 年 5-10 件 × 1-2 分 = 年 5-20 分 = 年 [MASKED:AMOUNT]-1,330
  • 合計: 年 [MASKED:AMOUNT]-57,000 削減見込み (投資回収 5-11 ヶ月)

5. 影響 (Consequences)

5.1 正の影響 (Good)

  • 端末横断起案が可能になる: PC でアップロード → tablet / phone から Basic Auth で投入確認、起案者の作業端末固定が解消
  • PR 作成成功時の auto-delete により残骸 draft が構造的に削減、目標月平均 ≤ 1 件
  • ADR-0035 ローカル投入と共存 (Supersede 不要)、起案者がワークフローに応じて選択可能
  • 既存 Cloudflare KV / Basic Auth / wrangler パターンを踏襲、新規認証層・新規インフラ不要
  • failed /draft 時は KV に draft が残り、再試行が冪等に可能
  • Jr エンジニア (2026-10 入社予定) の起案フロー統一感向上

5.2 負の影響 (Bad)

  • KV のレート制限 / eventual consistency: Cloudflare Workers KV は最大 60 秒の伝播遅延あり、1 端末でアップロード直後に他端末でリストすると遅延の可能性 (起案フローでは実用上問題なしと判断するが、UX としては気付き要因)
  • draft 機密情報の server 経由送信: ローカル draft より外部送信リスクが高まる (既存 Pipeline で /draft body は LiteLLM Gateway 経由で OpenAI/Anthropic に送信済のため追加リスクは限定的だが、PII フィルタ層は本 ADR 範囲外で別 ADR 検討)
  • 実装工数 6.5 時間 + 約 [MASKED:AMOUNT] 投資: 短期的に他作業を圧迫
  • draft ID 命名規約の未 enforce: ADR 番号 (adr0037 等) を ID にする規約は推奨どまり、衝突リスクや Pipeline slug 採番との不整合可能性が残る (別 ADR で enforcement 検討)

Status / Mode / Scope は 2026-06-11 に遡及追加 (ADR-0031 corrigendum パターン)。出典: Status = 旧形式「## ステータス」節の機械転記 / Mode = 旧 README §既存 ADR 一覧の推定値 (git 履歴) / Scope = ADR-0049 4 層分類の遡及付与 (PR レビューで確定)。

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

  • KV 容量肥大化リスク: failed draft の累積で KV が肥大化する可能性、月次クリーンアップ or TTL 設定で対応 (別 ADR で起案可能性)
  • draft schema 拡張 (4 キー以上、例: ADR-0036 で Confirmation セクション追加時): version 管理を別 ADR で起案
  • multi-user 化 (Jr 入社後): owner フィールド追加 + UI フィルタを別 ADR で対応
  • Cloudflare 課金: KV reads/writes 無料枠 (100k reads/day) 内で月 10-30 件起案は問題なし、影響軽微

5.4 影響範囲 (変更ファイル)

  • drp/src/index.ts: 3 endpoint 追加 + /draft 内部 auto-delete hook (+80 行)
  • drp/wrangler.toml: KV binding 追加 (+5 行)
  • drp/public/chat.html: プルダウン UI + 3 ボタン + GET/POST/DELETE 呼出 JS (+60 行)
  • drp/.dev.vars (任意): ローカル開発用 KV (wrangler kv:namespace create DRAFTS_KV --preview)

5.5 不変対象

  • ADR-0035 ローカル draft JSON ロードボタン (継続稼働、補完関係)
  • 既存 /draft / /chat/* エンドポイント (auto-delete hook 追加のみ、既存挙動不変)
  • 既存 KV namespace (STATE / RATE_LIMIT 等、新規 DRAFTS_KV を分離)
  • Basic 認証 middleware (既存パターンを継承)

6. 完了条件 (定量メトリクス)

  1. KV binding 追加済: grep -c "DRAFTS_KV" drp/wrangler.toml → >= 1
  2. 3 endpoint 実装済: grep -cE "app\.(post|get|delete).*'/drafts" drp/src/index.ts → 3
  3. chat.html にプルダウン UI 実装済: grep -cE 'id="draft-select"|id="upload-draft-btn"|id="delete-server-draft-btn"' drp/public/chat.html → 3
  4. /draft auto-delete hook 実装済: grep -c "DRAFTS_KV.delete" drp/src/index.ts → >= 1
  5. ローカル wrangler dev で動作確認: アップロード → リスト → 読み込み → /draft 投入 → PR 作成成功時に DELETE 自動実行を curl + ブラウザで目視
  6. 本番デプロイ後の動作確認: 実 draft で 1 回投入成功 + auto-delete 確認
  7. CI markdown-link-check PASS / TypeScript build PASS

7. 撤退条件 (Rollback Plan)

判定指標閾値判定タイミング対応
プルダウン UI が使われない3 ヶ月後の Pipeline ログ集計でアップロード経由起案が起案総数の 20% 未満3 ヶ月後 Review AfterUI 縮退 (削除 or feature flag で hide)、ADR-0035 ローカル投入のみ運用に戻す
KV 障害で起案フロー停止月 1 件超 KV エラーで /drafts 失敗月次振り返りフォールバック (ローカル投入のみ案内) を UI に追加
auto-delete の暴発failed /draft なのに削除される事象障害時hook を一時無効化、削除条件 (PR 作成成功 + 200 応答) を再点検
KV 容量上限月 100 件超の draft 累積 (auto-delete 不全)月次容量監視古い draft の TTL 設定 (例: 30 日) を追加 ADR で起案

8. 長期影響

6 ヶ月後の負債化リスク:

  1. KV 容量肥大化: failed draft の累積で KV が肥大化 → 月次クリーンアップ or TTL 設定で対応
  2. draft schema 拡張: 4 キー以上のフィールド (例: ADR-0036 で Confirmation セクション追加時) → version 管理を別 ADR で起案
  3. multi-user 化: Jr 入社後、複数起案者で draft が混在 → owner フィールド追加 + UI フィルタを別 ADR で対応
  4. PII リスク: KV に取引先名等が混入する可能性 → POST /drafts に PII フィルタ層追加を別 ADR で検討

観測指標 (月次):

  • アップロード経由起案率: ADR 起案数のうち KV アップロード経由の割合 (目標 80% 以上)
  • auto-delete 成功率: PR 作成成功時の delete 実行率 (目標 100%)
  • 残骸 draft 件数 (KV 内): 目標 月次平均 ≤ 1 件 (failed draft のみ)
  • 端末横断起案: PC アップロード → 別端末で投入の発生件数

Review After:

  • 1 ヶ月後 (2026-06-14): UI 利用率測定、auto-delete 成功率確認
  • 3 ヶ月後 (2026-08-14): 撤退条件 (利用率 < 20%) 判定、KV 容量チェック
  • 6 ヶ月後 (2026-11-14): Jr 入社後の運用感ヒアリング、multi-user 化要否判定

Confirmation (準拠確認 / Fitness Function)

本セクションは ADR-0036 (Accepted 2026-05-14) で遡及追加された。ADR-0031 パターン (業界標準準拠メタデータ後付け = 誤字修正範疇) に準拠する遡及で本文の意思決定内容は不変。

  • 検証手段: 月次レビューで KV draft 利用率 + auto-delete 成功率測定 + 手動 QA
  • 実行頻度: 月次
  • 違反時の対応: 月次レビューで集計

参照 (References)

  • 関連 ADR: ADR-0035 (ローカル draft JSON ロードボタン、本 ADR と共存・補完関係)、ADR-0036 (本日 2026-05-14 投入時に Finder 制約事象が発生)
  • 関連 PR/Issue: (要追記)
  • 外部資料: Cloudflare Workers KV ドキュメント (eventual consistency 最大 60 秒)、wrangler kv:namespace create CLI