"""validate_golden_coverage_100.py — P1-016 Golden Case Coverage Acceptance Test formula_golden_cases_v4.yaml(및 이전 버전)까지 포함해 golden_coverage_ratio가 목표치를 초과하는지 검증. 수락 기준: - golden_coverage_ratio >= 0.95 (95%+): PASS - decision_critical_min_cases >= 3: PASS for all 28 decision-critical formulas Exit: 0 = PASS (목표 커버리지 달성) 1 = FAIL (커버리지 미달 또는 decision-critical 케이스 부족) """ from __future__ import annotations import json import subprocess import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] COVERAGE_JSON = ROOT / "Temp" / "yaml_code_coverage_v1.json" COVERAGE_TARGET = 0.95 DECISION_CRITICAL = { "STOP_BREACH_V1", "SMART_CASH_RECOVERY_V4", "SMART_CASH_RECOVERY_V7", "ANTI_LATE_ENTRY_PULLBACK_GATE_V4", "REGIME_CONDITIONAL_MACRO_FACTOR_V1", "MACRO_REGIME_ALIGNMENT_GATE_V2", "DISTRIBUTION_EXIT_PRESIGNAL_V2", "SELL_EXECUTION_TIMING_LOCK_V2", "SELL_EXECUTION_QUALITY_GATE_V1", "PORTFOLIO_HEALTH_V1", "INDEX_RELATIVE_HEALTH_GATE_V1", "CASH_RAISE_PARETO_EXECUTOR_V2", "CASH_RAISE_VALUE_OPTIMIZER_V3", "CASH_RECOVERY_OPTIMIZER_V4", "CASH_RECOVERY_V1", "DATA_MATURITY_TRUTH_GATE_V1", "DATA_MATURITY_TRUTH_GATE_VALIDATOR_V1", "DATA_QUALITY_GATE_V2_PY", "DATA_QUALITY_GATE_V3", "IMPUTED_DATA_EXPOSURE_GATE_V2", "OPERATIONAL_ALPHA_CALIBRATION_V2", "PREDICTIVE_ALPHA_DIALECTIC_ENGINE_V1_BRIDGE", "REBOUND_SELL_EFFICIENCY_V1", "SELL_ENGINE_AUDIT_V1", "SELL_SLIPPAGE_BUDGET_FACTOR_V1", "ENTRY_TIMING_DECILE_FACTOR_V1", "DYNAMIC_VALUE_PRESERVATION_SELL_V3_BRIDGE", "ARTIFACT_FRESHNESS_GATE_V1", } MIN_CASES_PER_CRITICAL = 3 def _rebuild_coverage() -> dict: """coverage JSON이 없으면 빌더를 실행해 갱신.""" if not COVERAGE_JSON.exists(): subprocess.run( [sys.executable, str(ROOT / "tools" / "build_yaml_code_coverage_v1.py")], check=True, ) with COVERAGE_JSON.open(encoding="utf-8") as fh: return json.load(fh) def _count_cases_per_formula() -> dict[str, int]: """golden_cases_v2/v3/v4 에서 formula_id별 케이스 수 집계.""" import yaml # type: ignore spec_dir = ROOT / "spec" files = [ spec_dir / "formula_golden_cases_v2.yaml", spec_dir / "formula_golden_cases_v3.yaml", spec_dir / "formula_golden_cases_v4.yaml", ] counts: dict[str, int] = {} for f in files: if not f.exists(): continue try: doc = yaml.safe_load(f.read_text(encoding="utf-8")) or {} except Exception: continue for entry in doc.get("golden_cases", []): fid = entry.get("formula_id") if fid: counts[fid] = counts.get(fid, 0) + 1 return counts def main() -> int: cov = _rebuild_coverage() ratio = cov.get("golden_coverage_ratio", 0.0) total = cov.get("yaml_formula_count", 0) golden = cov.get("golden_test_count", 0) uncovered = cov.get("golden_uncovered_rules", []) case_counts = _count_cases_per_formula() critical_missing: list[str] = [] for fid in DECISION_CRITICAL: if case_counts.get(fid, 0) < MIN_CASES_PER_CRITICAL: critical_missing.append(fid) ok_ratio = ratio >= COVERAGE_TARGET ok_critical = len(critical_missing) == 0 print(f"[GOLDEN_COVERAGE_100] total={total} golden={golden} ratio={ratio:.4f} " f"({'≥' if ok_ratio else '<'}{COVERAGE_TARGET}) " f"critical_missing={len(critical_missing)}") if critical_missing: print(f" [WARN] decision-critical with <{MIN_CASES_PER_CRITICAL} cases:") for fid in critical_missing: print(f" - {fid}: {case_counts.get(fid, 0)} case(s)") if uncovered: print(f" [WARN] still uncovered ({len(uncovered)}): " + ", ".join(uncovered[:20]) + ("..." if len(uncovered) > 20 else "")) if ok_ratio and ok_critical: print(" [PASS] golden_coverage_ratio >= 95% and all decision-critical formulas covered") return 0 else: issues = [] if not ok_ratio: issues.append(f"golden_coverage_ratio={ratio:.4f} < {COVERAGE_TARGET}") if not ok_critical: issues.append(f"{len(critical_missing)} critical formula(s) have <{MIN_CASES_PER_CRITICAL} cases") print(f" [FAIL] {'; '.join(issues)}") return 1 if __name__ == "__main__": raise SystemExit(main())