# Telegram 事故通知模型

> 目的：讓 SRE 戰情室一眼分辨「AI 已修復」、「AI 可建議但需批准」、「AI 無法安全修復需人工」與「僅通知」，避免告警、執行 log、Code Review、Drift 與審批結果互相洗版。

## 核心判斷

Telegram 不應是完整執行日誌，也不應承載所有 AI 推理細節。Telegram 的職責是把需要人類注意力的決策摘要送到 SRE 戰情室；完整時間線、工具輸出、重試原因、provider fallback 與 audit 交給 AwoooP Run Monitor / Incident Timeline。

## 四種通知狀態

| 狀態 | 意義 | Telegram 行為 | 操作者動作 |
| --- | --- | --- | --- |
| AI 已自動修復 | 自動化已完成且驗證通過 | 更新原 incident 卡或回覆一次結果 | 檢查即可，不需批准 |
| AI 建議待審批 | AI / 規則已提出可執行建議，但被 Trust / Risk gate 擋下 | 發一張 ACTION REQUIRED 主卡 | 批准、拒絕、靜默或看詳情 |
| AI 無法安全修復 | NO_ACTION、INVALID_TARGET、LLM timeout、MCP 失敗或缺少安全動作 | 發人工接手摘要，不重複刷同一狀態 | 人工排查，或要求重診 |
| 僅通知 | 心跳、報表、Code Review 完成、低風險治理資訊 | 彙總卡或摘要頻道 | 通常不需即時動作 |

## 專業化訊息規則

1. 同一個 `incident_id` 只應有一張主卡。後續狀態使用原卡回覆、編輯按鈕或 AwoooP timeline，不再每一步都新發卡。
2. 主卡第一屏必須顯示「處置狀態」，先回答：AI 是否能修、是否已修、是否需要人工。
3. 同一個 `incident_id` 的相同狀態更新，短時間內要去重。詳細重試與錯誤放到 timeline，不洗 Telegram。
4. P0 / P1 escalation 可以另發升級卡，但內容必須是「目前影響、已嘗試、卡住原因、需要誰做什麼」，不可重貼所有底層 log。
5. Code Review、Config Drift、報表、心跳不應和 incident 執行回覆混在同一種語義；它們可以在同一 SRE 群組，但必須以摘要卡與固定前綴區分。
6. 主機、容器、runner、Nginx、Wazuh、Kali、CI/CD 這類資安 / 維運告警不得直接外送 `ps aux`、`docker stats`、stdout/stderr 或完整路徑；必須先轉成 AI 自動化事件包，再只保留可判讀摘要與 top evidence。

## AI 自動化告警事件包

IwoooS / AwoooP 是 AI 自動化產品，Telegram 告警不是終點，而是自動化飛輪的入口。任何可觸發值班判斷的告警，至少要能被轉成 `ai_automation_alert_card_v1` 等級的事件包。

合格告警的定義不是「有送出訊息」，而是能讓 operator 直接看出 AI 已把訊號送進哪一條自動化 lane、產生哪一個候選、目前被哪一道 Gate 擋住、誰要審、驗證要看哪裡，以及後續如何回寫 Timeline / KM / PlayBook。未做到這件事的訊息只能算 raw observability，不能算 AWOOOI 產品層告警。

事件包必填欄位：

| 欄位 | 說明 |
| --- | --- |
| 事件類型 | 例如 `host_resource_pressure`、`runner_build_resource_pressure`、`wazuh_intrusion_signal`、`kali_assessment_signal`、`nginx_config_drift`。 |
| 影響判讀 | 用一到三行說明現在影響的是服務可用性、入侵風險、部署風險、資料完整性或觀測盲點。 |
| 視覺化摘要 | 使用條狀圖、狀態列、矩陣或後續圖卡；不得只丟 raw log。Telegram 純文字階段可用 `■■□□` 類視覺 bar，前端 / 報表可再升級圖卡。 |
| AI lane | 指定 AI 後續分流 lane，例如 runner 資源壓力、主機入侵、設定漂移、供應鏈風險。 |
| Gate | 明確顯示 `candidate_only`、`approval_required`、`runtime_write_gate=0` 或已取得的授權；不得把告警當成 runtime 寫入批准。 |
| Top evidence | 最多保留前三個可判讀證據；只放 PID、CPU、服務類型、告警規則、redacted evidence ref，不放完整主機路徑、secret、個人 namespace 或內部對話內容。 |
| 建議下一步 | 指向 AI 要沉澱的候選、owner 欄位、AwoooP Run / Work Item / IwoooS gate，而不是只叫人看 log。 |
| 禁止事項 | 當下不允許的動作要明確列出，例如不 kill process、不 restart Docker / Gitea、不 reload Nginx、不改 firewall、不觸發 Kali active scan。 |

