feat(adr-075): Phase 2 — TYPE-8M 飛輪/告警鏈路健康通知格式與路由
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 4m0s
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 4m0s
新增 send_meta_alert() — ⚙️ META SYSTEM 卡片(觸發診斷/查看面板/靜默) decision_manager 新增 TYPE-8M elif 分支(在 TYPE-4D 後) _alert_category 提取提前至 if 鏈前,三個分支共用 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -227,6 +227,11 @@ async def _push_decision_to_telegram(
|
|||||||
decision_state=_decision_state,
|
decision_state=_decision_state,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 2026-04-12 ogt: ADR-075 — 從 Incident 提取 alert_category/notification_type(各分支共用)
|
||||||
|
_alert_category = getattr(incident, "alert_category", "") or ""
|
||||||
|
_notification_type = getattr(incident, "notification_type", "") or (_notif_type.value if _notif_type else "")
|
||||||
|
_alertname = incident.signals[0].labels.get("alertname", "MetaSystemAlert") if incident.signals else "MetaSystemAlert"
|
||||||
|
|
||||||
if _notif_type == NotificationType.TYPE_1:
|
if _notif_type == NotificationType.TYPE_1:
|
||||||
# 純資訊通知 — 無按鈕
|
# 純資訊通知 — 無按鈕
|
||||||
tg_result = await gateway.send_info_notification(
|
tg_result = await gateway.send_info_notification(
|
||||||
@@ -244,11 +249,20 @@ async def _push_decision_to_telegram(
|
|||||||
resource_name=target[:50],
|
resource_name=target[:50],
|
||||||
diff_summary=description[:500],
|
diff_summary=description[:500],
|
||||||
)
|
)
|
||||||
|
elif _notif_type.value == "TYPE-8M" or _alert_category in ("alertchain_health", "flywheel_health"):
|
||||||
|
# TYPE-8M:飛輪/告警鏈路健康異常,發到個人 DM(不發群組)
|
||||||
|
tg_result = await gateway.send_meta_alert(
|
||||||
|
incident_id=incident.incident_id,
|
||||||
|
approval_id=approval_id,
|
||||||
|
alertname=_alertname,
|
||||||
|
alert_category=_alert_category,
|
||||||
|
diagnosis=reasoning[:100] if reasoning else description[:100],
|
||||||
|
severity_level=risk_level,
|
||||||
|
system_impact=description[:150] if description else "",
|
||||||
|
probable_cause=reasoning[:100] if reasoning else "",
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# TYPE-2 / TYPE-3 / TYPE-4 都走 send_approval_card(按鈕組合由 alert_category 決定)
|
# TYPE-2 / TYPE-3 / TYPE-4 都走 send_approval_card(按鈕組合由 alert_category 決定)
|
||||||
# 2026-04-12 ogt: ADR-075 斷點 A 修復 — 從 Incident 提取 alert_category/notification_type
|
|
||||||
_alert_category = getattr(incident, "alert_category", "") or ""
|
|
||||||
_notification_type = getattr(incident, "notification_type", "") or _notif_type.value if _notif_type else ""
|
|
||||||
tg_result = await gateway.send_approval_card(
|
tg_result = await gateway.send_approval_card(
|
||||||
approval_id=approval_id,
|
approval_id=approval_id,
|
||||||
risk_level=risk_level,
|
risk_level=risk_level,
|
||||||
|
|||||||
@@ -1867,6 +1867,67 @@ class TelegramGateway:
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# =========================================================================
|
||||||
|
# ADR-075: TYPE-8M Meta-System 告警(飛輪/告警鏈路健康)
|
||||||
|
# 2026-04-12 ogt
|
||||||
|
# =========================================================================
|
||||||
|
|
||||||
|
async def send_meta_alert(
|
||||||
|
self,
|
||||||
|
incident_id: str,
|
||||||
|
approval_id: str,
|
||||||
|
alertname: str,
|
||||||
|
alert_category: str, # "flywheel_health" or "alertchain_health"
|
||||||
|
diagnosis: str,
|
||||||
|
severity_level: str = "critical",
|
||||||
|
system_impact: str = "",
|
||||||
|
probable_cause: str = "",
|
||||||
|
) -> dict:
|
||||||
|
"""
|
||||||
|
TYPE-8M Meta-System 告警 — 飛輪或告警鏈路自身健康異常。
|
||||||
|
|
||||||
|
適用: FlywheelPlaybookZero / AlertChainBroken_* 等
|
||||||
|
按鈕: 固定 3 個([觸發診斷] [查看面板] [靜默])
|
||||||
|
只發個人 DM,不發群組(雙頻道路由規則)。
|
||||||
|
"""
|
||||||
|
severity_emoji = "🔴" if severity_level == "critical" else "🟠"
|
||||||
|
category_label = "飛輪核心異常" if alert_category == "flywheel_health" else "告警鏈路異常"
|
||||||
|
|
||||||
|
text = (
|
||||||
|
f"⚙️ META SYSTEM | {severity_emoji} {category_label}\n"
|
||||||
|
f"━━━━━━━━━━━━━━━━━━━\n"
|
||||||
|
f"📋 <code>{html.escape(incident_id)}</code>\n"
|
||||||
|
f"🚨 異常元件:<b>{html.escape(alertname)}</b>\n"
|
||||||
|
f"🎯 診斷結果:{html.escape(diagnosis[:100])}\n"
|
||||||
|
)
|
||||||
|
if system_impact:
|
||||||
|
text += f"\n🧠 <b>系統影響</b>\n{html.escape(system_impact[:150])}\n"
|
||||||
|
if probable_cause:
|
||||||
|
text += f"└─ 可能根因:{html.escape(probable_cause[:100])}\n"
|
||||||
|
|
||||||
|
silence_nonce = self._security.generate_callback_nonce(approval_id, "silence")
|
||||||
|
keyboard = {
|
||||||
|
"inline_keyboard": [
|
||||||
|
[
|
||||||
|
{"text": "🔄 觸發診斷", "callback_data": f"action:flywheel_diag:{incident_id}"},
|
||||||
|
{"text": "📊 查看面板", "callback_data": f"action:flywheel_dashboard:{incident_id}"},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"text": "🔕 靜默 1h", "callback_data": silence_nonce},
|
||||||
|
],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return await self._make_request(
|
||||||
|
"sendMessage",
|
||||||
|
{
|
||||||
|
"chat_id": settings.OPENCLAW_TG_CHAT_ID,
|
||||||
|
"text": text,
|
||||||
|
"parse_mode": "HTML",
|
||||||
|
"reply_markup": keyboard,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
# 新訊息發送方法 (2026-03-29 ogt: ADR-038)
|
# 新訊息發送方法 (2026-03-29 ogt: ADR-038)
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user