"""Phase 11 invariant tests (GREEN). 11 SS sites migrated via 8 helpers + 1 reused helper: - _try_warm_sdk_result (sites 1+2; both classify functions) - _delete_gemini_cache_result (reused from Phase 10 for sites 3+4) - _set_tool_preset_result (site 5) - _set_bias_profile_result (site 6; also used by site 11) - _extract_gemini_thoughts_result (site 7) - _list_minimax_models_result (site 8) - _count_gemini_tokens_for_stats_result (sites 9+10) - _set_tool_preset_result (site 11; reused from site 5) """ import sys sys.path.insert(0, ".") def test_phase11_ai_client_ss_count_zero(): """After Phase 11: ai_client SS count is 0 (was 11).""" import json import subprocess r = subprocess.run( ["uv", "run", "python", "scripts/audit_exception_handling.py", "--include-baseline", "--json"], capture_output=True, text=True ) data = json.loads(r.stdout) files = {f["filename"]: f for f in data["files"]} ai = files["src\\ai_client.py"] ss = sum(1 for x in ai["findings"] if x["category"] == "INTERNAL_SILENT_SWALLOW") assert ss == 0, f"expected ai_client SS=0 after Phase 11, got {ss}" def test_phase11_ai_client_unclear_count_zero(): """After Phase 11: ai_client UNCLEAR count is 0.""" import json import subprocess r = subprocess.run( ["uv", "run", "python", "scripts/audit_exception_handling.py", "--include-baseline", "--json"], capture_output=True, text=True ) data = json.loads(r.stdout) files = {f["filename"]: f for f in data["files"]} ai = files["src\\ai_client.py"] unclear = sum(1 for x in ai["findings"] if x["category"] == "UNCLEAR") assert unclear == 0, f"expected ai_client UNCLEAR=0 after Phase 11, got {unclear}" def test_phase11_all_helpers_exist(): """All 7 new _result helpers must exist on ai_client.""" import src.ai_client expected = [ "_try_warm_sdk_result", "_set_tool_preset_result", "_set_bias_profile_result", "_extract_gemini_thoughts_result", "_list_minimax_models_result", "_count_gemini_tokens_for_stats_result", ] for name in expected: assert hasattr(src.ai_client, name), f"{name} helper missing" def test_phase11_legacy_functions_preserved(): """All legacy functions must still be callable (some OBLITERATED by cruft-removal Phase 4).""" import src.ai_client legacy = [ "_classify_anthropic_error", "_classify_gemini_error", "cleanup", "reset_session", "set_tool_preset", "set_bias_profile", "get_token_stats", ] # OBLITERATED by cruft-removal Phase 4 (no backward compat): obliterated = ["_extract_gemini_thoughts", "_list_minimax_models"] for name in legacy: assert hasattr(src.ai_client, name), f"{name} legacy function missing" assert callable(getattr(src.ai_client, name)), f"{name} not callable" for name in obliterated: assert not hasattr(src.ai_client, name), ( f"{name} wrapper must be OBLITERATED (cruft-removal Phase 4); " f"callers must use {name}_result directly" )