Files
awoooi/docs/adr/ADR-078-gap-a4-placeholder-resolution.md
OG T aa4e5757a2
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 15m46s
fix: 技術債清理 — report_generation 重試機制 + GAP-A4 文件化
技術債 #1: postmortem 發送失敗靜默吞掉
- 3 次指數退避重試 (2s → 4s → 6s)
- 全失敗後送簡化降級通知到 SRE 群組
- 防止事後檢討默默消失

技術債 #2 (QueryBuilder 抽象): DEFER
- 全專案僅 1 處用 outcome JSON path query
- 違反「Don't design for hypothetical future requirements」
- 待第二 caller 出現再抽

技術債 #3 (E2E 測試): 已涵蓋
- test_gap_a4_placeholder_resolution.py TestMatchRuleRejection
- Mission C prod 鏈路實測(KubePodCrashLooping)
- Playwright K8s/Telegram staging 留待 staging 環境就緒

新增文件:
- ADR-078-gap-a4-placeholder-resolution.md
- LOGBOOK 2026-04-14 深夜收官條目

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-14 18:46:25 +08:00

93 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-078: GAP-A4 規則模板 Placeholder 解析強化
> **日期**: 2026-04-14台北傍晚
> **狀態**: ✅ Accepted
> **作者**: Claude Sonnet 4.6(首席架構師)+ 統帥戰場偵察
> **相關**: ADR-064 Rule Engine、ADR-077 MASTER 藍圖收案、GAP-A1 kubectl 注入防護
---
## 問題
MASTER 藍圖收案後,統帥 log 巡察發現**真正的隱性病灶**
```
auto_execute_blocked_unresolved_placeholder
action: kubectl rollout restart deployment HostHighCpuLoad ← target=alertname!
action: kubectl rollout restart deployment unknown
action: kubectl scale deployment unknown --replicas=3
```
大量告警在規則引擎路徑產生垃圾指令 → GAP-A1 防注入閘攔下 → 自動修復卡死 → **飛輪沉默 8.3 小時**
MASTER 藍圖未涵蓋此缺口,命名為 **GAP-A4規則 Action 模板 Placeholder 解析缺漏**
---
## 根因
`alert_rule_engine._extract_vars()` 解析邏輯在 Prometheus 告警**缺 `deployment` label** 時:
- 退回 `alertname``"unknown"` 作為 `target`
- 填入 `{target}` placeholder → 產生 `kubectl rollout restart deployment HostHighCpuLoad`
---
## 決策
### 三層防護
1. **新增 `_strip_pod_suffix()`** — Pod 名稱還原 Deployment/StatefulSet base name
- Deployment: `awoooi-api-7d6b776f78-4sgjl``awoooi-api`
- StatefulSet: `postgresql-0``postgresql`
2. **新增 `_is_bad_target()`** — 垃圾 target 識別
- 空/unknown/none/null
- 等於 alertname 本身
- IP:port、純 IP、含空白/括號/引號
3. **重寫 `_extract_vars()`** — 多層 label 查找(權威優先)
`deployment` > `app` > `statefulset` > `pod(去後綴)` > `container` > `service` > `target_resource`
4. **`match_rule()` 後置雙驗證**
- bad target → 清空 `kubectl_command` → 降級 LLM
- 殘留 `{``}` → 清空 `kubectl_command` → 降級 LLM
### 降級策略
規則引擎清空 `kubectl_command` 後,`decision_manager` 會自然降級到 LLM 路徑OpenClaw/NemoTronLLM 有能力從 log 內容推理真實 deployment 名稱。若 LLM 也無解,進 TYPE-4 人工扶梯。
---
## 結果
- Commit `10b74af`
- 33 個新單元測試214/214 回歸全綠
- LOG: `rule_kubectl_command_discarded_bad_target` 取代 `auto_execute_blocked_unresolved_placeholder`
- 飛輪恢復運轉可能性大幅提升LLM 會接手處理無 deployment label 的告警)
---
## 教訓
1. **防注入閘是盡責的守門員**,但會遮蔽上游 bug。遇到大量攔截日誌必須追上游。
2. **測試告警需涵蓋缺 label 的 sad path**。原單元測試只測 happy path。
3. **log 監控不能取代 metrics 告警**`auto_execute_blocked_unresolved_placeholder` 累積 8.3 小時才被人工發現,應加 Prometheus 告警規則。
---
## 後續
- [ ] 加 Prometheus 告警規則:`rule_kubectl_command_discarded_bad_target` rate > 5/min 觸發 TYPE-8M flywheel_health
- [ ] 補 E2E 測試:真實 Alertmanager 發 HostHighCpuLoad → 驗證 target 正確降級
- [ ] 檢查其他規則(如 SSH 路徑)是否有類似 placeholder 解析問題
---
## 相關
- Memory: [feedback_placeholder_resolution_rule.md](~/.claude/projects/-Users-ogt-awoooi/memory/feedback_placeholder_resolution_rule.md)
- 測試: `apps/api/tests/test_gap_a4_placeholder_resolution.py`
- 源碼: `apps/api/src/services/alert_rule_engine.py:94-180`
*Accepted by 統帥 @ 2026-04-14 台北深夜*