fix(km): backfill symptoms hash read column
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 1m7s
CD Pipeline / build-and-deploy (push) Successful in 4m50s
CD Pipeline / post-deploy-checks (push) Successful in 3m37s
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 1m7s
CD Pipeline / build-and-deploy (push) Successful in 4m50s
CD Pipeline / post-deploy-checks (push) Successful in 3m37s
This commit is contained in:
@@ -19,7 +19,8 @@ from contextlib import asynccontextmanager
|
|||||||
|
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
from sqlalchemy import text
|
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 (
|
from sqlalchemy.ext.asyncio import (
|
||||||
AsyncConnection,
|
AsyncConnection,
|
||||||
AsyncEngine,
|
AsyncEngine,
|
||||||
@@ -450,12 +451,15 @@ async def _run_init_db_ddl(conn: AsyncConnection) -> None:
|
|||||||
# 2026-04-29 ogt + Claude Opus 4.7: M4 KMWriter 反查鏈 + 冪等補欄
|
# 2026-04-29 ogt + Claude Opus 4.7: M4 KMWriter 反查鏈 + 冪等補欄
|
||||||
# CD #1115-1117 全 failure 根因:commit c22e5f33 加 ORM 欄位但無對應 ALTER
|
# CD #1115-1117 全 failure 根因:commit c22e5f33 加 ORM 欄位但無對應 ALTER
|
||||||
# 錯誤:column "related_approval_id" of relation "knowledge_entries" does not exist
|
# 錯誤: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
|
# 補防禦性 ALTER(同 timeline_events 模式)+ 對應 index
|
||||||
await conn.execute(
|
await conn.execute(
|
||||||
text("""
|
text("""
|
||||||
ALTER TABLE knowledge_entries
|
ALTER TABLE knowledge_entries
|
||||||
ADD COLUMN IF NOT EXISTS related_approval_id VARCHAR(64),
|
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)
|
# 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) "
|
"ON knowledge_entries(related_approval_id) "
|
||||||
"WHERE related_approval_id IS NOT NULL;"
|
"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 修復)
|
# W2 PR-L1 2026-04-28 ogt + Claude Sonnet 4.6: KM→Playbook 互饋回路(飛輪 C3 修復)
|
||||||
# PlaybookRecord 新增 review_required 欄位
|
# PlaybookRecord 新增 review_required 欄位
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ from sqlalchemy.dialects import postgresql
|
|||||||
from src.db.models import KnowledgeEntryRecord
|
from src.db.models import KnowledgeEntryRecord
|
||||||
from src.models.knowledge import EntrySource, EntryStatus, EntryType
|
from src.models.knowledge import EntrySource, EntryStatus, EntryType
|
||||||
from src.repositories.knowledge_repository import (
|
from src.repositories.knowledge_repository import (
|
||||||
KnowledgeDBRepository,
|
|
||||||
_ASSET_TAXONOMY_KEYS,
|
_ASSET_TAXONOMY_KEYS,
|
||||||
|
KnowledgeDBRepository,
|
||||||
_enum_text,
|
_enum_text,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -255,3 +255,16 @@ def test_api_lifespan_closes_worker_redis_pool_after_signal_worker() -> None:
|
|||||||
assert "close_worker_redis_pool" in source
|
assert "close_worker_redis_pool" in source
|
||||||
assert source.index("close_signal_worker") < source.index("close_worker_redis_pool")
|
assert source.index("close_signal_worker") < source.index("close_worker_redis_pool")
|
||||||
assert source.index("close_worker_redis_pool") < source.index("close_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
|
||||||
|
|||||||
Reference in New Issue
Block a user