事件包必須能接到下列產品閉環：

| 閉環節點 | 必須可回讀的狀態 |
| --- | --- |
| AI lane | `security_intrusion_triage`、`runner_build_resource_pressure`、`nginx_config_drift`、`supply_chain_drift` 等明確 lane。 |
| Candidate | 對應候選動作、owner request、dry-run、Work Item 或 Run；不得只有「請人工判斷」。 |
| Gate | `candidate_only`、`approval_required`、`runtime_write_gate=0/1`、批准者與批准理由。 |
| Verifier | post-check、route smoke、receipt readback、Wazuh / SIEM readback、production health 或 no-write 驗證結果。 |
| Learning | Timeline event、KM / PlayBook writeback、trust score / rule learning 或報表沉澱狀態。 |

不合格告警範例：

- 只貼 CPU、`ps aux`、`docker stats`、stdout/stderr、完整路徑或完整 log。
- 只說「AI 選擇不執行」但沒有候選、Gate、owner、verifier 或 learning。
- 把工作視窗、內部對話、個人 namespace、內網位址、secret 片段或未脫敏 raw payload 放進 Telegram 或前端。
- 把 Telegram 送達、UI 可見、CD success 或 smoke success 誤當成 runtime 寫入批准。

Host / runner 資源告警的第一版落地：

- `TelegramGateway.send_alert_notification()` 與 `send_text()` 會在最後出口自動套用 host resource formatter；即使呼叫端傳入 Markdown，也必須強制改成脫敏 HTML 卡片。
- `TelegramGateway._send_request("sendMessage", ...)` 也必須套用同一個 formatter，避免 approval execution、legacy helper 或未來 direct gateway 呼叫繞過 `send_alert_notification()` / `send_text()`。
- `CPU 警告`、`容器內 root Node.js 進程`、含 `ps aux` 且指向 build / package install / Prisma generate 程序的文字，會被轉成 `ai_automation_alert_card_v1`。
- raw process dump 會被壓成 `PID + CPU + 精簡命令`，不保留 `/workspace/...`、`/opt/hostedtoolcache/...`、完整 `node_modules` 路徑、外部檢查 URL、JSON payload 或整段 `ps aux`。
- build 壓力會分流到 `runner_build_resource_pressure`；Prisma / package install 壓力會分流到 `runner_prisma_generate_resource_pressure`；預設都是 `candidate_only / runtime_write_gate=0`。
- 這只建立 AI 候選與判讀入口，不代表允許 kill process、restart 服務、改 Nginx、改 firewall 或執行 Kali active scan。

非 host 維運 / 資安訊號的第一版落地：

- `TelegramGateway.send_alert_notification()` 與 `send_text()` 現在也會把 Wazuh、Kali、Nginx drift、Backup / Restore / Escrow、Provider freshness、Supply-chain drift 類訊號轉成同一版 `ai_automation_alert_card_v1`。
- 事件類型固定映射：
  - `wazuh_dashboard_api_readback_degraded` → `siem_observability_readback_degraded`
  - `wazuh_intrusion_signal` → `security_intrusion_triage`
  - `kali_assessment_signal` → `security_assessment_review`
  - `nginx_config_drift` → `public_gateway_config_drift`
  - `backup_restore_escrow_signal` → `backup_restore_escrow_triage`
  - `provider_freshness_signal` → `source_provider_freshness_triage`
  - `supply_chain_drift` → `supply_chain_drift_review`
- 所有上述卡片都必須顯示 `candidate_only / runtime_write_gate=0`，並把下一步導向 owner evidence、reviewer acceptance、rendered diff / freshness / restore / SIEM readback、KM / PlayBook / Verifier 沉澱。
- Wazuh Dashboard 顯示 agent 消失但 agent transport 或 manager service 仍有只讀證據時，必須優先分類為 `wazuh_dashboard_api_readback_degraded`；在 manager registry counts 未驗收前，不得把它寫成「所有 agent 已消失」或「agent 已恢復」。
- formatter 會在 Telegram 最後出口脫敏 URL、內網 IP、絕對路徑、Bearer token、token / password / secret / api key 類 assignment；Top evidence 最多保留三行摘要。
- 這只把 raw signal 變成 AI 自動化候選，不代表允許 Wazuh 封鎖、Kali active scan、`nginx -t` / reload、backup / restore / remote delete、provider switch、package upgrade、workflow dispatch 或 production write。

