# ADR-037: 監控增強架構 - 異常頻率統計與根本修復

> **狀態**: ✅ Wave A+B 完成
> **日期**: 2026-03-29
> **決策者**: 統帥 (已批准)
> **審查者**: 首席架構師 (Wave A: 91/100, Wave B: 92/100 OUTSTANDING)
> **預估工時**: 17h (7 Phase)
> **整合計畫**: [MONITORING_MASTER_PLAN.md](../proposals/MONITORING_MASTER_PLAN.md) (Wave A-D / 10.75h)

---

## 背景

2026-03-29 統帥明確指示：
> "重啟只是治標，不是治本！太常發生的異常必須徹底解決"
> "需要統計、計數！必須要讓使用者知道！！"
> "太常發生的異常，必須要有徹底解決的自動修復機制！！！"

### 現狀問題

| 問題 | 影響 | 根因 |
|------|------|------|
| 重複異常無統計 | 同樣問題反覆告警 | 無頻率追蹤機制 |
| 修復只靠重啟 | 治標不治本 | 無 Tier 分級修復策略 |
| 資料庫無監控 | PostgreSQL/Redis 盲區 | 缺少 Exporter |
| Sentry 無回寫 | 修復結果斷鏈 | 缺少 Comment API 整合 |
| 無學習機制 | 無法自動改善 | 缺少成功率統計 |

---

## 決策

### 1. AnomalyCounter 服務 (Phase A)

**技術選型**: Redis Sorted Set + 滑動窗口

```python
# 異常簽名 Hash 生成
def generate_anomaly_key(signature: dict) -> str:
    """生成異常簽名的唯一 key"""
    key_parts = [
        signature.get("alert_name", ""),
        signature.get("service", ""),
        signature.get("namespace", ""),
        signature.get("error_type", ""),
    ]
    return hashlib.sha256("|".join(key_parts).encode()).hexdigest()[:16]
```

**統計維度**:
- `count_1h`: 1 小時內發生次數
- `count_24h`: 24 小時內發生次數
- `count_7d`: 7 天內發生次數
- `count_30d`: 30 天內發生次數

**升級閾值**:
| 等級 | 閾值 (24h) | 行動 |
|------|-----------|------|
| NORMAL | < 3 | 正常處理 |
| REPEAT | ≥ 3 | 標記重複，通知用戶 |
| ESCALATE | ≥ 5 | 升級 Tier，通知 Owner |
| PERMANENT_FIX | ≥ 10 | 強制根因修復 |

### 2. Tier 分級修復策略 (Phase A)

| Tier | 名稱 | 修復動作 | 適用場景 |
|------|------|---------|---------|
| 1 | 重啟 | restart_pod, restart_container | 首次異常 |
| 2 | 緩解 | scale_up, flush_cache, kill_queries | 重複 2 次 |
| 3 | 根因 | apply_fix, update_config, run_migration | 24h ≥ 5 次 |
| 4 | 架構 | failover, switch_backend, permanent_fix | 24h ≥ 10 次 |

**修復嘗試記錄**:
```python
# Redis Hash: anomaly:{key}:repair_stats
{
    "restart_pod": {"total": 3, "success": 1, "rate": 0.33},
    "scale_up": {"total": 1, "success": 1, "rate": 1.0},
}
```

### 3. Database Exporters (Phase B)

| 服務 | Exporter | Port | 關鍵指標 |
|------|----------|------|---------|
| PostgreSQL | postgres_exporter | 9187 | 連接池、慢查詢、鎖等待、表膨脹 |
| Redis | redis_exporter | 9121 | 記憶體、命中率、驅逐率、延遲 |

**部署位置**: 192.168.0.188 (Docker Compose)

### 4. Incident 頻率欄位 (Phase C)

```python
class IncidentFrequencyStats(BaseModel):
    anomaly_key: str
    count_1h: int = 0
    count_24h: int = 0
    count_7d: int = 0
    count_30d: int = 0
    escalation_level: str | None = None  # REPEAT, ESCALATE, PERMANENT_FIX
```

**聚合窗口**: 10 分鐘內同一問題不建新 Incident

### 5. Sentry Comment 回寫 (Phase D)

