型付き辺: 出 3 / 入 0
ADR-0083: Gate 2 整合性チェックの ADR 一覧キャッシュ導入
- Status: Accepted
- Mode: Standard
- Kruchten Type: Existence/Property
- Scope: platform
- Implementation Status: Done
- 起案者: [email protected]
- 起案日時 (JST): 2026-05-28 05:46
- 承認日時 (JST): 2026-06-21
- Deciders: [email protected] (単独)
コンテキスト
1.1 背景
Gate 2 (consistency.ts) は毎回 GitHub API で全 ADR ファイル一覧と内容を取得している。ADR 件数の増加とともに、Pipeline 実行ごとの GitHub API 負荷が累積的に増加してきたため、キャッシュ層導入の議論を開始した。
1.2 現状
80+ ADR ファイル。fetchAdrSummaries は毎回 REST + GraphQL で全件取得している。
1.3 課題
(1) 5 ドラフト投入で 10 subrequest 発生。(2) レスポンス ~200KB。(3) rate limit 消費非効率。
1.4 制約・要件
- Workers KV (eventually consistent、TTL ベースキャッシュ)
- ADR 変更頻度: 日 0-3 件、TTL 1 時間で十分
- 既存 consistency.ts の判定ロジック不変
1.5 目標
fetchAdrSummaries の結果を DRAFTS_KV に TTL 付きでキャッシュする。新規 ADR マージ直後のキャッシュ無効化は手動 Runbook + 将来的な自動化で対応する。
1.6 KV Eventually Consistent 特性への対処 (#reliable の根拠)
Cloudflare KV は eventually consistent だが、本ユースケースでの影響は以下の理由で限定的:
(1) 整合性ウィンドウの定量評価: Cloudflare の KV 伝播遅延は通常 60 秒以内 (cf. Cloudflare docs: "changes are usually visible globally within 60 seconds")。TTL=3600s に対し伝播遅延 60s は 1.7% の追加不整合ウィンドウであり、実用上無視可能。
(2) 手動無効化後の read-after-write: DELETE _cache:adr-summaries 後の次回 fetchAdrSummaries は cache miss → GitHub API fetch → KV put → 最新データ取得。同一 Worker instance 内の read-after-write は KV の仕様上一貫性が保証される (same colo, same request path)。ただし Gate 1 盲点 #4 指摘のとおり、DELETE → 次回 fetchAdrSummaries はクロスリクエストシナリオであり、同一リクエストスコープ内の保証は適用されない可能性がある。Cloudflare KV ドキュメントの正確な引用と、クロスリクエストでの保証有無の精査は実装フェーズで完了させる(要追記)。
(3) 誤通過の影響評価: 仮にキャッシュが古い ADR 一覧を返した場合、最悪ケースは「新規 ADR との CONFLICT/SUPERSEDE が検出されない」。これは Gate 3 (Parallel Review) と Gate 4 (Scoring) で代替検出可能 (多層防御)。かつ ADR 起案頻度 (月 5-8 件) と TTL (1h) を考慮すると、同日に ADR マージ + 別 ADR pipeline 投入が重なる確率は月 1-2 回程度。ただし Gate 1 盲点 #5 のとおり「Gate 3・Gate 4 は Gate 2 の完全な代替ではなく補完」と位置づける。
(4) Force refresh 確実化: DELETE 後に即座に GET /drafts/_cache:adr-summaries で 404 を確認するスクリプトを Runbook に記載し、運用者が伝播完了を検証可能にする。複数リージョンの Worker endpoint に対する 404 確認手順も Runbook に含める。
1.7 ステークホルダー
- Pipeline 利用者: Gate 2 応答時間改善
- ADR 起案者: 新規 ADR マージ直後の最大 1 時間不整合(手動無効化で回避可能)
1.8 過去 ADR との関係
| ADR | 関係 |
|---|---|
| ADR-0019 (LangGraph 基盤) | Confirms |
| ADR-0037 (KV draft staging) | Confirms — DRAFTS_KV namespace 共用、_cache: prefix 分離 |
| ADR-0077 (Telemetry) | Confirms (盲点 #3 反映により Neutral から変更) — キャッシュ可観測性のメトリクス計装を必須化 |
Review After: 2026-08-28 (3 ヶ月後)
決定
DRAFTS_KV namespace に _cache:adr-summaries キーで TTL=3600s のキャッシュを保持し、cache miss 時のみ GitHub API で fetchAdrSummaries を実行する。手動無効化は DELETE /drafts/_cache:adr-summaries + 404 確認スクリプトで実施し、将来的に GitHub Actions による自動無効化への移行を計画する。テレメトリ計装 (cache_hit/miss/invalidate、cached_at、X-Cache-Age) を ADR-0077 パイプラインに接続し、可観測性を確保する。
判断基準 (Decision Drivers)
3.1 評価軸 (Q42 9 タグから 3-5 個選定)
重要度ラベル係数: Must ×2.0 / High ×1.0 / Medium ×0.5
| # | 軸 | 重要度 (係数) | 案件特有の解釈 |
|---|---|---|---|
| 1 | #reliable | [Must] (×2.0) | キャッシュが古いデータを返しても CONFLICT/SUPERSEDE 検出に致命的影響を与えないこと。KV 伝播遅延が許容範囲内であること |
| 2 | #efficient | [Must] (×2.0) | GitHub API rate limit 消費を実質的に削減すること。subrequest 数とペイロードサイズの削減 |
| 3 | #operable | [High] (×1.0) | キャッシュ無効化が運用者に理解しやすく、Runbook 通り実行可能であること。可観測性が担保されること |
| 4 | #maintainable | [High] (×1.0) | 既存 consistency.ts への変更を最小化し、将来の ADR 件数増加に耐えうる構造であること |
| 5 | #secure | [Medium] (×0.5) | キャッシュデータの機密性が ADR-0037 アクセス制御ポリシーに準拠すること |
K.O. criterion: Must 軸の score < 3 は不採用。
3.2 評価軸 × 案スコア表
| 軸 | 係数 | 採択案 (A) | 案 B (ETag) | 案 C (Cache API) | 案 D (現状維持) |
|---|---|---|---|---|---|
#reliable | ×2.0 | 4 | 5 | 4 | 5 |
#efficient | ×2.0 | 4 | 2 | 4 | 1 |
#operable | ×1.0 | 3 | 2 | 3 | 5 |
#maintainable | ×1.0 | 4 | 2 | 3 | 4 |
#secure | ×0.5 | 3 | 4 | 3 | 5 |
| 加重和 (正規化) | 0.755 | 0.605 | 0.711 | 0.689 | |
| K.O. 通過 (Must ≥3) | ✓ | ❌ (#efficient=2) | ✓ | ❌ (#efficient=1) |
加重和は K.O. 通過候補のタイブレーク用。案 A は K.O. 通過かつ最高スコア。
検討した代替案 (Alternatives Considered)
- 案 A【採用】: DRAFTS_KV に
_cache:adr-summariesキーで TTL=3600s キャッシュ。miss 時のみ GitHub API。手動無効化は DELETE + 404 確認。影響: consistency.ts のみ。工数 ~1.5h (Gate 1 盲点 #10 を反映し再見積もり 4-6h、要追記)。KV 伝播遅延は 60s 以内で実用上無視可能 (cf. §1.6)。 - 案 B: ETag 条件付きリクエスト — 不採用: GraphQL は ETag 非対応。
- 案 C: Workers Cache API — 不採用: 自前 JSON キャッシュには KV が適切。
- 案 D: 現状維持 — 不採用: rate limit 消費非効率が継続。ただし盲点 #8 のとおり実消費量の定量データが未提示のため、実装前に過去 30 日間の rate limit 消費ログを確認し本決定の妥当性を再検証する (要追記)。
影響 (Consequences)
5.1 正の影響 (Good)
- GitHub API subrequest 数の削減 (5 ドラフト投入時 10 → ~2、TTL 内 cache hit 時)
- Gate 2 応答時間の短縮 (~200KB のネットワーク往復除去)
- rate limit 消費の削減によりピーク時の枯渇耐性向上
- テレメトリ計装により Gate 2 整合性チェックの可観測性が向上 (ADR-0077 Confirms)
5.2 負の影響 (Bad)
- キャッシュ可観測性の欠如リスク (盲点 #3): 計装が不十分な場合、キャッシュ起因の誤判定とロジックバグの切り分けが不能になる。X-Cache-Age 出力と structured log を必須化することで緩和。
- 手動無効化 Runbook の形骸化リスク (盲点 #2): 月 15-24 回の手動操作機会で人的ミスが発生しうる。GitHub Actions による自動無効化 workflow への移行を Phase 2 として計画 (要追記: 移行期限)。
- DRAFTS_KV 共用によるキャッシュ汚染リスク (盲点 #1): 既存 draft 管理スクリプトの一括 flush が
_cache:キーを巻き込む可能性。実装前に既存スクリプト全件をレビューし、KV list 操作にprefix='draft:'の明示フィルタを追加。専用 CACHE_KV namespace 化のコスト評価も実施 (要追記)。 - read-after-write 保証の根拠の精査不足 (盲点 #4): Cloudflare KV ドキュメントの正確な引用が未完了。実装フェーズで完了させ、保証されない場合は Runbook に 60s 待機を明記。
- 工数過小見積もりリスク (盲点 #10): thundering herd 対策・テレメトリ・自動無効化 CI・統合テストを含めた再見積もり 4-6h を起案者承認後に確定 (要追記)。
5.3 中立・トレードオフ (Neutral / Trade-offs)
- 多層防御前提の確証バイアス (盲点 #5): Gate 3・Gate 4 は Gate 2 の完全な代替ではなく補完。各 Gate の責任範囲を README に明記し、Gate 3・Gate 4 の CONFLICT/SUPERSEDE 検出テストケースを CI に追加。
- O(N) スケール問題 (盲点 #6): 単一キャッシュエントリ設計のため、1 件追加でも全体無効化。1 年後 100 件・2 年後 150 件のペイロード増加に備え、Review 条件として ADR 件数 150 件到達・ペイロード 500KB 超・p95 レイテンシ・KV 読み取り率・GitHub API 消費率を評価指標として設定 (要追記)。
- Thundering herd 問題 (盲点 #7): TTL 切れ・無効化直後の並列 cache miss で同時 GitHub API 呼び出しが発生しうる。singleflight パターンの実装可否と rate limit 残量の Telemetry 監視を実装フェーズで検討。
- rate limit 消費の定量根拠不足 (盲点 #8): 現状の GitHub API 消費量と rate limit への近接度データが未提示。実装前に過去 30 日間の X-RateLimit-Used ログまたは ADR-0077 Telemetry データで定量化する (要追記)。
- キャッシュデータ機密性 (盲点 #9): キャッシュ対象フィールドを
title・status・idに限定し、本文・コメント等の機密性の高い情報は除外。ADR-0037 アクセス制御ポリシーの_cache:prefix への適用を明示文書化。
撤退条件 (Rollback Plan)
| 判定指標 | 閾値 | 期限 | 対応 |
|---|---|---|---|
| キャッシュ起因の誤通過インシデント | 月 2 件以上 | Review After (2026-08-28) | キャッシュ無効化・コード revert・案 D 復帰 |
| KV 伝播遅延 | p95 > 300s が継続 | 1 ヶ月 | TTL を 300s に短縮または案 D 復帰 |
| ペイロードサイズ | > 500KB | Review After | 軽量スキーマ (title+status+id) に変更 |
| ADR 件数 | > 150 件 | Review After | 差分キャッシュ設計に再設計 |
| GitHub API rate limit 残量 | < 1000 req/h で頻発 | 1 ヶ月 | singleflight 実装・並列度抑制 |
撤退手順:
wrangler kv:key delete --binding=DRAFTS_KV "_cache:adr-summaries"でキャッシュ削除- consistency.ts のキャッシュ参照コードを feature flag で無効化 → revert PR
- ADR-0077 Telemetry で cache_hit 率 0% を確認
- 影響範囲: Gate 2 応答時間は元に戻るが、機能は完全復元
Confirmation (準拠確認 / Fitness Function)
| 要素 | 内容 |
|---|---|
| 検証手段 1 | scripts/adr-lint.mjs 拡張: consistency.ts が _cache: prefix 付きキーのみを操作し、draft: prefix を一括 flush していないことを静的解析で確認 |
| 検証手段 2 | 統合テスト (tests/gate2-cache.test.ts): (a) cache hit/miss 経路の正常動作、(b) DELETE 後の next fetch が GitHub API を呼ぶこと、(c) TTL 経過後の自動再取得 |
| 検証手段 3 | ADR-0077 Telemetry ダッシュボード: cache_hit_rate・cache_age_p95・github_api_subrequest_count・rate_limit_remaining を週次でレビュー |
| 検証手段 4 | Gate 3・Gate 4 の CONFLICT/SUPERSEDE 検出テストケース (CI 定期実行) により多層防御の実効性を継続確認 |
| 実行頻度 | 静的解析: 全 PR / 統合テスト: 全 PR + nightly / Telemetry レビュー: 週次 / 多層防御テスト: 日次 |
| 違反時の対応 | (a) 静的解析・統合テスト失敗 → PR ブロック / (b) cache_hit_rate < 50% が 1 週間継続 → TTL 見直し / (c) 多層防御テスト失敗 → Gate 2 キャッシュ無効化 + Incident チケット起票 / (d) Review After までに評価指標 (§5.3) のいずれか閾値超過 → 撤退条件発動 |
参照 (References)
- 関連 ADR: ADR-0019 (LangGraph 基盤, Confirms), ADR-0037 (KV draft staging, Confirms), ADR-0077 (Telemetry, Confirms)
- 関連 PR/Issue: - (要追記)
- 外部資料: Cloudflare Workers KV docs ("changes are usually visible globally within 60 seconds"), Suhr 1999 CBA criterion