通知出口旁路清冊：

- `docs/security/telegram-notification-egress-inventory.snapshot.json` 目前固定 repo 內 `0` 個 direct Bot API `sendMessage`，分布為 Gitea workflow `0`、ops script `0`、API direct path `0`。
- `apps/api/src/services/channel_hub.py` 的 interim feedback sender 已改走 `TelegramGateway.send_text()`，讓 non-shadow interim 訊息進入既有 final-exit formatter、thread reply、錯誤 sanitizer 與 AwoooP outbound mirror path；不再直接讀 `TELEGRAM_BOT_TOKEN` 或拼 Bot API URL。
- `scripts/ops/backup-from-110.sh`、`scripts/ops/docker-health-monitor.sh`、`scripts/ops/dr-drill.sh`、`scripts/ops/pg-backup.sh` 的 legacy direct Bot API fallback 已移除；API 不可達時只留下本地 log，不再繞過 DB/log receipt 與 AI automation。
- `docs/security/telegram-notification-egress-owner-request-draft.snapshot.json` 已讀回 `0` 份 metadata-only candidate；owner response 欄位只能作為 evidence，不得阻擋低爆炸半徑 controlled apply。
- `docs/security/telegram-notification-egress-migration-plan-draft.snapshot.json` 已讀回 `0` 份 migration candidate；migration runtime send / Bot API call / secret read 仍維持 `0`。
- `GET /api/v1/agents/telegram-alert-ai-automation-matrix` 會把上述清冊與 readability guard、AI digest policy、AwoooP outbound mirror source contract 合併，讀回 DB/log receipt、AI route、controlled queue、work item、post verifier、learning writeback、manual/default gap 與 direct send gap。
- direct egress 已不再是目前 repo 內已知缺口；後續若新增 direct Bot API 會被 no-new-bypass guard 阻擋，並必須先回到 TelegramGateway / AwoooP receipt path。
- 清冊階段只允許保存 path、line、redacted excerpt、owner 欄位與 reviewer gate；不送 Telegram、不讀 Bot token、不保存 chat secret、不改 workflow / script、不開 runtime gate。
- 後續每個 direct egress 要收斂前，都必須補 owner route、message shape、redaction contract、formatter convergence plan、delivery receipt、fallback mode、rollback owner 與 post-check evidence。

Host / runner 告警卡片必須採用下列第一屏版型：

```text
P1 主機資源壓力｜h110-gitea
ai_automation_alert_card_v1

一眼摘要
├ CPU 使用率：29.8%
├ Load：8.62 ■■■■■■■■
├ 容器 root 進程：3
└ 影響：Prisma generate / package build 程序正在吃 CPU；先確認 CI/CD、runner job 與供應鏈來源，不可直接 kill

AI 自動化判讀
├ Lane：runner_prisma_generate_resource_pressure
├ Gate：candidate_only / runtime_write_gate=0
└ 下一步：建立 Prisma / package install 資源壓力候選，交由 AI 彙整 CI/CD run、套件來源、runner queue 與供應鏈 evidence

Top evidence
├ PID 365 CPU 27.5%：Prisma generate root
├ PID 376 CPU 15.5%：Prisma generate root
└ PID 392 CPU 0%：Prisma generate root

建議下一步
├ 確認是否為 CI/CD / Actions / runner 正常建置或 package install 窗口
├ 若持續超過門檻，先查 runner queue、build job、套件來源、容器資源限制與服務 SLO
└ 同一 host/service 5 分鐘聚合一次，避免洗版

禁止事項
└ 不 kill process、不 restart Docker / Gitea、不 reload Nginx、不改 firewall；除非已有維護窗口與 owner 批准。
```

## 與 AwoooP 的分工

| 介面 | 承載內容 |
| --- | --- |
| Telegram | 決策摘要、升級、人工批准入口 |
| AwoooP Run Monitor | 非同步 Run、provider fallback、tool call、retry、latency |
| Approval Queue | 所有等待批准的高風險動作 |
| Incident Timeline | 事件完整歷程、AI 嘗試、失敗原因、KM / Playbook 回寫 |
| MCP Audit | 工具執行、redaction、permission gate、credential 注入 |

