feat(Phase 5 Sprint 5.4): 分類按鈕從 registry 動態產生 — 按鈕重啟上線
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 17m11s

_build_inline_keyboard() 改寫:
- 原 hardcode _CATEGORY_BUTTONS dict (28 按鈕) 已下架
- 改從 callback_action_spec.yaml registry 動態產生
- spec.callback_format 決定格式:
  * nonce (寫類) → self._security.generate_callback_nonce(approval_id, action_name)
  * info (查類) → {action_name}:{incident_id}
- 新按鈕只需改 yaml,零改 code

分類覆蓋 (從 yaml 自動推算):
- kubernetes: 6 按鈕 (4 寫 + 2 查)
- host_resource: 3 按鈕 (1 查 + 2 寫)
- secops: 4 按鈕 (全寫類 + Multi-Sig)
- database: 3 按鈕
- storage: 2 按鈕
- network: 3 按鈕
- devops_tool: 2 按鈕
- external_site: 2 按鈕
- business: 1 按鈕
- flywheel_health: 1 按鈕
- ssl_cert: 1 按鈕

這次按鈕不是鬼魂 — 每個都有:
 callback_format 正確 (4-part nonce / 2-part info)
 Sprint 5.3 dispatch handler 接收
 Sprint 5.2 MCP registry 執行
 audit log + reply_to 原卡片

回歸: 188/188

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-04-14 21:40:20 +08:00
parent de8bbd8ab9
commit a92562d65c

View File

@@ -1376,16 +1376,26 @@ class TelegramGateway:
alert_category: 告警類別 (ADR-071-E: 決定 TYPE-3 按鈕組合)
notification_type: 通知類型 (TYPE-1/2/3/4/4D)
"""
# 2026-04-14 Claude Sonnet 4.6 首席架構師裁示:
# 原 _CATEGORY_BUTTONS (28 個分類按鈕) 全部下架 — 信任 > 功能
# 盤查證據(統帥 2026-04-14 20:00 完整 audit:
# - callback_data 格式全錯 (3-part action:xxx:id 不符合 parser 4-part nonce / 2-part info)
# - 後端 0 個 handlergrep apps/api/src 無任何 dispatch elif 分支)
# - 從 2026-04-11 commit 325b3851 起死了 3 天
# - 統帥今天真踩到:點「查程序」沒反應 → 信任破壞
# 正式下架改用通用按鈕 (approve/reject/silence/detail/history/reanalyze)
# 補完計畫MASTER 藍圖 Phase 5「分類按鈕完整化」(另立 ADR)
_CATEGORY_BUTTONS: dict[str, list[tuple[str, str]]] = {} # 臨時空fallback 通用按鈕
# 2026-04-14 Claude Sonnet 4.6 (Phase 5 Sprint 5.4):
# 從 callback_action_spec registry 動態產生按鈕(原 _CATEGORY_BUTTONS hardcode 已下架)
# 優點:新增按鈕只需改 yamlcallback_data 格式由 spec.callback_format 決定
# 安全yaml 裡每個 action 都有對應 MCP dispatcher handlerSprint 5.2/5.3 實作)
from src.services.callback_dispatcher import list_actions_for_category as _list_actions
def _build_category_buttons_for(category: str) -> list[tuple[str, str]]:
"""從 registry 產生 (label, callback_data) list"""
actions = _list_actions(category)
btns: list[tuple[str, str]] = []
for spec_it in actions:
emoji_label = f"{spec_it.emoji} {spec_it.label}".strip()
if spec_it.callback_format == "nonce":
# 寫類:產生 4-part nonce
cb = self._security.generate_callback_nonce(approval_id, spec_it.name)
else:
# 查類2-part info
cb = f"{spec_it.name}:{incident_id}"
btns.append((emoji_label, cb))
return btns
# 產生 Nonce (防重放,用於寫操作)
approve_nonce = self._security.generate_callback_nonce(approval_id, "approve")
@@ -1394,11 +1404,13 @@ class TelegramGateway:
is_type3 = notification_type in ("TYPE-3", NotificationType.TYPE_3, "")
if is_type3 and alert_category and alert_category in _CATEGORY_BUTTONS:
_dynamic_buttons = _build_category_buttons_for(alert_category) if alert_category else []
if is_type3 and _dynamic_buttons:
# TYPE-3 動態操作按鈕:第一行為類別專屬操作
category_btns = [
{"text": text, "callback_data": cb_data}
for text, cb_data in _CATEGORY_BUTTONS[alert_category]
for text, cb_data in _dynamic_buttons
]
# 每行最多 3 個,超過換行
rows = [category_btns[i:i+3] for i in range(0, len(category_btns), 3)]