# INV-6: Rollback Playbook Register

**版本**：v1.0 初稿
**日期**：2026-05-03（台北）
**範圍**：AwoooP 全 8 Phase 的 rollback 場景
**用途**：Phase 4 起的 gate 驗收「rollback evidence ≥ 3 次」需要這份登記冊

---

## 說明

每個 rollback playbook 需要：
1. 觸發條件（什麼時候需要 rollback）
2. rollback 步驟（精確指令）
3. 驗證方式（rollback 是否成功）
4. 影響範圍（什麼會受影響）

---

## RBP-01: Phase 1 Schema Migration Rollback

**觸發**：Phase 1 migration up 後發現業務功能異常、CI 回歸測試失敗

**rollback 步驟**：
```bash
# 1. 確認當前 migration head
alembic current  # 或直接查 DB schema

# 2. 執行 down migration（每個 AwoooP migration 都有 down SQL）
# 手動執行 down migration SQL（deps/alembic down 或直接 psql）
psql $DATABASE_URL -f apps/api/migrations/awooop_phase1_down.sql

# 3. 驗證 AwoooP 表已移除
psql $DATABASE_URL -c "\dt awooop_*"  # 應該 0 結果

# 4. 確認 AWOOOI 原有功能正常
curl -f http://localhost:8000/v1/health
```

**影響**：AwoooP 控制面表全部刪除，AWOOOI 業務功能不受影響（P0：AWOOOI 0 行為改動）
**pre-condition**：AWOOOI 業務表無任何 AwoooP 外鍵依賴（Phase 1 設計邊界）

---

## RBP-02: Phase 2 Redis Key Rollback（三階段雙寫任一 Phase）

**觸發**：Redis 雙寫後發現舊服務讀取異常（Phase A 或 Phase B 期間）

**rollback 步驟**（Phase A 回滾）：
```bash
# 停止寫入新 key（code revert 或 feature flag off）
# 舊 key 本來就還在，直接恢復正常讀取
# 確認舊 key 仍有效（TTL 未過期）
redis-cli TTL "telegram_silence:{target}"  # 確認大於 0

# 清理已寫入的新 key（避免混淆）
redis-cli DEL "{project_id}:telegram:silence:{target}"
```

**rollback 步驟**（Phase B 回滾 → 回到 Phase A）：
```bash
# 將讀取邏輯改回「舊 key 為主」
# 保持雙寫（不移除新 key 寫入）
# 這是 Phase A 狀態，不需要清理資料
```

**影響**：Redis 讀取回到舊 key，功能降級但不中斷
**monitoring**：舊 key 命中率應在 24h 內回升到 100%

---

## RBP-03: Strangler Fig Phase Rollback（shadow/canary/read_only 回退）

**觸發**：量化 gate 失敗（error rate > threshold、p95 退化 > 10%、出現 P0/P1 incident）

**rollback 步驟**：
```sql
-- 回退 project_migration_state
UPDATE awooop_project_migration_state
SET current_mode = 'shadow',  -- 回到上一個 mode
    rolled_back_at = NOW(),
    rollback_reason = '量化 gate 失敗：error_rate > 0.5%'
WHERE project_id = 'awoooi'
  AND capability = 'sre_flows';

-- 讓 worker 重新讀 migration_state（invalidate cache）
-- Redis: DEL platform:awooop:migration_state:awoooi
```

```bash
# feature flag 切回
# AWOOOP_CANARY_MODE=false（K8s ConfigMap 或 env）
kubectl patch configmap awoooi-config -n awoooi-prod \
    --type=merge -p '{"data":{"AWOOOP_CANARY_MODE":"false"}}'
kubectl rollout restart deployment/awoooi-api -n awoooi-prod
```

**影響**：AwoooP 回到上一個 mode，legacy AWOOOI handler 重新接管
**monitoring**：Strangler Fig dashboard 顯示回退記錄（ADR-UI-03）

---

## RBP-04: Phase 5 MCP Gateway Rollback

**觸發**：MCP Gateway 導致工具呼叫失敗率 > 5%