## 2026-05-12 live gate

> Canonical diagnosis and repair waves live in `docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md` §2.5. This section is only the Telegram-facing contract.

Telegram 卡片目前不能再只顯示「AI 研判 / 建議動作」。每張卡都必須能回查到一筆 truth-chain 狀態，最少包含：

- `source_event_id` / `fingerprint` / `repeat_count` / `first_seen` / `last_seen`
- current stage：received、deduped、evidence、MCP、decision、approval、execution、verification、learning、resolved / manual_required
- evidence quality：sensors attempted / succeeded、failed sensors、Sentry / SignOz / Prometheus refs
- MCP usage：AwoooP Gateway audit、legacy direct MCP、not-used reason
- executor choice：Ansible / MCP / K8s / SSH / no_action，以及 dry-run / diff / rollback evidence
- approval / execution / verification：approval_id、operation op_id、verification_result、KM / Playbook writeback

Live 2026-05-12 evidence shows this gate is not yet green:

- AwoooP Run State 24h is still `legacy_outbound` shadow with `step_total=0`.
- `awooop_mcp_gateway_audit` has 0 rows; legacy `mcp_audit_log` has activity but is not the AwoooP choke point.
- `INC-20260512-B6C589` has incident / approval status mismatch and `8/8` failed SSH sensors.
- Config Drift repeats hourly with the same counts and pending status, but Telegram does not show repeat/update state.
- Outbound mirror visibility must be revalidated after RLS; the app role currently cannot rely on it as a complete truth source.

## 本輪落地

- `TelegramMessage` 主卡新增「處置狀態」。
- `append_incident_update()` 對同一 incident 的相同狀態做 5 分鐘 Redis 去重。
- `append_incident_update()` 對相同的「AI 自動修復失敗 / AI 診斷工具失敗」摘要增加 10 分鐘跨 incident 去重；每個 incident 仍會移除原卡危險按鈕，但 Telegram 不再重複 reply 同一個失敗摘要。
- `TelegramGateway._send_request()` 對成功送出的 legacy `sendMessage` 增加 AwoooP `awooop_outbound_message` 鏡像。鏡像失敗只記錄 `telegram_outbound_mirror_failed`，不能影響 Telegram 正常送達。
- `ai_automation_alert_card_v1` 送出後，AwoooP mirror envelope 需帶 `ai_automation_alert_card_mirror_v1` metadata，至少包含 `event_type`、`lane`、`target`、`gates`、`runtime_write_gate_count=0` 與 `delivery_receipt_readback_required=true`；不得把 raw alert、完整 Telegram text、token、內網 URL、主機路徑或 raw Wazuh payload 放進 envelope。
- `GET /api/v1/platform/runs/ai-alert-cards` 只讀查詢 `ai_automation_alert_card_v1` delivery readback，可用 `project_id`、`event_type`、`lane` 篩選；此路徑只回 metadata、source refs 與 send status，不回完整 Telegram text，也不代表 Telegram 已實發或 Wazuh registry 已驗收。
- 成本告警、審批執行結果、自愈 rollback 提案已由 direct Bot API 改走 `TelegramGateway._send_request()`，避免繞過 outbound mirror。
- `telegram_gateway.py` 內部歷史直打 `sendMessage` 路徑已收斂；多 Bot `_send_as_bot()` 因需指定 token 保留 direct HTTP，但成功後同樣鏡像到 `awooop_outbound_message`。
- 既有 `詳情 / 重診 / 歷史` 按鈕保留，讓 Telegram 保持輕量，細節回到控制台。

## 後續建議

1. 將 Telegram 群組升級為 Forum topics 或固定 topic lane：`P0/P1 事故`、`人工審批`、`治理/報表`、`CI/Code Review`。
2. AwoooP Approval Queue 顯示與 Telegram 相同的「處置狀態」欄位，避免前後端語義分裂。
3. 將 auto-repair failure 的完整 stdout/stderr 改寫入 Run Timeline，只在 Telegram 顯示最短摘要與詳情連結。
4. 對 firing 告警做 fingerprint 聚合：同一 alertname + target + namespace 在窗口內只更新卡片，不新增卡片。
