Files
QuantEngineByItz/tools/validate_golden_coverage_100.py
T
kjh2064 ee3e799de1 feat: 리밸런싱 엔진 V1 + GAS 버그 수정 (2026-06-13)
주요 변경:
- tools/build_rebalance_engine_v1.py: REBALANCE_ENGINE_V1 신규
  * account_snapshot 직접 합산(_build_snap_position_map) → 소수주 분리 행 병합
  * 레짐 소스 macro.REGIME_PRELIM 최우선 (GAS 와 동일)
- src/gas_adapter_parts/gdf_06_rebalance.gs: runRebalanceSheet_() 신규
  * Logger.log / getSpreadsheet_() 로 run_all 연동 수정
- src/gas_adapter_parts/gdc_01_fetch_fundamentals.gs
  * _mergePositionRecord_(): 소수주 중복 행 합산 신규
  * parseInt → parseFloat (qty, availQty)
- src/gas_adapter_parts/gdf_01_price_metrics.gs
  * 미보유 종목 SELL_READY → WATCH_EXIT_SIGNAL
- spec/41_release_dag.yaml: build_rebalance_sheet 노드 추가 (step_count 63)
- spec/51_formula_lifecycle_registry.yaml: REBALANCE_ENGINE_V1 등록

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 13:20:14 +09:00

141 lines
4.5 KiB
Python

"""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())