diff --git a/docs/memory/claude_inventory_validation_20260513.md b/docs/memory/claude_inventory_validation_20260513.md index ed255aa..93ed3cf 100644 --- a/docs/memory/claude_inventory_validation_20260513.md +++ b/docs/memory/claude_inventory_validation_20260513.md @@ -52,7 +52,7 @@ - V2 BLOCKED migration 守門已補:`031-037` 必須存在且 group/world-readable,`database/momo.db` / `momo_data.db` / `momo_database.db` 迷惑檔不得回來。 - `host_health_probes.chk_host_label_029` 不一致已有 migration 033 修補並補測試:必須重建 CHECK,且接受 `GCP-SSD`、`GCP-SSD-2`、`111 備援` 與兩個 110 Nginx proxy runtime labels。 - `rag_query_log` / `learning_episodes` 缺 `embedding_signature` 已由 migration 034、ORM 欄位、RAG/learning 寫入路徑與 migration metadata 測試覆蓋。 -- `incidents` 雙欄相容與 `action_plans` source/status guardrails 已在 migration 036/037 與 `tests/test_auto_heal_safety.py` 覆蓋。 +- `incidents` 雙欄相容與 `action_plans` source/status guardrails 已在 migration 036/037、migration metadata 測試與 `tests/test_auto_heal_safety.py` 覆蓋。 - `services/agent_actions.py` 不是死碼:`services/event_router.py` 透過 `SAFE_ACTIONS` registry 動態執行 ADR-012 L2 actions,`tests/test_agent_actions.py` 與 `tests/test_event_router.py` 已覆蓋並通過。 ## 不可盲動 diff --git a/tests/test_migration_metadata_coverage.py b/tests/test_migration_metadata_coverage.py index 0daed15..d93c5ea 100644 --- a/tests/test_migration_metadata_coverage.py +++ b/tests/test_migration_metadata_coverage.py @@ -81,6 +81,44 @@ def test_rag_embedding_signature_migration_covers_query_and_learning_tables(): assert snippet in migration +def test_incidents_dual_column_migration_backfills_legacy_and_current_columns(): + migration = (ROOT / "migrations" / "036_normalize_incidents_dual_columns.sql").read_text(encoding="utf-8") + + expected_snippets = [ + "ADD COLUMN IF NOT EXISTS error_traceback TEXT", + "ADD COLUMN IF NOT EXISTS traceback_str TEXT", + "ADD COLUMN IF NOT EXISTS playbook_id INTEGER", + "ADD COLUMN IF NOT EXISTS matched_playbook_id INTEGER", + "SET traceback_str = error_traceback", + "SET error_traceback = traceback_str", + "SET matched_playbook_id = playbook_id", + "SET playbook_id = matched_playbook_id", + "incidents_playbook_id_fkey", + "incidents_matched_playbook_id_fkey", + ] + for snippet in expected_snippets: + assert snippet in migration + + +def test_action_plans_guardrail_migration_keeps_source_and_status_checks(): + migration = (ROOT / "migrations" / "037_add_action_plans_guardrails.sql").read_text(encoding="utf-8") + + expected_constraints = [ + "chk_action_plans_source_marker", + "chk_action_plans_action_type", + "chk_action_plans_created_by", + "chk_action_plans_status", + ] + for constraint in expected_constraints: + assert constraint in migration + + assert "CHECK (action_type IS NOT NULL OR created_by IS NOT NULL)" in migration + assert "'code_review_fix'" in migration + assert "'openclaw_recommendation'" in migration + assert "'pending_review'" in migration + assert migration.count("NOT VALID") >= 4 + + def test_legacy_zero_byte_database_decoys_do_not_return(): for filename in ["momo.db", "momo_data.db", "momo_database.db"]: assert not (ROOT / "database" / filename).exists()