diff --git a/apps/api/src/jobs/coverage_evaluator_job.py b/apps/api/src/jobs/coverage_evaluator_job.py index 4d6c749e..6a18ddec 100644 --- a/apps/api/src/jobs/coverage_evaluator_job.py +++ b/apps/api/src/jobs/coverage_evaluator_job.py @@ -27,7 +27,6 @@ from __future__ import annotations import asyncio import json as _json import time as _time -from typing import Any import httpx import structlog @@ -253,27 +252,29 @@ async def _evaluate_alerting(run_id: str) -> int: async def _evaluate_km_coverage(run_id: str) -> int: """ asset 有對應 knowledge_entries → green - 粗略: k8s_workload 看 app/namespace 是否有出現在 knowledge_entries.body. + + 2026-04-19 ogt + Claude Opus 4.7 v2 bug fix: knowledge_entries 欄位是 'content', + 不是 'body' (前次 UndefinedColumnError). 同時加 title 匹配擴大覆蓋. """ from sqlalchemy import text as _sql from src.db.base import get_db_context try: async with get_db_context() as db: - # 簡化: 只看 k8s_workload 是否有 app:name 字樣出現在 KM 裡 result = await db.execute( _sql(""" UPDATE asset_coverage_snapshot cs SET coverage_status = CASE WHEN ai.asset_type = 'k8s_workload' AND EXISTS ( SELECT 1 FROM knowledge_entries ke - WHERE ke.body ILIKE '%' || ai.name || '%' + WHERE ke.content ILIKE '%' || ai.name || '%' + OR ke.title ILIKE '%' || ai.name || '%' ) THEN 'green' WHEN ai.asset_type = 'k8s_workload' THEN 'yellow' ELSE cs.coverage_status END, evidence = jsonb_build_object( - 'source', 'knowledge_entries_substring_match', + 'source', 'knowledge_entries_content_or_title_match', 'asset_name', ai.name ) FROM asset_inventory ai