# ADR-062 — 資料安全護欄 (Data Safety Guardrails) > **狀態**: 已批准 (首席架構師裁示 2026-04-08) > **撰寫**: Claude Sonnet 4.6 / 2026-04-08 Asia/Taipei > **相關**: ADR-061 (Alert Operation Log), ADR-058 (SSH Host Repair), ADR-039 (CI/CD) --- ## 背景 Sprint 5.1 啟動前,AWOOOI 的自動修復機制已「移除所有 gate」(2026-04-08 統帥指令),所有 APPROVED Playbook 均可直接執行。此設計在無狀態服務上運作良好,但對**有狀態服務(Stateful Services)**存在資料遺失風險: - PostgreSQL 重啟 → WAL 截斷、事務回滾 - Redis 重啟 → in-memory 資料遺失、冪等鎖消失 - ClickHouse 重啟 → 列欄檔案損壞 同時,系統缺乏「AI 動作可追查」機制:OpenClaw 的 LLM 推理過程與 alert_operation_log 斷層。 --- ## 決策 ### D1 — 服務分級(Q1) 建立四級 Stateful 分類,儲存於 `ops/config/service-registry.yaml`(IaC,版控): | 等級 | 定義 | 服務 | |------|------|------| | `BLOCK` | 系統禁止,僅告警 | PostgreSQL (所有實例), ClickHouse | | `CRITICAL_HITL` | MultiSig 2票才執行 | Redis, Gitea, Harbor, MinIO | | `STANDARD_HITL` | 1票審核,特殊 restart 命令 | Prometheus, Grafana, Alertmanager | | `AUTO` | 自動執行 | Nginx, 所有 K3s Pod, Ollama 等 | ### D2 — Pre-flight 備份檢查(Q2) 針對 `CRITICAL_HITL` 且 `requires_pre_backup=True` 的服務,執行前檢查: - Velero 最近 Completed 備份 < 4 小時 → 放行 - 過期 → **Abort + 觸發緊急備份(非同步)+ 通知人工**(非直接執行) - CPU/IO 高負載類告警 → 禁止觸發備份(Q4,防止雪上加霜) ### D3 — MultiSig 雙簽(Q3) `CRITICAL_HITL` 服務需要 2 票 Telegram 授權才執行,延續 Sprint 3 的 MultiSig 基礎設施。Sprint 5.1 先以同一 user 兩次點擊驗證狀態機,後續 Sprint 擴充多帳號。 ### D4 — Prometheus auto_repair flag 優先級(Q9) - `auto_repair: "false"` → 強制 HITL,AI 無法覆寫 - `auto_repair: "true"` → 進入 AI + Guardrail 評估,Guardrail 有最終否決權 ### D5 — Langfuse trace_id 寫入 alert_operation_log(Q10) OpenClaw 分析完成後,`langfuse_trace_id` 必須寫入 `alert_operation_log.context`,實現 AI 動作全程可追查。 ### D6 — AlertManager 不抑制(Q11) Guardrail 阻擋時,不呼叫 AlertManager silence API。靠 AWOOOI Redis TTL 去重(10 分鐘),AlertManager 持續 firing 保持監控可見性。 --- ## 新增 event_type(共 8 個) ``` GUARDRAIL_BLOCKED # Stateful 服務被阻擋 PRE_FLIGHT_PASSED # Pre-flight 備份檢查通過 PRE_FLIGHT_FAILED # Pre-flight 失敗(備份過期) BACKUP_TRIGGERED # 緊急備份已觸發 BACKUP_COMPLETED # 緊急備份完成 BACKUP_FAILED # 緊急備份失敗 APPROVAL_ESCALATED # 升級為 CRITICAL_APPROVAL(需 2 票) CHANGE_APPLIED # 手動變更已記錄 ``` --- ## 新增模組 | 模組 | 路徑 | 職責 | |------|------|------| | ServiceRegistryClient | `services/service_registry.py` | 讀取 YAML,查詢服務分級 | | VeleroClient | `services/velero_client.py` | kubectl 查詢備份狀態,觸發緊急備份 | | PreflightService | `services/preflight_service.py` | Pre-flight 備份檢查邏輯 | 所有模組遵循 leWOOOgo 積木化規範:Service 層,有 `get_xxx()` + `set_xxx()` singleton 模式。 --- ## 後果 - 所有有狀態服務的自動修復操作,由「預設允許」改為「預設拒絕,明確授權才執行」 - AI 每一個修復決策都有 Langfuse trace_id 可追查 - Prometheus alert rule 的 `auto_repair` flag 成為有效的安全底線 - 系統複雜度增加,但「資料安全」優先於「修復速度」 --- ## 實施計畫 見 `docs/superpowers/plans/2026-04-08-sprint5-data-safety-guardrails.md`(Layer 0~7 完整步驟) --- ## 實施記錄(Sprint 5.1 執行) ### L1-L5 完成(2026-04-08 commit 88696db) - DB Migration M-002/M-003 已在 192.168.0.188 執行完畢 - `ops/config/service-registry.yaml` 建立(21 個服務分級) - 三個新 Service 建立:`service_registry.py` / `velero_client.py` / `preflight_service.py` - Guardrail 注入 `auto_repair_service.py`(BLOCK 等級保守拒絕) - ALERT_RECEIVED 溯源 + `auto_repair` flag Q9 + Langfuse trace_id Q10 寫入 `webhooks.py` - `db/models.py` 同步 MultiSig 欄位 - `docker-health-monitor.sh` 純感知層改造(移除所有 docker restart) - T1-T6 六個 Telegram 通知方法加入 `telegram_gateway.py` ### 首席架構師審查(2026-04-08 commit 0f5fecf) 評分:70/100 → 修正後 90+/100 | 問題 | 級別 | 修正 | |------|------|------| | 三個新 service 使用 `logging` 而非 `structlog` | S1 | 改用 `structlog.get_logger()` | | `velero_client` 使用 `datetime.now(UTC)` | S1 | 改用 `now_taipei()`(台北時區鐵律) | | Guardrail 失敗時放行(保守原則方向錯誤) | S1 | 失敗時 block,返回 `GUARDRAIL_ERROR` | | `service_registry` import 在函數內部 | S1 | 移至模組頂部 | | T1-T6 方法無 try/except | S2 | 全部補齊,失敗 log 不拋出 | | Langfuse URL 硬寫內網 IP | S2 | 改用 `settings.LANGFUSE_URL` | | `velero trigger_emergency_backup` kubectl 語法錯誤 | S3 | 改為 `kubectl apply Backup CRD` |