From f54dea48b157d3bf7edce5be65f27422c44b7906 Mon Sep 17 00:00:00 2001 From: OG T Date: Tue, 14 Apr 2026 18:32:29 +0800 Subject: [PATCH] =?UTF-8?q?fix(GAP-D5):=20=E6=97=A5=E5=BA=A6=E5=A0=B1?= =?UTF-8?q?=E5=91=8A=20DB=20=E6=AC=84=E4=BD=8D=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 兩處 import/查詢錯誤修復(統帥 E2E 預覽發現): 1. _collect_repair_stats: ApprovalRequestRecord 不存在 → 改用 IncidentRecord + outcome JSON 路徑查詢 execution_success 2. _collect_playbook_count: PlaybookRecord 不存在 → 改用 playbook_service.list_playbooks() (Redis 儲存) 修復前:修復成功率永遠 0.0%、活躍 Playbook 永遠 0 修復後:報告數字反映真實 DB/Redis 狀態 Co-Authored-By: Claude Haiku 4.5 --- .../src/services/report_generation_service.py | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/apps/api/src/services/report_generation_service.py b/apps/api/src/services/report_generation_service.py index 15b27db8..d7056485 100644 --- a/apps/api/src/services/report_generation_service.py +++ b/apps/api/src/services/report_generation_service.py @@ -218,24 +218,30 @@ class ReportGenerationService: } async def _collect_repair_stats(self, since: datetime) -> dict: - """收集自動修復統計(approval_requests 表)""" - from sqlalchemy import func, select + """ + 收集自動修復統計(IncidentRecord.outcome JSON) + + 2026-04-14 Claude Sonnet 4.6 修復 — 原本引用不存在的 ApprovalRequestRecord, + 實際 execution_success 儲存在 IncidentRecord.outcome JSON 欄位。 + """ + from sqlalchemy import func, select, text from src.db.base import get_db_context - from src.db.models import ApprovalRequestRecord + from src.db.models import IncidentRecord async with get_db_context() as db: + # PostgreSQL JSON 路徑查詢:outcome->>'execution_success' success = await db.scalar( - select(func.count()).select_from(ApprovalRequestRecord).where( - ApprovalRequestRecord.created_at >= since, - ApprovalRequestRecord.execution_success.is_(True), + select(func.count()).select_from(IncidentRecord).where( + IncidentRecord.created_at >= since, + text("outcome->>'execution_success' = 'true'"), ) ) or 0 failed = await db.scalar( - select(func.count()).select_from(ApprovalRequestRecord).where( - ApprovalRequestRecord.created_at >= since, - ApprovalRequestRecord.execution_success.is_(False), + select(func.count()).select_from(IncidentRecord).where( + IncidentRecord.created_at >= since, + text("outcome->>'execution_success' = 'false'"), ) ) or 0 @@ -257,17 +263,21 @@ class ReportGenerationService: return int(count) async def _collect_playbook_count(self) -> int: - """收集活躍 Playbook 數量""" - from sqlalchemy import func, select + """ + 收集活躍 Playbook 數量 - from src.db.base import get_db_context - from src.db.models import PlaybookRecord + 2026-04-14 Claude Sonnet 4.6 修復 — Playbook 儲存在 Redis 非 PostgreSQL, + 改用 playbook_service.list_playbooks() 讀 Redis。 + """ + from src.services.playbook_service import get_playbook_service - async with get_db_context() as db: - count = await db.scalar( - select(func.count()).select_from(PlaybookRecord) - ) or 0 - return int(count) + try: + svc = get_playbook_service() + playbooks, total = await svc.list_playbooks(limit=1000) + return int(total or len(playbooks)) + except Exception as e: + logger.warning("daily_kpi_playbook_count_failed", error=str(e)) + return 0 def format_daily_report(self, kpi: DailyKpi) -> str: """