**rollback 步驟**：
```bash
# 1. 關閉 MCP Gateway 攔截（feature flag）
kubectl patch configmap awoooi-config -n awoooi-prod \
    --type=merge -p '{"data":{"AWOOOP_MCP_GATEWAY_ENABLED":"false"}}'

# 2. 重啟 pod 使設定生效
kubectl rollout restart deployment/awoooi-api -n awoooi-prod

# 3. 確認工具呼叫直接通過（繞過 Gateway）
# 監控：mcp_tool_call_success_rate 應在 5min 內回升
```

**影響**：audit 仍記錄，但 Five-gate 不攔截；credential isolation 暫時失效
**post-rollback action**：找 MCP Gateway 失敗原因後再重新啟用

---

## RBP-05: Phase 6 EwoooC Tenant Rollback

**觸發**：EwoooC shadow 期間發現跨 tenant 資料洩漏（E-TENANT-001 告警）

**rollback 步驟**：
```sql
-- 1. 立即停止 EwoooC 所有 run
UPDATE awooop_run_state
SET status = 'CANCELLED',
    failure_reason = 'Emergency rollback: cross-tenant leak detected'
WHERE project_id = 'ewoooc'
  AND status NOT IN ('COMPLETED', 'FAILED', 'CANCELLED');

-- 2. 停用 EwoooC project
UPDATE awooop_projects
SET is_active = FALSE,
    suspension_reason = 'Emergency rollback 2026-05-xx'
WHERE project_id = 'ewoooc';
```

```bash
# 3. feature flag 關閉
kubectl patch configmap awoooi-config -n awoooi-prod \
    --type=merge -p '{"data":{"AWOOOP_EWOOOC_LIVE":"false"}}'

# 4. 通知 EwoooC 團隊
```

**影響**：EwoooC 服務中斷；AWOOOI 不受影響
**RCA 必要**：觸發 Runbook RB-06（cross-tenant leak）；需確認 RLS 是否失效

---

## RBP-06: Phase 8 Approval Flow Rollback

**觸發**：approval_token 簽章機制導致正常 approval 無法完成

**rollback 步驟**：
```bash
# 1. 臨時切回舊 approval 路徑（feature flag）
kubectl patch configmap awoooi-config -n awoooi-prod \
    --type=merge -p '{"data":{"AWOOOP_APPROVAL_TOKEN_REQUIRED":"false"}}'

# 2. 重啟
kubectl rollout restart deployment/awoooi-api -n awoooi-prod

# 3. 手動處理 stuck WAITING_APPROVAL run（Runbook RB-02）
```

**影響**：approval token 安全性降級，回到舊 approval 驗證邏輯
**post-rollback action**：診斷 token 簽章失敗原因（clock skew？Secret rotation？）

---

## RBP-07: GCP Ollama Primary 失聯緊急 Rollback

**觸發**：GCP-A 和 GCP-B 同時不可達，Local 111 也異常（見 Runbook RB-07）

**rollback 步驟**：
```bash
# 1. 強制 Redis 設定 fallback
redis-cli SET "platform:ollama:topology" \
    '{"primary":"http://192.168.0.111:11434","secondary":null,"fallback":"gemini"}'

# 2. 確認 paid provider 路由已啟用（config.py GEMINI_API_KEY 有效）
# 3. 監控：LLM call 應切換到 Gemini
```

**影響**：推理效能降低（Local HDD）或費用增加（Gemini）
**post-rollback action**：確認 GCP-A/B 健康狀態後，Redis 恢復三層拓撲

---

## 登記表

| Rollback ID | Phase | 已驗證次數 | 最後驗證日期 | 備註 |
|------------|-------|-----------|------------|------|
| RBP-01 | Phase 1 | 0 | — | 待 Phase 1 完成後驗證 |
| RBP-02 | Phase 2 | 0 | — | 待 Redis 遷移開始後驗證 |
| RBP-03 | Phase 4+ | 0 | — | Strangler Fig gate |
| RBP-04 | Phase 5 | 0 | — | MCP Gateway |
| RBP-05 | Phase 6 | 0 | — | EwoooC |
| RBP-06 | Phase 8 | 0 | — | Approval token |
| RBP-07 | 任何時間 | 0 | — | GCP Ollama 緊急 |

**Phase 8 gate 要求**：進入 `suggest → auto_remediate` 前，上表「已驗證次數」必須 ≥ 3 次（每個 RBP）。
由 critic + db-expert + vuln-verifier 三方在 LOGBOOK 簽核。

*最後更新：2026-05-03（台北）*
