fix(telegram): keep info callbacks nonfatal
All checks were successful
Code Review / ai-code-review (push) Successful in 19s
CD Pipeline / tests (push) Successful in 1m10s
CD Pipeline / build-and-deploy (push) Successful in 3m41s
CD Pipeline / post-deploy-checks (push) Successful in 1m21s

This commit is contained in:
Your Name
2026-05-18 09:47:40 +08:00
parent ae18751d17
commit 0dd4b486c5
3 changed files with 85 additions and 7 deletions

View File

@@ -4017,17 +4017,17 @@ class TelegramGateway:
if action == "detail":
# ADR-050 P2: 取得事件詳情,傳送新訊息 (保留原始簽核卡片+按鈕)
# 2026-04-01 Claude Code (ADR-050 P2)
await self._answer_callback(callback_query_id, action, text="📋 詳情傳送中...")
await self._answer_callback_nonfatal(callback_query_id, action, text="📋 詳情傳送中...")
await self._send_incident_detail(incident_id)
elif action == "history":
# ADR-050 P2: 取得頻率統計
# 2026-04-01 Claude Code (ADR-050 P2)
await self._answer_callback(callback_query_id, action, text="📊 歷史統計傳送中...")
await self._answer_callback_nonfatal(callback_query_id, action, text="📊 歷史統計傳送中...")
await self._send_incident_history(incident_id)
elif action == "reanalyze":
# ADR-050 P2: 觸發重診
# 2026-04-01 Claude Code (ADR-050 P2): reanalyze button handler
await self._answer_callback(callback_query_id, action, text="🔄 重診排程中...")
await self._answer_callback_nonfatal(callback_query_id, action, text="🔄 重診排程中...")
await self._send_reanalyze_result(incident_id)
elif action == "drift_view_page":
# 2026-04-20 P0.1 ogt + Claude Opus 4.7: drift_view 分頁切頁
@@ -4037,7 +4037,7 @@ class TelegramGateway:
_page_num = int(_page_str)
except ValueError:
_rid, _page_num = incident_id, 0
await self._answer_callback(
await self._answer_callback_nonfatal(
callback_query_id, action, text=f"📄 切換至第 {_page_num + 1} 頁..."
)
await self._send_drift_diff_detail(_rid or incident_id, page=_page_num)
@@ -4408,7 +4408,7 @@ class TelegramGateway:
except UserNotWhitelistedError as e:
logger.warning("telegram_callback_denied", error=str(e), user_id=user_id)
await self._answer_callback(
await self._answer_callback_nonfatal(
callback_query_id,
"denied",
text="⛔ 您沒有簽核權限",
@@ -4417,7 +4417,7 @@ class TelegramGateway:
except NonceReplayError as e:
logger.warning("telegram_callback_replay", error=str(e))
await self._answer_callback(
await self._answer_callback_nonfatal(
callback_query_id,
"replay",
text="⚠️ 此操作已處理過",
@@ -4426,7 +4426,7 @@ class TelegramGateway:
except Exception as e:
logger.error("telegram_callback_error", error=str(e))
await self._answer_callback(
await self._answer_callback_nonfatal(
callback_query_id,
"error",
text="❌ 處理失敗",
@@ -5017,6 +5017,22 @@ class TelegramGateway:
"show_alert": False,
})
async def _answer_callback_nonfatal(
self,
callback_query_id: str,
action: str,
text: str | None = None,
) -> None:
"""Best-effort callback toast; never block the actual DB-backed reply."""
try:
await self._answer_callback(callback_query_id, action, text=text)
except Exception as exc:
logger.warning(
"telegram_answer_callback_nonfatal_failed",
action=action,
error=str(exc),
)
async def _update_message_after_action(
self,
message_id: int,

View File

@@ -195,6 +195,35 @@ async def test_send_html_line_message_attaches_awooop_markup_to_first_chunk(monk
assert all("reply_markup" not in payload for _, payload in sent_requests[1:])
@pytest.mark.asyncio
async def test_info_callback_sends_history_when_answer_callback_is_stale(monkeypatch):
"""Telegram answerCallbackQuery 400 不得阻斷詳情/歷史 DB truth-chain reply。"""
gateway = TelegramGateway()
sent_history = []
monkeypatch.setattr(gateway._security, "is_whitelisted", lambda _user_id: True)
async def stale_answer(*_args, **_kwargs):
raise telegram_gateway_module.TelegramGatewayError("HTTP error: 400")
async def fake_history(incident_id: str):
sent_history.append(incident_id)
monkeypatch.setattr(gateway, "_answer_callback", stale_answer)
monkeypatch.setattr(gateway, "_send_incident_history", fake_history)
result = await gateway.handle_callback(
callback_query_id="stale-callback",
callback_data="history:INC-20260513-79ED5E",
user_id=123456,
message_id=789,
)
assert result["success"] is True
assert result["info_action"] is True
assert sent_history == ["INC-20260513-79ED5E"]
class TestTelegramMessageFormat:
"""測試現有 TelegramMessage 格式化"""