fix(api): 標示全零週報資料鏈異常
All checks were successful
Code Review / ai-code-review (push) Successful in 22s
CD Pipeline / tests (push) Successful in 1m40s
CD Pipeline / build-and-deploy (push) Successful in 4m10s
CD Pipeline / post-deploy-checks (push) Successful in 1m44s

This commit is contained in:
Your Name
2026-06-18 13:27:43 +08:00
parent 650b227a73
commit e0a32b3bd2
3 changed files with 100 additions and 5 deletions

View File

@@ -3168,6 +3168,11 @@ class WeeklyReportMessage:
disposition_manual: int = 0
disposition_cold_start: int = 0
disposition_total: int = 0
stats_source_ok: bool = True
k3s_source_ok: bool = True
git_source_ok: bool = True
cost_source_ok: bool = False
all_zero_actionable_anomaly: bool = False
def format(self) -> str:
"""格式化為 Telegram HTML"""
@@ -3175,6 +3180,29 @@ class WeeklyReportMessage:
alert_health = "" if self.resolved_rate >= 80 else "⚠️"
ai_health = "" if self.ai_success_rate >= 70 else "⚠️"
k3s_health = "" if self.k3s_uptime_pct >= 99 else "⚠️"
source_ok_count = sum([
self.stats_source_ok,
self.k3s_source_ok,
self.git_source_ok,
self.cost_source_ok,
])
all_zero = (
self.alert_total == 0
and self.ai_proposal_count == 0
and self.ai_executed_count == 0
and self.commits_count == 0
and self.deploy_count == 0
and self.ai_tokens_week == 0
and self.disposition_total == 0
)
actionable_all_zero = self.all_zero_actionable_anomaly or all_zero
report_trust = "低可信" if actionable_all_zero or source_ok_count < 4 else "可參考"
source_status = (
f"Stats={'ok' if self.stats_source_ok else 'fail'} / "
f"K3s={'ok' if self.k3s_source_ok else 'fail'} / "
f"Git={'ok' if self.git_source_ok else 'fail'} / "
f"Cost={'ok' if self.cost_source_ok else 'missing'}"
)
message = (
f"═══════════════════════════\n"
@@ -3182,6 +3210,11 @@ class WeeklyReportMessage:
f"═══════════════════════════\n"
f"📅 {html.escape(self.week_range)} | {html.escape(self.report_date)}\n"
f"━━━━━━━━━━━━━━━━━━━\n"
f"🧭 <b>報表資料信任度</b>\n"
f"├ 判定: <b>{report_trust}</b>\n"
f"├ 來源: <code>{html.escape(source_status)}</code>\n"
f"└ 全 0: <code>{'actionable_anomaly' if actionable_all_zero else 'no'}</code>\n"
f"━━━━━━━━━━━━━━━━━━━\n"
f"{alert_health} <b>告警統計</b>\n"
f"├ 總數: <code>{self.alert_total}</code>\n"
f"├ Critical: <code>{self.alert_critical}</code>\n"
@@ -3222,7 +3255,7 @@ class WeeklyReportMessage:
f"└ 自動化率: <b>{auto_rate}%</b>"
)
return message[:1200]
return message[:1800]
@dataclass

View File

@@ -94,7 +94,7 @@ class WeeklyReportService:
return week_range, monday, sunday
def _get_git_stats(self, since: datetime) -> tuple[int, int]:
def _get_git_stats(self, since: datetime) -> tuple[int, int, bool]:
"""取得 Git 統計 (commits, deploys)"""
try:
# 取得本週 commits 數量
@@ -118,10 +118,10 @@ class WeeklyReportService:
)
deploys = len(result_deploy.stdout.strip().split("\n")) if result_deploy.stdout.strip() else 0
return commits, deploys
return commits, deploys, True
except Exception as e:
logger.warning("git_stats_failed", error=str(e))
return 0, 0
return 0, 0, False
async def generate_report(self) -> WeeklyReportMessage:
"""
@@ -134,25 +134,29 @@ class WeeklyReportService:
report_date = now.strftime("%Y-%m-%d %H:%M")
# 取得統計數據 (7 天)
stats_source_ok = True
try:
incident_summary = await self._stats_service.get_incident_summary(days=7)
resolution_stats = await self._stats_service.get_resolution_stats(days=7)
ai_performance = await self._stats_service.get_ai_performance(days=7)
except Exception as e:
logger.warning("stats_fetch_failed", error=str(e))
stats_source_ok = False
incident_summary = {}
resolution_stats = {}
ai_performance = {}
# 取得 K3s 狀態
k3s_source_ok = True
try:
k3s_status = await self._k3s_monitor.collect_cluster_status()
except Exception as e:
logger.warning("k3s_fetch_failed", error=str(e))
k3s_source_ok = False
k3s_status = None
# 取得 Git 統計
commits, deploys = self._get_git_stats(monday)
commits, deploys, git_source_ok = self._get_git_stats(monday)
# 計算指標
total_incidents = incident_summary.get("total_incidents", 0)
@@ -216,6 +220,18 @@ class WeeklyReportService:
disposition_manual=disp_manual,
disposition_cold_start=disp_cold,
disposition_total=disp_total,
stats_source_ok=stats_source_ok,
k3s_source_ok=k3s_source_ok,
git_source_ok=git_source_ok,
cost_source_ok=False,
all_zero_actionable_anomaly=(
total_incidents == 0
and ai_proposals == 0
and ai_executed == 0
and commits == 0
and deploys == 0
and disp_total == 0
),
)
logger.info(

View File

@@ -18,6 +18,7 @@ from src.services.telegram_gateway import (
SentryErrorMessage,
TelegramGateway,
TelegramMessage,
WeeklyReportMessage,
)
@@ -53,6 +54,51 @@ def test_auto_repair_status_line_distinguishes_auto_resolved() -> None:
assert "CPU 92%-&gt;30%" in result
def test_weekly_report_marks_all_zero_as_low_trust_anomaly() -> None:
report = WeeklyReportMessage(
week_range="2026-W24",
report_date="2026-06-12 10:00",
stats_source_ok=False,
k3s_source_ok=True,
git_source_ok=False,
cost_source_ok=False,
all_zero_actionable_anomaly=True,
)
body = report.format()
assert "報表資料信任度" in body
assert "判定: <b>低可信</b>" in body
assert "Stats=fail" in body
assert "Git=fail" in body
assert "Cost=missing" in body
assert "全 0: <code>actionable_anomaly</code>" in body
assert "告警統計" in body
def test_weekly_report_keeps_nonzero_source_status_visible() -> None:
report = WeeklyReportMessage(
week_range="2026-W24",
report_date="2026-06-12 10:00",
alert_total=3,
ai_proposal_count=2,
commits_count=5,
deploy_count=1,
ai_tokens_week=1200,
stats_source_ok=True,
k3s_source_ok=True,
git_source_ok=True,
cost_source_ok=True,
)
body = report.format()
assert "判定: <b>可參考</b>" in body
assert "全 0: <code>no</code>" in body
assert "Commits: <code>5</code>" in body
assert "Tokens: <code>1,200</code>" in body
def test_telegram_html_chunks_preserve_complete_lines() -> None:
"""歷史/詳情長訊息不得用 text[:500] 切壞 HTML tag。"""
lines = [