```
POST /api/0/issues/{issue_id}/comments/
Authorization: Bearer {SENTRY_API_TOKEN}
{"text": "🤖 OpenClaw 自動修復: restart_pod 成功"}
```

### 6. SignOz 告警規則 (Phase E)

| 指標 | 閾值 | 嚴重度 |
|------|------|--------|
| Error Rate | > 5% (5m) | warning |
| P95 Latency | > 2s | warning |
| Trace 異常 | duration > 10s | critical |

### 7. Learning Service (Phase G)

```python
class LearningService:
    async def should_skip_action(self, anomaly_key: str, action: str) -> bool:
        """成功率 < 20% 時跳過此動作"""
        stats = await self.counter.get_repair_stats(anomaly_key, action)
        return stats and stats["rate"] < 0.2
```

---

## 模組化合規

| 檢查項 | 狀態 | 說明 |
|--------|------|------|
| Interface 先定義 | ✅ | AnomalyCounter Protocol |
| Router 禁止直接 DB | ✅ | 透過 Service 層 |
| Repository 單一職責 | ✅ | AnomalyCounterRepository |
| 無循環依賴 | ✅ | counter → repair → learning |
| 可測試 (無 Mock) | ✅ | Redis Testcontainer |

---

## 實施計畫

| Phase | 任務 | 工時 | 依賴 | 狀態 |
|-------|------|------|------|------|
| A | AnomalyCounter + Tier 修復 | 4h | - | ✅ 已存在 |
| B | Database Exporters | 3h | - | ⏳ 待執行 |
| C | Incident 頻率欄位 | 2h | Phase A | ⏳ 待執行 |
| D | Sentry Comment 回寫 | 1h | Phase A | ✅ **Wave A.4** |
| E | SignOz 告警規則 | 2h | - | ✅ **Wave A.2+A.3** |
| F | Alert Chain E2E 驗證 | 2h | Phase A-E | ✅ **Wave A.6+B.1+B.2** |
| G | Learning Service | 3h | Phase A | ✅ 已存在 |

**總工時**: 17h (已完成約 10h)

### Wave A+B 完成明細 (2026-03-29)

| Wave | 任務 | 狀態 | 首席架構師審查 |
|------|------|------|---------------|
| A.1 | Sentry API Token | ✅ | 91/100 |
| A.2 | SignOz 告警規則 | ✅ | OUTSTANDING |
| A.3 | SignOz Webhook | ✅ | - |
| A.4 | Sentry Comment | ✅ | - |
| A.5 | Alert Chain Metrics | ✅ | - |
| A.6 | Smoke Test | ✅ | - |
| B.1 | PrometheusRule | ✅ | - |
| B.2 | CD Pipeline | ✅ | - |

---

## 風險與緩解

| 風險 | 影響 | 緩解 |
|------|------|------|
| Redis 記憶體增長 | 統計資料膨脹 | 30 天 TTL + ZREMRANGEBYSCORE |
| Tier 誤判 | 不當修復 | 人工審批 Tier 3/4 |
| Sentry API 限流 | Comment 失敗 | Rate Limiter + 重試 |

---

## 參考

- [MONITORING_STRATEGIC_PLANNING.md](../proposals/MONITORING_STRATEGIC_PLANNING.md)
- [IMPLEMENTATION_STEPS_ANOMALY_COUNTER.md](../proposals/IMPLEMENTATION_STEPS_ANOMALY_COUNTER.md)
- [IMPLEMENTATION_STEPS_DATABASE_EXPORTERS.md](../proposals/IMPLEMENTATION_STEPS_DATABASE_EXPORTERS.md)
- [IMPLEMENTATION_STEPS_INCIDENT_FREQUENCY.md](../proposals/IMPLEMENTATION_STEPS_INCIDENT_FREQUENCY.md)
- [IMPLEMENTATION_STEPS_REMAINING_PHASES.md](../proposals/IMPLEMENTATION_STEPS_REMAINING_PHASES.md)

---

## 變更紀錄

| 日期 | 版本 | 變更 | 作者 |
|------|------|------|------|
| 2026-03-29 | 1.0 | 初版建立 | Claude (首席架構師) |
| 2026-03-29 | 1.1 | Wave A+B 完成 (91/100 OUTSTANDING) | Claude Code |
