ADR-0226 (outbox_dead_letter 表の schema と permanent event 物理 move 経路を確定 · 2026-07-08 受理) の Confirmation 4 KPI の観測結果を時系列で記録する。SQL 骨格は本ファイル各節 · SSoT は ADR-0226 §9 Confirmation。実 SQL の実行は Phase B (dead-letter-alerter 実装 + integration test 5-8 case · vlt session 49 Phase A shipping 後の別 PR) 完了後に開始する。

Week 0 (2026-07-09 · Phase A shipping · dead-letter-alerter 実装前 · 準備段階)

Phase A (schema.sql 追加 + vlt-schema-lint 4 rule 追加 + docs 3 種同期) の shipping 完了時点。dead-letter-alerter.ts 実装 (Phase B 予定) 未着手のため実測データなし。4 KPI の SQL 骨格 + SLO + 実施頻度 + 撤退条件連動を先出しで整理する。Phase B (dead-letter-alerter 実装 + integration test) merge 完了時点で本節を Week 1 として実測数値に置き換える。

KPI 1: outbox_dead_letter 表への物理 move 成功率 ≥ 99% (月次)

  • SLO: 成功 / (成功 + move_failed) ≥ 99%
  • 実施頻度: 月次 (BQ scheduled query · Cloud SQL export 経由で BigQuery mirror へ)
  • 撤退条件連動: <99% で dead-letter-alerter 実装の tx 境界 review + move_failed 経路の手動介入手順 (ADR-0221 §3.3 L101 pattern) · ADR-0226 §8 撤退条件 1 と連動

BigQuery SQL 骨格 (Cloud SQL export の日次 mirror テーブル前提):

WITH
  moved AS (
    SELECT COUNT(*) AS moved_count
    FROM `${project}.${dataset}.outbox_dead_letter`
    WHERE classified_at > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  ),
  failed AS (
    SELECT COUNT(*) AS failed_count
    FROM `${project}.${dataset}.pubsub_outbox`
    WHERE STARTS_WITH(CAST(published_at AS STRING), 'error:move_failed:')
      AND created_at > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  )
SELECT
  moved.moved_count,
  failed.failed_count,
  SAFE_DIVIDE(moved.moved_count, moved.moved_count + failed.failed_count) AS move_success_rate
FROM moved, failed;
-- 期待値: move_success_rate >= 0.99

KPI 2: alert 発火から代表取締役 drill-down までの中央値 ≤ 15 分 (月次)

  • SLO: 中央値 ≤ 15 分
  • 実施頻度: 月次
  • 撤退条件連動: >15 分で alert 内容の情報密度改善 (event 概要を alert body に埋込 · ADR-0221 §3.3 L94 payload マスキングとの両立)

BigQuery SQL 骨格 (Cloud Monitoring incident notification + docs.bizlp.dev retrieve_evidence log 突合):

WITH
  alerts AS (
    SELECT incident_id, alert_fire_time
    FROM `${project}.${dataset}.cloud_monitoring_incidents`
    WHERE policy_name = 'outbox-dead-letter-permanent-move'
      AND alert_fire_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  ),
  drill_downs AS (
    SELECT incident_id, MIN(access_time) AS first_drill_down
    FROM `${project}.${dataset}.docs_retrieve_evidence_access_log`
    WHERE resource_pattern LIKE 'outbox_dead_letter%'
    GROUP BY incident_id
  )
SELECT
  APPROX_QUANTILES(
    TIMESTAMP_DIFF(d.first_drill_down, a.alert_fire_time, MINUTE), 100
  )[OFFSET(50)] AS median_response_minutes
FROM alerts a
LEFT JOIN drill_downs d USING (incident_id);
-- 期待値: median_response_minutes <= 15

KPI 3: 追記専用性の DB REVOKE 検査 (週次)

  • SLO: 常時 0 件 (vlt_app に UPDATE / DELETE 権限が付与されていないこと)
  • 実施頻度: 週次 (vlt-schema-lint の schema-side rule missing-outbox-dead-letter-app-user-revoke が CI で発火 · runtime side は本 KPI で監視)
  • 撤退条件連動: >0 件で即座に REVOKE 再実行 + 追記経路の監査 (audit_log 側 SoT で GRANT 変更履歴を照合) · ADR-0226 §8 撤退条件 2 と連動 (role_table_grants 定期照合)

Cloud SQL (Postgres) 側 SQL 骨格 (Cloud SQL Studio または export 経由で BQ mirror):

SELECT COUNT(*) AS bad_grant_count
FROM information_schema.role_table_grants
WHERE table_name = 'outbox_dead_letter'
  AND grantee = 'vlt_app'
  AND privilege_type IN ('UPDATE', 'DELETE');
-- 期待値: 0

KPI 4: retention_expires_at 到来行の sweep 完遂率 (月次)

  • SLO: 常時 0 件 (Phase 0 は 7 年 retention なので 2033 以降まで自然到来なし · sweep 経路の smoke test は synthetic data で実施)
  • 実施頻度: 月次
  • 撤退条件連動: >0 件で Retention Manager sweep 経路の実装再検討 (P3-2 意思決定 = ADR-0225 flag flip と連動)

Cloud SQL SQL 骨格:

SELECT COUNT(*) AS expired_unswept_count
FROM outbox_dead_letter
WHERE retention_expires_at <= NOW();
-- 期待値: 0 (すべて sweep 済で物理削除)

変更履歴

  • 2026-07-09: 新設 (Phase A shipping · Week 0 preseed pattern に従い 4 KPI 骨格 + SLO + 実施頻度 + 撤退条件連動を先出し · dead-letter-alerter 実装 = Phase B PR で Week 1 実測に置換予定)