"""Invariant tests for result_migration_baseline_cleanup_20260620. Phase 1 (4): audit + inventory doc counts match expected baseline Phase 2 (3): baseline state is correct (88 MIG sites in 3 files) Phase 3 (3): mcp_client BC count decreased from 40 -> 32 after Batch A Phase 4 (3): mcp_client BC count decreased from 32 -> 24 after Batch B Phase 5 (3): mcp_client BC count decreased from 24 -> 16 after Batch C Phase 6 (3): mcp_client BC count decreased from 16 -> 9 after Batch D Phase 7 (3): mcp_client BC count decreased from 9 -> <=3 after Batch E """ import json import subprocess from collections import Counter from pathlib import Path import pytest AUDIT_PATH = Path("tests/artifacts/PHASE1_AUDIT_BASELINE.json") INV_MCP = Path("tests/artifacts/PHASE1_INVENTORY_mcp_client.md") INV_AI = Path("tests/artifacts/PHASE1_INVENTORY_ai_client.md") INV_RAG = Path("tests/artifacts/PHASE1_INVENTORY_rag_engine.md") MIG = {"INTERNAL_BROAD_CATCH", "INTERNAL_SILENT_SWALLOW", "INTERNAL_OPTIONAL_RETURN", "INTERNAL_RETHROW", "UNCLEAR"} EXPECTED = { "src\\mcp_client.py": (40, 5, 0, 0, 1, 46), "src\\ai_client.py": (17, 9, 0, 7, 0, 33), "src\\rag_engine.py": (5, 1, 0, 3, 0, 9), } TARGETS = ("src\\mcp_client.py", "src\\ai_client.py", "src\\rag_engine.py") def _load_audit(): return json.loads(AUDIT_PATH.read_text(encoding="utf-8")) def _audit_live(): r = subprocess.run( ["uv", "run", "python", "scripts/audit_exception_handling.py", "--include-baseline", "--json"], capture_output=True, text=True ) return json.loads(r.stdout) # ============ Phase 1 tests (4) ============ def test_phase1_audit_json_exists(): assert AUDIT_PATH.exists(), f"missing audit json at {AUDIT_PATH}" def test_phase1_inventory_docs_exist(): for p in [INV_MCP, INV_AI, INV_RAG]: assert p.exists(), f"missing inventory doc at {p}" assert p.stat().st_size > 500, f"inventory doc {p} too small" def test_phase1_total_migration_target_is_88(): data = _load_audit() files = {f["filename"]: f for f in data["files"]} total = 0 for key in EXPECTED: findings = files[key]["findings"] mig = [f for f in findings if f["category"] in MIG] total += len(mig) assert total == 88, f"expected 88 migration-target sites, got {total}" def test_phase1_per_file_site_counts(): data = _load_audit() files = {f["filename"]: f for f in data["files"]} for key, expected in EXPECTED.items(): findings = files[key]["findings"] cats = Counter(f["category"] for f in findings) bc = cats.get("INTERNAL_BROAD_CATCH", 0) ss = cats.get("INTERNAL_SILENT_SWALLOW", 0) opt = cats.get("INTERNAL_OPTIONAL_RETURN", 0) rethrow = cats.get("INTERNAL_RETHROW", 0) unclear = cats.get("UNCLEAR", 0) mig = bc + ss + opt + rethrow + unclear assert (bc, ss, opt, rethrow, unclear, mig) == expected, ( f"{key}: expected BC={expected[0]} SS={expected[1]} OPT={expected[2]} " f"RETHROW={expected[3]} UNCLEAR={expected[4]} MIG={expected[5]}, " f"got BC={bc} SS={ss} OPT={opt} RETHROW={rethrow} UNCLEAR={unclear} MIG={mig}" ) # ============ Phase 2 tests (3) ============ def test_phase2_baseline_audit_runs(): r = subprocess.run( ["uv", "run", "python", "scripts/audit_exception_handling.py", "--include-baseline", "--json"], capture_output=True, text=True ) assert r.returncode == 0, f"audit failed: {r.stderr[:500]}" data = json.loads(r.stdout) assert "files" in data assert len(data["files"]) >= 40, f"expected 40+ files, got {len(data['files'])}" def test_phase2_all_3_targets_have_migration_sites(): data = _load_audit() files = {f["filename"]: f for f in data["files"]} for target in TARGETS: assert target in files, f"missing target file: {target}" mig = [f for f in files[target]["findings"] if f["category"] in MIG] assert len(mig) > 0, f"{target} has 0 migration-target sites (expected >0)" def test_phase2_per_file_baseline_counts_match_inventory(): data = _load_audit() files = {f["filename"]: f for f in data["files"]} BASELINE = {"src\\mcp_client.py": 46, "src\\ai_client.py": 33, "src\\rag_engine.py": 9} for target, expected in BASELINE.items(): mig = [f for f in files[target]["findings"] if f["category"] in MIG] assert len(mig) == expected, ( f"{target}: baseline expected {expected}, got {len(mig)}" ) # ============ Phase 3 tests (3) ============ def test_phase3_mcp_client_broad_catch_decreased_from_40_to_32(): """Loosened: BC <= 32 to allow Phase 4+ overshoot.""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} findings = files["src\\mcp_client.py"]["findings"] bc = sum(1 for f in findings if f["category"] == "INTERNAL_BROAD_CATCH") assert bc <= 32, f"expected mcp_client BC<=32 after Phase 3, got {bc}" def test_phase3_total_migration_target_decreased_to_80(): """Loosened: total MIG <= 80.""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} total = 0 for key in TARGETS: findings = files[key]["findings"] total += sum(1 for f in findings if f["category"] in MIG) assert total <= 80, f"expected total MIG<=80 after Phase 3, got {total}" def test_phase3_audit_baseline_matches_phase1_audit_json(): data = _load_audit() files = {f["filename"]: f for f in data["files"]} total = 0 for key in TARGETS: findings = files[key]["findings"] total += sum(1 for f in findings if f["category"] in MIG) assert total == 88, f"PHASE1_AUDIT_BASELINE.json expected 88 baseline MIG, got {total}" # ============ Phase 4 tests (3) ============ def test_phase4_mcp_client_broad_catch_decreased_to_24(): """Loosened: BC <= 24.""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} findings = files["src\\mcp_client.py"]["findings"] bc = sum(1 for f in findings if f["category"] == "INTERNAL_BROAD_CATCH") assert bc <= 24, f"expected mcp_client BC<=24 after Phase 4, got {bc}" def test_phase4_total_migration_target_decreased_to_72(): """Loosened: total MIG <= 72.""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} total = 0 for key in TARGETS: findings = files[key]["findings"] total += sum(1 for f in findings if f["category"] in MIG) assert total <= 72, f"expected total MIG<=72 after Phase 4, got {total}" def test_phase4_modules_import_cleanly(): """Verify mcp_client module imports after Batch B.""" import src.mcp_client assert hasattr(src.mcp_client, "get_git_diff_result") assert hasattr(src.mcp_client, "ts_c_get_skeleton_result") # ============ Phase 5 tests (3) ============ def test_phase5_mcp_client_broad_catch_decreased_to_16(): """Loosened: BC <= 16.""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} findings = files["src\\mcp_client.py"]["findings"] bc = sum(1 for f in findings if f["category"] == "INTERNAL_BROAD_CATCH") assert bc <= 16, f"expected mcp_client BC<=16 after Phase 5, got {bc}" def test_phase5_total_migration_target_decreased_to_64(): """Loosened: total MIG <= 64.""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} total = 0 for key in TARGETS: findings = files[key]["findings"] total += sum(1 for f in findings if f["category"] in MIG) assert total <= 64, f"expected total MIG<=64 after Phase 5, got {total}" def test_phase5_modules_import_cleanly(): """Verify mcp_client module imports after Batch C.""" import src.mcp_client assert hasattr(src.mcp_client, "ts_cpp_get_definition_result") assert hasattr(src.mcp_client, "py_get_skeleton_result") assert hasattr(src.mcp_client, "py_get_code_outline_result") # ============ Phase 6 tests (3) ============ def test_phase6_mcp_client_broad_catch_decreased_to_9(): """Loosened: BC <= 9.""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} findings = files["src\\mcp_client.py"]["findings"] bc = sum(1 for f in findings if f["category"] == "INTERNAL_BROAD_CATCH") assert bc <= 9, f"expected mcp_client BC<=9 after Phase 6, got {bc}" def test_phase6_total_migration_target_decreased_to_56(): """Loosened: total MIG <= 56.""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} total = 0 for key in TARGETS: findings = files[key]["findings"] total += sum(1 for f in findings if f["category"] in MIG) assert total <= 56, f"expected total MIG<=56 after Phase 6, got {total}" def test_phase6_modules_import_cleanly(): """Verify mcp_client module imports after Batch D.""" import src.mcp_client assert hasattr(src.mcp_client, "py_get_signature_result") assert hasattr(src.mcp_client, "py_set_signature_result") assert hasattr(src.mcp_client, "py_check_syntax_result") # ============ Phase 7 tests (3) ============ def test_phase7_mcp_client_broad_catch_decreased(): """After Phase 7 Batch E, mcp_client BC <= 3 (the 3 nested helper functions).""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} findings = files["src\\mcp_client.py"]["findings"] bc = sum(1 for f in findings if f["category"] == "INTERNAL_BROAD_CATCH") assert bc <= 3, f"expected mcp_client BC<=3 after Phase 7, got {bc}" def test_phase7_total_migration_target_decreased(): """Total MIG was 56 after Phase 6; should be <= 48 after Phase 7 (8 sites migrated).""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} total = 0 for key in TARGETS: findings = files[key]["findings"] total += sum(1 for f in findings if f["category"] in MIG) assert total <= 48, f"expected total MIG<=48 after Phase 7, got {total}" def test_phase7_modules_import_cleanly(): """Verify mcp_client module imports after Phase 7 Batch E migrations.""" import src.mcp_client assert hasattr(src.mcp_client, "py_get_docstring_result") assert hasattr(src.mcp_client, "derive_code_path_result") assert hasattr(src.mcp_client, "get_tree_result") assert hasattr(src.mcp_client, "web_search_result") assert hasattr(src.mcp_client, "fetch_url_result") assert hasattr(src.mcp_client, "get_ui_performance_result") # ============ Phase 8 tests (3) ============ def test_phase8_mcp_client_silent_swallow_zero(): """Phase 8 CRITICAL anti-sliming phase: mcp_client INTERNAL_SILENT_SWALLOW = 0.""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} findings = files["src\\mcp_client.py"]["findings"] ss = sum(1 for f in findings if f["category"] == "INTERNAL_SILENT_SWALLOW") assert ss == 0, f"expected mcp_client SS=0 after Phase 8, got {ss}" def test_phase8_mcp_client_total_migration_target_zero(): """After Phase 8, mcp_client should have 0 migration-target sites (BC + SS + UNCLEAR).""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} findings = files["src\\mcp_client.py"]["findings"] mig_cats = {"INTERNAL_BROAD_CATCH", "INTERNAL_SILENT_SWALLOW", "UNCLEAR"} total = sum(1 for f in findings if f["category"] in mig_cats) assert total == 0, f"expected mcp_client migration-target=0 after Phase 8, got {total}" def test_phase8_modules_import_cleanly(): """Verify mcp_client imports after Phase 8 anti-sliming migrations.""" import src.mcp_client # New _result variants from Phase 8 are inside py_find_usages_result and # derive_code_path_result; these are integration tests, not attribute tests. assert hasattr(src.mcp_client, "py_find_usages_result") assert hasattr(src.mcp_client, "derive_code_path_result") # ============ Phase 9 tests (3) ============ def test_phase9_ai_client_broad_catch_decreased(): """After Phase 9 Batch A (8 BC sites migrated), ai_client BC <= 9 (17 - 8).""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} findings = files["src\\ai_client.py"]["findings"] bc = sum(1 for f in findings if f["category"] == "INTERNAL_BROAD_CATCH") assert bc <= 9, f"expected ai_client BC<=9 after Phase 9, got {bc}" def test_phase9_ai_client_silent_swallow_count(): """After Phase 9, ai_client INTERNAL_SILENT_SWALLOW count is recorded for Phase 11.""" data = _audit_live() files = {f["filename"]: f for f in data["files"]} findings = files["src\\ai_client.py"]["findings"] ss = sum(1 for f in findings if f["category"] == "INTERNAL_SILENT_SWALLOW") # Some sites moved from BC to SS via exception narrowing; record for Phase 11. assert ss >= 0, f"ss count check (informational): {ss}" def test_phase9_modules_import_cleanly(): """Verify ai_client imports after Batch A migrations.""" import src.ai_client assert hasattr(src.ai_client, "_classify_deepseek_error") assert hasattr(src.ai_client, "_classify_minimax_error") assert hasattr(src.ai_client, "set_provider") # ============ Phase 9 redo tests (TIER1_REVIEW, 4 sites) ============ def test_phase9_redo_ai_client_unclear_zero(): """After Phase 9 redo per TIER1_REVIEW: - L332, L355 refactored to return ErrorInfo (BOUNDARY_CONVERSION) - L394, L716, L723, L994 migrated to Result[T] UNCLEAR should be 0. """ data = _audit_live() files = {f["filename"]: f for f in data["files"]} findings = files["src\\ai_client.py"]["findings"] unclear = sum(1 for f in findings if f["category"] == "UNCLEAR") assert unclear == 0, f"expected ai_client UNCLEAR=0 after Phase 9 redo, got {unclear}" def test_phase9_redo_new_helpers_exist(): """The new _result helpers added in Phase 9 redo must exist on ai_client.""" import src.ai_client assert hasattr(src.ai_client, "_set_minimax_provider_result") assert hasattr(src.ai_client, "_parse_tool_args_result") assert hasattr(src.ai_client, "_reread_file_items_result") def test_phase9_redo_modules_import_cleanly(): """Verify ai_client imports after Phase 9 redo migrations.""" import src.ai_client # The legacy string-returning functions should still exist for backward compat. assert callable(getattr(src.ai_client, "set_provider", None)) assert callable(getattr(src.ai_client, "_reread_file_items", None))