# ADR-048: Sentry → OpenClaw AI Triage 自動化

**狀態**: 已實作 (Phase 23)
**日期**: 2026-04-01 (台北時區)
**作者**: Claude Code
**關聯**: Phase 10 (Sentry 基礎整合), Phase 21 (ADR-037 異常頻率統計), Phase 22 (ADR-044 Nemotron 協作)

---

## 問題陳述

Sentry 持續捕獲後端 Python 與前端 Next.js 錯誤，但缺乏自動化 triage 流程：

- 工程師需手動查看 Sentry Issue 並判斷嚴重程度
- 錯誤發生後沒有即時通知渠道（Telegram）
- 無法自動關聯歷史頻率判斷是否為常態錯誤或異常升級
- 沒有 AI 輔助根因分析，所有診斷依賴人工

**目標**：Sentry 新錯誤觸發時，自動完成 triage → AI 分析 → Incident 建立 → Telegram 通知，無需人工介入。

---

## 決策

透過 **Sentry Issue Alert Webhook** 整合 OpenClaw AI Triage 流程。

### 選擇 Webhook 而非輪詢的原因

| 方案 | 延遲 | 基礎設施成本 | 複雜度 |
|------|------|-------------|--------|
| Webhook (本方案) | 近即時 (<2s) | 無額外組件 | 低 |
| 輪詢 (每分鐘) | 最高 60s | 需 scheduler | 中 |
| Sentry Alerts API | 近即時 | 需 OAuth | 高 |

---

## 架構

```
自架 Sentry (192.168.0.110:9000)
    │  Issue Alert Webhook (action=triggered, level=error/fatal)
    ▼
AWOOOI API  POST /api/v1/webhooks/sentry/error
    │
    ├─ [同步] 去重檢查 (Redis, 10min TTL)
    ├─ [同步] Level 過濾 (只處理 error/fatal)
    │
    └─ [背景 BackgroundTask]
         │
         ├─ 1. AnomalyCounter.record_anomaly() → 頻率統計
         │      (ADR-037: 1h/24h/7d/30d + 升級判斷)
         │
         ├─ 2. OpenClawHttpService.analyze_error()
         │      Circuit Breaker (ADR-038) + Semaphore
         │      優先 Ollama (本地) → Fallback Claude
         │      → ErrorAnalysisResult (root_cause, fix, prevention, confidence)
         │
         ├─ 3. ApprovalService.create_approval()
         │      風險等級 = Sentry Level + 頻率升級
         │      → Approval ID
         │
         ├─ 4. TelegramGateway.send_approval_card()
         │      格式: 🐛 SENTRY 錯誤告警 + OpenClaw 分析 + [Y/n]
         │
         └─ 5. SentryService.post_issue_comment()
                AI 分析結果回寫至 Sentry Issue
```

### Sentry Cloud (wooo-92.sentry.io) 前端整合

前端 Next.js 錯誤透過 Sentry Cloud 捕獲，使用相同 Webhook 格式。
在 Sentry Cloud 配置 Alert Rule 指向同一端點：
`POST https://awoooi.wooo.work/api/v1/webhooks/sentry/error`

---

## 實作細節

### 端點

```
POST /api/v1/webhooks/sentry/error
```

### 觸發條件 (Sentry Alert Rule 配置)

- action: `triggered`
- level: `error` 或 `fatal`

### 去重策略

- Redis key: `sentry_dedup:{issue_id}`
- TTL: 600 秒 (10 分鐘)
- 同一 issue 10 分鐘內不重複處理

### 風險等級映射

| Sentry Level | 基礎風險 | 頻率升級 (ESCALATE) | 頻率升級 (PERMANENT_FIX) |
|-------------|---------|-------------------|------------------------|
| fatal       | CRITICAL | CRITICAL | CRITICAL |
| error       | HIGH | HIGH | CRITICAL |
| warning     | MEDIUM | HIGH | CRITICAL |

### Webhook Secret 驗證

- Config: `SENTRY_WEBHOOK_SECRET`
- Header: `sentry-hook-signature` (HMAC-SHA256)
- 生產環境未設定 → Fail-Closed 拒絕
- 開發環境未設定 → 允許跳過 (僅供測試)

---

## 影響評估

### 正向影響

- **MTTR 縮短**: AI 自動根因分析，工程師無需從 log 推斷
- **告警品質提升**: 頻率統計避免重複告警噪音
- **可審計性**: 所有 Sentry Issue 自動建立 Approval 記錄
- **回饋閉環**: AI 分析結果回寫 Sentry Comment，歷史可查

### 風險與緩解

| 風險 | 緩解措施 |
|------|---------|
| OpenClaw 不可用 | Circuit Breaker (ADR-038) + 降級：無 AI 分析仍建立 Approval |
| Telegram 傳送失敗 | Exception catch + log，不中斷主流程 |
| Redis 不可用 | check_dedup 失敗 → 預設 True（允許處理，可能重複） |
| Sentry API Token 未設 | Comment 回寫跳過，其他流程不受影響 |

### 不影響項目

- 現有 Alertmanager → AWOOOI → Telegram 流程不變
- 現有 GitHub Webhook 整合不變
- Sentry SDK 錯誤捕獲邏輯不變

---

## 相關檔案

- **Router**: `apps/api/src/api/v1/sentry_webhook.py`
- **Service (Sentry API)**: `apps/api/src/services/sentry_service.py`
- **Service (Webhook 業務邏輯)**: `apps/api/src/services/sentry_webhook_service.py`
- **Config**: `apps/api/src/core/config.py` (`SENTRY_WEBHOOK_SECRET`)
- **Circuit Breaker**: `apps/api/src/core/circuit_breaker.py` (ADR-038)

---

## 後續工作

- [ ] 在自架 Sentry 配置 Issue Alert Rule 指向 `/webhooks/sentry/error`
- [ ] 在 Sentry Cloud 配置相同 Alert Rule
- [ ] K8s Secret 注入 `SENTRY_WEBHOOK_SECRET`
- [ ] E2E 測試：手動觸發 Sentry Issue → 驗證 Telegram 收到告警
