From 4018548552e1abdc4832806a7ce369e02382f482 Mon Sep 17 00:00:00 2001 From: ogt Date: Thu, 9 Jul 2026 17:27:08 +0800 Subject: [PATCH] fix(km): backfill symptoms hash read column --- apps/api/src/db/base.py | 13 +++++++++++-- .../tests/test_knowledge_repository_read_model.py | 2 +- apps/api/tests/test_runtime_bootstrap_guards.py | 13 +++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/apps/api/src/db/base.py b/apps/api/src/db/base.py index 1d24bb615..c4ee50da9 100644 --- a/apps/api/src/db/base.py +++ b/apps/api/src/db/base.py @@ -19,7 +19,8 @@ from contextlib import asynccontextmanager from fastapi import HTTPException from sqlalchemy import text -from sqlalchemy.exc import DBAPIError, TimeoutError as SQLAlchemyTimeoutError +from sqlalchemy.exc import DBAPIError +from sqlalchemy.exc import TimeoutError as SQLAlchemyTimeoutError from sqlalchemy.ext.asyncio import ( AsyncConnection, AsyncEngine, @@ -450,12 +451,15 @@ async def _run_init_db_ddl(conn: AsyncConnection) -> None: # 2026-04-29 ogt + Claude Opus 4.7: M4 KMWriter 反查鏈 + 冪等補欄 # CD #1115-1117 全 failure 根因:commit c22e5f33 加 ORM 欄位但無對應 ALTER # 錯誤:column "related_approval_id" of relation "knowledge_entries" does not exist + # 2026-07-09 Codex: 舊 prod schema 也可能缺 symptoms_hash,會讓 KM list/search + # 只剩 source-backed fallback;同一段補齊,避免正式 KM 看似歸零。 # 補防禦性 ALTER(同 timeline_events 模式)+ 對應 index await conn.execute( text(""" ALTER TABLE knowledge_entries ADD COLUMN IF NOT EXISTS related_approval_id VARCHAR(64), - ADD COLUMN IF NOT EXISTS path_type VARCHAR(50); + ADD COLUMN IF NOT EXISTS path_type VARCHAR(50), + ADD COLUMN IF NOT EXISTS symptoms_hash VARCHAR; """) ) # M3 冪等 unique index (incident_id + path_type) @@ -470,6 +474,11 @@ async def _run_init_db_ddl(conn: AsyncConnection) -> None: "ON knowledge_entries(related_approval_id) " "WHERE related_approval_id IS NOT NULL;" )) + await conn.execute(text( + "CREATE INDEX IF NOT EXISTS ix_knowledge_symptoms_hash " + "ON knowledge_entries(symptoms_hash) " + "WHERE symptoms_hash IS NOT NULL;" + )) # W2 PR-L1 2026-04-28 ogt + Claude Sonnet 4.6: KM→Playbook 互饋回路(飛輪 C3 修復) # PlaybookRecord 新增 review_required 欄位 diff --git a/apps/api/tests/test_knowledge_repository_read_model.py b/apps/api/tests/test_knowledge_repository_read_model.py index 6ae75bde4..6f0053f01 100644 --- a/apps/api/tests/test_knowledge_repository_read_model.py +++ b/apps/api/tests/test_knowledge_repository_read_model.py @@ -9,8 +9,8 @@ from sqlalchemy.dialects import postgresql from src.db.models import KnowledgeEntryRecord from src.models.knowledge import EntrySource, EntryStatus, EntryType from src.repositories.knowledge_repository import ( - KnowledgeDBRepository, _ASSET_TAXONOMY_KEYS, + KnowledgeDBRepository, _enum_text, ) diff --git a/apps/api/tests/test_runtime_bootstrap_guards.py b/apps/api/tests/test_runtime_bootstrap_guards.py index 317824ae3..8d1723747 100644 --- a/apps/api/tests/test_runtime_bootstrap_guards.py +++ b/apps/api/tests/test_runtime_bootstrap_guards.py @@ -255,3 +255,16 @@ def test_api_lifespan_closes_worker_redis_pool_after_signal_worker() -> None: assert "close_worker_redis_pool" in source assert source.index("close_signal_worker") < source.index("close_worker_redis_pool") assert source.index("close_worker_redis_pool") < source.index("close_redis_pool") + + +def test_init_db_backfills_all_optional_knowledge_read_columns() -> None: + import inspect + + from src.db import base as db_base + + source = inspect.getsource(db_base._run_init_db_ddl) + assert "ALTER TABLE knowledge_entries" in source + assert "ADD COLUMN IF NOT EXISTS related_approval_id" in source + assert "ADD COLUMN IF NOT EXISTS path_type" in source + assert "ADD COLUMN IF NOT EXISTS symptoms_hash" in source + assert "CREATE INDEX IF NOT EXISTS ix_knowledge_symptoms_hash" in source