型付き辺: 出 11 / 入 0
ADR-0230: GCS delete を COMMIT 後の補償ワーカーへ移送
1. Executive Summary
- 文脈: 帳票 SaaS の Retention Manager (= vlt の保存期限が経過した受領書を廃棄するモジュール · ADR-0223) は receipt 論理削除と GCS オブジェクト削除を単一トランザクション内で並置し、複数のモジュールを統合したパイプラインでアトミシティを維持している。
- 課題: GCS deleteObject は Postgres COMMIT に参加しない外部 I/O のため GCS 削除成功 → Postgres COMMIT 失敗時に「GCS オブジェクト消失 · receipt 行残存」の逆向き孤立が発生しうる (ADR-0225 の潜在リスク信頼性で指摘された課題を、エンドツーエンド検出で一時的に担保し、恒久解決は本 ADR で扱う)。
- 対策: Phase 1 event-emitter 有効化 (ADR-0222 §3.3 仕様 + ADR-0223 §3.3 仕様 連動) と同時に GCS delete を Postgres COMMIT 後の at-least-once 補償ワーカーへ移送し、Postgres tx の atomicity を完全に切り離す。
- 効果: 「GCS 削除成功 → Postgres COMMIT 失敗」経路の逆向き孤立 (現状 e2e 検出のみ · 手動介入 runbook 対応) を根本解消し、tx 境界を Postgres 内に閉じて sweep atomicity の設計負荷 (5 module 統合 pipeline の 4 case + 手動 runbook) を軽減する。
- 代償: 補償ワーカー (= 新規モジュール) の新設に 5 人日 (ADR-0225 §5.4 記載) + at-least-once セマンティクス (= 少なくとも 1 回実行) 受容 (GCS delete 重複実行の冪等性を GCS 側で担保) + Phase 1 移送タイミングの 1 PR 追加。
2. 何を解決するか
2.1 直面していること
適合性:
- ADR-0225 §2.3 潜在リスク信頼性で「GCS 削除成功 → Postgres COMMIT 失敗」経路の逆向き孤立が発生しうる旨を明記済み · §Confirmation KPI 3 で e2e 検出 case を新規追加した (発生確率不明 · 実害未発生)。
- ADR-0175 (3 号真実性ルート 4 要素) §Confirmation では audit_log 完全性 100% を要求するが、逆向き孤立発生時は receipt 行残存 + GCS 消失で削除経路の audit 記録と物理状態が乖離するリスクが残る。
信頼性:
- ADR-0225 §11 実装配線で GCS 削除失敗方向の手動介入 runbook を明記予定 · Phase 0 期間中は手動対応で足りるが Phase 1 商用化後は運用工数のスケーラビリティが問題となる。
2.2 放置すると起こること
適合性:
- Phase 1 商用化 (= 2027 一般提供目標 · ADR-0206 (JIIMA の 2 つのスキームに並行して申請する)) 後にテナント数増加で GCS 削除 tx の実行回数が線形増加し、逆向き孤立の発生件数を実測した値が観測可能な水準 (月 1 件以上) に到達すると JIIMA 認証審査 (ADR-0206) の「削除経路の完全性」設問で説明不能となる。
- 逆向き孤立の手動介入 runbook が Phase 1 で必要頻度が上昇し (Phase 0 = ゼロ想定 · Phase 1 = 月 1-3 件想定 · 実測値は本 ADR §Confirmation で追跡)、代表取締役 1 人法人体制での対応工数を圧迫する。
信頼性:
- Phase 1 event-emitter 有効化 (
VLT_AUDIT_LOG_ENABLED=true) 後に sweep atomicity 設計を継続すると、audit_log INSERT 経路が sweep 内から event-emitter 外部に移送されたにもかかわらず GCS delete のみ sweep 内に残存し、tx 境界の一貫性 (audit と GCS が同 tx 内) が崩れる。
2.3 潜在リスク (実害未発生 · 発生確率不明)
信頼性:
- 補償ワーカー (= 新規モジュール) が Postgres COMMIT 後に GCS delete を実行するため、補償ワーカーが GCS delete 前に crash した場合、Cloud Scheduler retry で再開されるまでの遅延 (= 最大 15 分 · Cloud Scheduler default 間隔) の間 GCS オブジェクト残存となる · at-least-once セマンティクス下で GCS delete 実行数 > receipt 論理削除数 の乖離が短期発生する可能性。
- Phase 1 移送タイミング (
VLT_AUDIT_LOG_ENABLED=true切替) と本 ADR 実装 PR の順序が逆転すると、event-emitter 有効化と GCS delete 移送が別 PR に分離される期間 (デプロイ間 buffer) に tx 境界の一貫性が崩れる · 順序制約は本 ADR §11 実装配線で明記する必要がある。 - sweep tx が INSERT 後・COMMIT 前にプロセス crash / タイムアウトで ROLLBACK した場合、
vlt_pending_gcs_delete表への INSERT も同時に ROLLBACK され pending 行が残らず GCS delete が永遠に実行されない (=「静かな失敗」経路 · GCS オブジェクト残存 · receipt 行残存) · pending 行が存在しないため §9 KPI 1 の SELECT では検知不能 · §9 KPI 5 (孤立 receipt_id 監視) で別経路検知する。 - GCS Object Retention Lock (= 削除保護) と
receipts.retention_expires_atの時刻比較で許容誤差・タイムゾーン誤りが発生した場合、Retention Lock 有効期間中の削除リクエストが 403 で返り補償ワーカーが retry 対象外行を蓄積し続ける · 手動介入 SLA が未定義だと dead letter 化が常態化する。 vlt_pending_gcs_delete表への INSERT を sweep tx 内に追加したため、テナント数増加で並列 sweep 実行時に同一テーブル集中 INSERT による HOT 更新阻害 · page bloat · 行ロック競合が発生し、sweep 全体の tx commit latency が上昇して receipt 論理削除そのものがタイムアウトする経路が生じうる。- GCS 側の恒常的障害 (IAM ポリシーの変更、バケットの削除、課金停止といった障害) で全件 retry 失敗が継続した場合、retry_count 上限到達行の dead letter 隔離フローがないと
vlt_pending_gcs_delete表が無制限膨張し Postgres ストレージ · sequential scan コストを圧迫する。
3. 採用したい方針
3.1 対策方針
Phase 1 event-emitter 有効化 (ADR-0222 · ADR-0223 §3.3 仕様 連動) と同時に、GCS deleteObject を Postgres COMMIT 後の at-least-once 補償ワーカー vlt/src/retention-manager/gcs-delete-compensation.ts (= 新規モジュール · Postgres COMMIT 後の非同期 GCS delete 実行本体) へ移送する。sweep atomicity は Postgres tx 内 (receipt の論理削除、監査ログの挿入経路、イベントエミッター) に閉じ、GCS delete は独立 Cloud Run Job で Cloud Scheduler 起動 (毎 15 分) する事後補償経路とする。GCS delete 重複実行の冪等性は GCS 側 (削除済みオブジェクトへの DELETE = 404 no-op 扱い) で担保する。
- 適合性: ADR-0175 4 要素 #3 append-only の完全性は event-emitter 経路 (audit_log INSERT) で担保 · GCS delete 失敗時も receipt 行の論理削除フラグと audit_log INSERT は既に確定済みで、削除経路の audit 記録は物理状態に先行して確定する。
- 信頼性: Postgres tx atomicity は Postgres 内に閉じ、GCS delete は補償ワーカーの at-least-once retry で eventual に一致する · 補償ワーカーが失敗を継続 (24 時間) すると Cloud Monitoring alert で代表取締役に通知。
- 効率性: sweep atomicity 5 module 統合 pipeline の 4 case 中 2 case (GCS 削除の失敗、GCS 削除の成功後の Postgres コミット失敗) が sweep 側検証範囲から除外され、補償ワーカー側 unit test に移送されるため統合 pipeline test の複雑性が軽減される。
3.2 守るべき設計制約
- 適合性: 本 ADR 実装 PR は
VLT_AUDIT_LOG_ENABLED=true切替 (ADR-0223 §3.3 · event-emitter 有効化) と同一 PR で必ず同梱する (別 PR 分離時は audit_log 経路と GCS delete 経路の tx 境界が不整合になる期間が生じるため · ADR-0225 §8 撤退条件 (1) 準拠)。 - 信頼性: 補償ワーカーの retry 上限 (= 試行 96 回 = 24 時間) と Cloud Monitoring のアラートが発火する閾値を Terraform で管理し、手動介入不要の完全自動化を維持する。
- 信頼性: GCS delete の冪等性は GCS 側の 404 no-op 挙動に依存 · Object Retention Lock (= 削除保護) 有効期間中の削除リクエストは補償ワーカー側で
retention_expires_at未到達エラーとして分離し、retry 対象外 (= 手動介入対象) とする · 手動介入 SLA は §3.3 仕様と ops runbook (docs/_internal/06_ops/gcs-delete-compensation-runbook.md新設予定) で明記する。 - 信頼性: 補償ワーカーのランタイムは Cloud Run Job のみとし、GAS (= Google Apps Script · 最大実行 6 分 · 同時 30 · Properties Store 500KB 制限) 実行環境との混在を禁止する · ADR-0221 outbox-relay の Cloud Run Job 稼働実績 (
vlt/terraform/modules/vlt-cloud-run-jobstate) を PR link で明示引用し、補償ワーカーが同 pattern を再利用することを実装 PR で証跡化する。 - 効率性: 補償ワーカーは既存 outbox-relay (ADR-0221 · Cloud Run Job + Cloud Scheduler pattern) と同じインフラ pattern を再利用し、Terraform module を共通化する · インフラ設計工数を抑制する。
3.3 仕様
- 信頼性:
vlt/src/retention-manager/gcs-delete-compensation.ts(= 新規モジュール) を実装 · retention_manager から発行されたイベント (vlt_pending_gcs_delete表 · 新規テーブル · 3 列 =receipt_id·gcs_object_path·created_at) を polling し GCS deleteObject を実行する · Postgres COMMIT 後の同 tx でvlt_pending_gcs_delete表への INSERT が完了しているため、event-emitter 経路と同じ tx 内に GCS delete pending 状態が確定する。 - 信頼性:
vlt_pending_gcs_delete表は追記専用ではなく DELETE 可能 (= 補償ワーカーが GCS delete 成功後に該当行を DELETE) · UPDATE は禁止 (retry 回数のみ別列で追記) · この表は audit_log ではなく作業キューであり、ADR-0175 4 要素 #3 append-only 要件の対象外。 - 信頼性: retry_count が上限 96 に到達した行は自動的に
vlt_pending_gcs_delete_dead_letter表 (= 新規テーブル · 隔離キュー) へ移送し、vlt_pending_gcs_deleteの膨張を防ぐ · dead_letter 行数が閾値 (= 累積 100 件 or 24 時間で新規 10 件) を超えた時点で Cloud Monitoring alert を発火し、ops runbook (docs/_internal/06_ops/gcs-delete-compensation-runbook.md) に対応 SLA (= 発火から 2 営業日以内) · 担当者 (= 代表取締役) · エスカレーション先 (= GCS API サポート) を明記する。 - 信頼性: Object Retention Lock と
retention_expires_atの時刻比較は UTC 統一 · 許容誤差は Retention Lock 解除後 60 秒以上経過してから補償ワーカーが削除リクエストを発行する · タイムゾーン誤り検知のため実装 PR に UTC 明示 assertion を追加する。 - 効率性: Cloud Run Job は既存 outbox-relay と同じ Terraform module (
terraform/modules/vlt-cloud-run-job) を再利用 · Cloud Scheduler の起動間隔は 15 分 (= outbox-relay と同 default) で開始し、Phase 1 中に実測 latency を観測して調整する。 - 柔軟性: Phase 2 (= 商用化後 6 ヶ月) で外部 message broker (Pub/Sub · Cloud Tasks) への移送を再評価する余地を残す · 移送時は
vlt_pending_gcs_delete表 polling を廃止し subscriber へ書き換える · 移行期間中は dual-write (= 表 INSERT + broker publish 併存) 方式で互換性を維持し、subscriber 稼働確認後に表 INSERT を段階廃止する。
4. 判断基準
4.1 評価軸 (4 個選定)
| # | 軸 (Q42) | 日本語軸名 | 重要度 (係数) | 案件特有の解釈 |
|---|---|---|---|---|
| 1 | #reliable | 信頼性 | Must (×2.0) | Postgres tx atomicity 内に閉じ · 逆向き孤立を根本解消 · at-least-once セマンティクスで eventual consistency 担保 · K.O.: 補償ワーカー retry で eventual に一致できない案は不採用 |
| 2 | #suitable | 適合性 | Must (×2.0) | ADR-0175 4 要素 #3 append-only 完全性 (= audit_log 経路) を維持しつつ GCS 側の物理状態と分離 · K.O.: audit 経路と GCS 経路の tx 境界不整合を生む案は不採用 |
| 3 | #efficient | 効率性 | High (×1.0) | 補償ワーカー新設 5 人日 vs sweep atomicity 5 module pipeline の複雑性軽減効果 · Cloud Run Job インフラ再利用 · sweep test case 削減 |
| 4 | #flexible | 柔軟性 | Medium (×0.5) | Phase 2 (= 商用化後 6 ヶ月) で外部 message broker への移送余地 · Cloud Scheduler polling は initial 実装 |
K.O. criterion: Must 軸 score < 3 は不採用。
4.2 評価軸 × 案スコア表
| 軸 | 係数 | 案 1: 補償ワーカー移送 | 案 2: sweep tx 内継続 | 案 3: 分散 tx (2PC) |
|---|---|---|---|---|
| 信頼性 | ×2.0 | 5 | 3 | 4 |
| 適合性 | ×2.0 | 5 | 3 | 4 |
| 効率性 | ×1.0 | 4 | 3 | 2 |
| 柔軟性 | ×0.5 | 4 | 3 | 2 |
| 加重和 (正規化) | 0.909 | 0.591 | 0.591 | |
| K.O. 通過 (Must ≥3) | ✓ | ✓ | ✓ |
5. 検討した代替案
5.1 案 1 (採用): 補償ワーカー移送 (at-least-once)
採用案。詳細は §3.1 対策方針 参照。
- 信頼性: Postgres COMMIT 後の補償ワーカー retry で GCS delete を eventual に一致 (score 5)。
- 適合性: audit_log 完全性 (event-emitter 経路) を維持しつつ GCS 物理状態と分離 (score 5)。
- 効率性: sweep test case 削減 + Cloud Run Job インフラ再利用 · 補償ワーカー新設 5 人日で恒久解決 (score 4)。
- 柔軟性: Phase 2 で外部 message broker 移送の余地 (score 4)。
5.2 案 2 (不採用): sweep tx 内継続 (現状継承)
- 信頼性: GCS 削除成功 → Postgres COMMIT 失敗の逆向き孤立が発生確率不明のまま Phase 1 商用化後に線形増加する · 手動介入 runbook 対応で運用工数を圧迫 (score 3)。
- 適合性: audit_log 完全性は event-emitter 経路で担保できるが GCS 側の物理状態と audit の一貫性が保てない (score 3)。
- 効率性: sweep 5 module 統合 pipeline の 4 case を継続維持 · 補償ワーカー新設工数 0 (score 3)。
- 柔軟性: Phase 2 の外部 broker 移送を再評価する際に sweep tx 内 GCS delete を先に外す作業が必要 · 移送コスト増 (score 3)。
5.3 案 3 (不採用): 分散トランザクション (2PC) 導入
- 信頼性: XA プロトコル or Saga pattern で GCS delete と Postgres COMMIT を 2 phase commit する · GCS API が XA 未対応のため Saga pattern (= 補償トランザクション) 経由となり案 1 と同等の compensation 経路が必要 (score 4)。
- 適合性: 2PC coordinator が failure すると partial commit 状態から手動復旧が必要 · audit 経路と GCS 経路の tx 境界不整合を完全解消できない (score 4)。
- 効率性: Saga pattern の compensation ロジック実装工数 (= 推定 8 人日) が案 1 (5 人日) より大きい · インフラ再利用不可 (score 2)。
- 柔軟性: Saga pattern を捨てる場合は case-by-case の compensation を書き直す必要 · 移送コスト増 (score 2)。
6. 影響
6.1 正の影響
- 信頼性: 「GCS 削除成功 → Postgres COMMIT 失敗」経路の逆向き孤立発生を Phase 1 商用化後に月 0 件 (= 補償ワーカー retry で eventual に一致) を目標値とする · ADR-0225 §Confirmation KPI 3 の e2e 検出 case は継続維持しつつ、手動介入 runbook 発火頻度を月 0 件へ削減。
- 適合性: audit_log 完全性 (= event-emitter 経路の 100% INSERT 成功) は Phase 0 期間中の実測値を継承 · GCS 側の物理状態と audit_log の一貫性が eventual consistency 内で担保される。
- 効率性: sweep のアトミシティを保証する 5 つのモジュールを統合したパイプラインのテストの 4 case 中 2 case (GCS 削除失敗 · GCS 削除成功 → Postgres COMMIT 失敗) を補償ワーカー側 unit test へ移送 · 統合 pipeline 複雑性 50% 軽減目標。
6.2 負の影響 / リスク
- 信頼性: GCS オブジェクト残存期間 (= receipt 論理削除完了時から補償ワーカー retry まで) が最大 15 分間存在 · 電帳法上「削除実行」は Postgres 論理削除 (=
receipts.deleted_at設定) で成立するため法的リスクはない前提だが、JIIMA 認証審査 (ADR-0206) の運用指針 (2024 年改訂版) では審査員解釈にばらつきがあるため、論理削除時点を削除実行とみなす解釈の文書確認を JIIMA 事務局から取得し §10.3 に添付する。 - 信頼性: sweep tx 内に
vlt_pending_gcs_deleteINSERT を追加したため、並列 sweep 実行時の行ロック競合 · HOT 更新阻害 · page bloat による commit latency 上昇リスクが残る · 実装 PR 前にテナント 100 件規模の同時 sweep 負荷試験を実施し INSERT latency P99 を計測する (§9 KPI 6)。 - 効率性: 補償ワーカー Cloud Run Job の毎 15 分起動でランタイム月 ~[MASKED:AMOUNT] (= Cloud Run Job Free tier 超過分推定) が発生 · outbox-relay と同 pattern のため既存予算枠内で吸収可能。
7. コスト試算
7.1 前提条件
| 項目 | 値 | 根拠 |
|---|---|---|
| 補償ワーカー実装工数 | 5 人日 | ADR-0225 §5.4 記載値を継承 (module 新設 + Terraform + 3 test suite) |
| Cloud Run Job ランタイム | 月 ~[MASKED:AMOUNT] | outbox-relay 実績 (毎 15 分起動 · 60 秒/回) と同 pattern |
| GCS deleteObject 冪等性 | 404 no-op | GCS API 仕様 (削除済みオブジェクトへの DELETE は 404 · not error) |
| 補償ワーカー retry 上限 | 96 回 = 24 時間 | 15 分間隔 × 96 = 24 時間 (= 手動介入判断猶予) |
7.2 月コスト試算
- 実装工数 (一括): 5 人日 (= [MASKED:AMOUNT] 相当 · 1 人日 [MASKED:AMOUNT] 換算)。
- 月ランタイム: ~[MASKED:AMOUNT] (= Cloud Run Job 起動 + GCS API call 課金) · Phase 1 商用化後のテナント数増加に応じて線形増加想定 (= 1 テナント +[MASKED:AMOUNT] / 月)。
- 年次サブスクリプション: なし (= 既存インフラ再利用)。
- 代替案 2 (sweep tx 内継続) 比較: 実装工数 0 だが手動介入 runbook 対応が月 1-3 件想定で年 ~[MASKED:AMOUNT] (= 1 件 [MASKED:AMOUNT] × 3 件 × 12 ヶ月) の運用工数コスト · 本案 1 の実装工数 (= [MASKED:AMOUNT]) は 1.4 年で回収。
8. 撤退条件
- 補償ワーカー retry 失敗率 > 5% (= 1 週間平均) 継続 4 週間: at-least-once セマンティクス破綻の兆候 · 案 2 (sweep tx 内継続) への切戻しを再評価する · Terraform で
vars.enable_gcs_delete_compensation = falseflag で切戻し可能状態を維持 · 切戻し時はVLT_AUDIT_LOG_ENABLED=trueを維持したまま sweep tx 内 GCS delete へ戻すことは §3.2 tx 境界一貫性制約に反するため、event-emitter を同時にfalseへ戻す (= ADR-0225 §8 撤退条件 (1) と連動整合) · この順序制約を切戻し runbook で明記する。 - GCS オブジェクト残存期間 > 24 時間 の事案が月 3 件超え: 補償ワーカーの retry 上限を延長 or Cloud Scheduler 起動間隔を短縮 (= 15 分 → 5 分) する判断 · 追加 ADR で条件明記。
- 月コスト超過 [MASKED:AMOUNT]/月: テナント数増加に対する Cloud Run Job ランタイム線形増加が予算枠を超過 · 外部 message broker (Cloud Tasks) への移送を Phase 2 で前倒し評価する。
- 法令改定で GCS 物理削除の即時性要求が発生: 電帳法・個人情報保護法の改定で「論理削除と物理削除の間隔 ≤ N 分」要件が新設された場合、補償ワーカー retry 間隔を要件に合わせて短縮 · 補償ワーカー廃止を含む再設計判断。
- GCS オブジェクト残存期間 P99 > 60 分 (遅延 SLA · 月次観測): Cloud Scheduler 15 分 polling では追随できないテナント負荷に到達したと判断し、Phase 2 前倒しで Pub/Sub 移送を評価する · dual-write 移行期間を含む再設計。
9. Confirmation
- 補償ワーカー成功率 KPI:
SELECT COUNT(*) FROM vlt_pending_gcs_delete WHERE created_at < NOW() - INTERVAL '1 hour' AND retry_count < 96= 月次で 5% 未満 · 週次で BigQuery observation dashboard に集計 · 違反時は補償ワーカー log を drill-down し原因分析 (= GCS API 429 rate limit · IAM policy 変更 · GCS bucket 権限変更 の 3 分類)。 - GCS オブジェクト残存期間 KPI:
SELECT PERCENTILE_CONT(NOW() - created_at, 0.99) FROM vlt_pending_gcs_delete_history= P99 で 24 時間未満 · 月次観測 · 違反時は §8 撤退条件 (2) 発火 · P99 60 分超過で §8 撤退条件 (5) 発火。 - audit_log 完全性 (event-emitter 経路 100%): ADR-0223 §Confirmation KPI 継承 · 本 ADR で追加検証 case なし · 但し補償ワーカー実装 PR 後の初回 Phase 1 dogfood で audit_log INSERT 数 =
receipts.deleted_at設定数 の一致確認を e2e test で追加。 - 月コスト観測: Cloud Run Job ランタイム + GCS API call 課金の月次実測値 · [MASKED:AMOUNT]/月 超過を §8 撤退条件 (3) 発火閾値とする · 実測観測は billing export table から抽出。
- 孤立 receipt_id 監視 (静かな失敗検知):
SELECT receipt_id FROM receipts WHERE deleted_at IS NOT NULL AND NOT EXISTS (SELECT 1 FROM vlt_pending_gcs_delete WHERE receipt_id = receipts.id) AND NOT EXISTS (SELECT 1 FROM vlt_pending_gcs_delete_history WHERE receipt_id = receipts.id)= 日次で 0 件 · 1 件でも検出したら sweep tx ROLLBACK 経路の「静かな失敗」の兆候として調査 · Cloud Monitoring alert 即時発火。 - sweep tx commit latency KPI (負荷試験): 実装 PR 前にテナント 100 件規模の同時 sweep 負荷試験を実施し、
vlt_pending_gcs_deleteINSERT 追加後の sweep tx commit latency P99 を計測する · P99 < 3 秒 (= sweep tx タイムアウト閾値の 30%) を通過条件とし、超過時は FILLFACTOR 調整 · autovacuum 設定変更 · 表分割を検討する。 - dead_letter 隔離キュー観測:
SELECT COUNT(*) FROM vlt_pending_gcs_delete_dead_letter= 累積 100 件 or 24 時間で新規 10 件を Cloud Monitoring alert 発火閾値とする · ops runbook (docs/_internal/06_ops/gcs-delete-compensation-runbook.md) 記載の対応 SLA 2 営業日以内で 100% 対応。
10. 参照
10.1 関連 ADR
- Refines: ADR-0225 (sweep boundary に audit_log を同梱 · Standard) — 本 ADR は §5.4 案 4 (不採用) の恒久解決を扱う · §2.3 潜在リスク信頼性の GCS 削除失敗方向の逆向き孤立を根本解消。
- ADR-0175 (真実性確保ルート確定 · Critical) — 4 要素 #3 append-only 完全性を event-emitter 経路で担保する前提の継承 · 併立。
- ADR-0221 (outbox-relay 実装 · Standard) — Cloud Run Job + Cloud Scheduler pattern を本 ADR 補償ワーカーが再利用 · インフラ pattern 継承。
- ADR-0222 (append-only 監査ログ物理担保 module 単位確定 · Standard) — event-emitter 有効化 (=
VLT_AUDIT_LOG_ENABLED=true) の実装 SSoT · 本 ADR は同 flag 切替と同一 PR 同梱制約を継承。 - ADR-0223 (Retention Manager 運用実装 · Standard) — sweep atomicity 5 module pipeline の実装 SSoT · 本 ADR で 2 case を補償ワーカー側 unit test へ移送。
- ADR-0203 (schema 基礎 · retention 4 列 pattern) —
vlt_pending_gcs_delete表の 3 列設計 pattern を継承 · KPI-4 (Phase 0 中 schema 変更 ≤ 1 回) は Phase 1 移送タイミングのため対象外。 - ADR-0206 (JIIMA 2 スキーム並行申請 · Critical) — 削除経路完全性設問の解釈確認先 · §6.2 で JIIMA 事務局からの文書確認取得を §10.3 に添付する制約。
10.2 関連 PR/Issue
- PR #5475 (ADR-0225 受理 PR · shipping 段階) — 本 ADR §11 起案フロー配線で明示計上済。
- PR #5480 (ADR-0226 outbox_dead_letter 表 · MERGED) — 同 Cloud Run Job pattern の直近実例 · インフラ再利用の参考。
10.3 外部資料
- Google Cloud Storage API Reference (deleteObject 404 no-op 挙動): https://cloud.google.com/storage/docs/json_api/v1/objects/delete
- Cloud Scheduler pricing: https://cloud.google.com/scheduler/pricing
- PostgreSQL 公式 VACUUM ドキュメント §HOT (
vlt_pending_gcs_delete表の HOT 更新 · page bloat 検討根拠): https://www.postgresql.org/docs/current/routine-vacuuming.html - JIIMA 認証審査 運用指針 2024 年改訂版 (削除実行の解釈文書確認取得先 · §6.2 添付予定): https://www.jiima.or.jp/
11. 実装配線
- lint 配線:
scripts/vlt-schema-lint.mjsに新規 rule 追加 (vlt_pending_gcs_delete表の 3 列存在検証 +retry_count列 UPDATE 権限 REVOKE 検証 +vlt_pending_gcs_delete_dead_letter表存在検証 + audit_log 経路の event-emitter 側 INSERT 数 =receipts.deleted_at設定数 の e2e assertion + Object Retention Lock 有効期間中の 403 を retry 対象外として正しく分離する assertion + 補償ワーカー test suite が outbox-relay test suite からのコピー流用でないこと (= GCS 固有 case 5 種の独立記述) を検証する rule) ·.github/workflows/vlt-schema-lint.ymlで run · PR 実装時に adr-lint doc consistency check で本 ADR の implementation_status flip を検証。 - 起案フロー配線: 本 ADR 受理 PR merge 後、下記を同一 PR で同梱 —
vlt/src/db/schema.sqlにvlt_pending_gcs_delete表 +vlt_pending_gcs_delete_history表 (= 補償ワーカー成功後の archive · KPI 2 観測用) +vlt_pending_gcs_delete_dead_letter表 (= retry 上限到達行の隔離キュー) 追加 ·vlt/src/retention-manager/gcs-delete-compensation.ts(= 補償ワーカー本体 module) 新設 ·vlt/src/retention-manager/lock-transaction-boundary.tsから GCS deleteObject 呼び出しを削除しvlt_pending_gcs_delete表への INSERT に置換 ·vlt/terraform/modules/vlt-cloud-run-jobを再利用して補償ワーカー Cloud Run Job + Cloud Scheduler 定義追加 (Terraform state で outbox-relay の Cloud Run Job 稼働実績を PR link で明示引用) ·vlt/tests/e2e/gcs-delete-compensation.test.ts新設 (5 case = 補償ワーカー成功 / retry 上限到達 → dead_letter 移送 / 429 rate limit / IAM policy 変更 / bucket 権限変更 · 加えて Object Retention Lock 有効期間中の 403 分離 assertion) · ADR-0223 §11 実装配線からsweep-audit-atomicity.test.tsの 2 case を補償ワーカー側 unit test へ移送 · 実装 PR 前にテナント 100 件規模同時 sweep 負荷試験を実施し §9 KPI 6 の P99 計測結果を PR description に添付。 - docs SSoT 同期:
docs/architecture/arch_jtbd012_voucher_saas_draft.mdの Retention Manager 節に補償ワーカー経路追記 ·docs/_internal/06_ops/adr-0225-observation-log.md(= 別途新設予定) に KPI 1-7 月次観測ログを追加 ·docs/_internal/06_ops/gcs-delete-compensation-runbook.md(= 新設) に dead_letter 対応 SLA 2 営業日 · 担当者 · エスカレーション先 (GCS API サポート) を明記 ·.claude/rules/vlt.md(= vlt clone のドメイン規約 · 該当あればの前提) に補償ワーカー Terraform module 再利用 pattern + GAS 実行環境混在禁止を追記 · ADR-0225 §5.4 の refined_by list に本 ADR を追記 · ADR-0206 JIIMA 事務局への削除実行解釈文書確認依頼を issue tracker に起票し取得後 §10.3 に添付。