"""build_final_execution_decision_v4.py — FINAL_EXECUTION_DECISION_V4 P0-004: 하위 엔진 execution_allowed를 child_engine_internal_allowed로 명시적 분리. global_execution_gate != HTS_READY이면 buy/sell/hts_order_count를 강제 0으로 잠금. LLM이 "child_engine_internal_allowed=true"를 HTS 실행 허가로 오독하는 경로를 차단한다. """ from __future__ import annotations import argparse import hashlib import json from datetime import datetime, timezone from pathlib import Path from typing import Any ROOT = Path(__file__).resolve().parents[1] DEFAULT_JSON = ROOT / "GatherTradingData.json" DEFAULT_TRUTH = ROOT / "Temp" / "operational_truth_score_v1.json" DEFAULT_FJ = ROOT / "Temp" / "final_judgment_gate_v1.json" DEFAULT_SCR = ( ROOT / "Temp" / "smart_cash_recovery_v7.json" if (ROOT / "Temp" / "smart_cash_recovery_v7.json").exists() else ROOT / "Temp" / "smart_cash_recovery_v6.json" ) DEFAULT_HARDENING = ROOT / "Temp" / "strategy_hardening_harness_v2.json" DEFAULT_MATRIX = ROOT / "Temp" / "execution_readiness_matrix_v1.json" DEFAULT_OUT = ROOT / "Temp" / "final_execution_decision_v4.json" def _load(path: Path) -> dict[str, Any]: if not path.exists(): return {} try: obj = json.loads(path.read_text(encoding="utf-8")) except Exception: return {} return obj if isinstance(obj, dict) else {} def _f(v: Any, default: float = 0.0) -> float: try: return float(v) except Exception: return default def _rows(v: Any) -> list[dict[str, Any]]: if isinstance(v, list): return [x for x in v if isinstance(x, dict)] if isinstance(v, str): try: return _rows(json.loads(v)) except Exception: return [] return [] def _extract_harness(payload: dict[str, Any]) -> dict[str, Any]: data = payload.get("data") if isinstance(data, dict): h = data.get("_harness_context") if isinstance(h, dict): return h h_apex = payload.get("hApex") if isinstance(h_apex, dict): return h_apex return {} import sys if sys.stdout.encoding and sys.stdout.encoding.lower() not in ("utf-8", "utf8"): sys.stdout = open(sys.stdout.fileno(), mode="w", encoding="utf-8", buffering=1) def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--json", default=str(DEFAULT_JSON)) ap.add_argument("--truth", default=str(DEFAULT_TRUTH)) ap.add_argument("--fj", default=str(DEFAULT_FJ)) ap.add_argument("--scr", default=str(DEFAULT_SCR)) ap.add_argument("--hardening", default=str(DEFAULT_HARDENING)) ap.add_argument("--matrix", default=str(DEFAULT_MATRIX)) ap.add_argument("--out", default=str(DEFAULT_OUT)) args = ap.parse_args() def rp(s: str) -> Path: p = Path(s) return p if p.is_absolute() else ROOT / p json_path = rp(args.json) hctx = _extract_harness(_load(json_path)) truth = _load(rp(args.truth)) fj = _load(rp(args.fj)) scr = _load(rp(args.scr)) or _load(ROOT / "Temp" / "smart_cash_recovery_v5.json") hardening = _load(rp(args.hardening)) matrix = _load(rp(args.matrix)) # ── 판단 기반 수집 ──────────────────────────────────────────────────────────── truth_gate = str(truth.get("gate") or "MISSING") truth_score = _f(truth.get("score_0_100")) fj_gate = str(fj.get("gate") or "MISSING") fj_coverage = _f(fj.get("coverage_pct")) # child engine: smart cash recovery — execution_allowed → child_engine_internal_allowed scr_child_internal_allowed = bool(scr.get("execution_allowed")) scr_status = str(scr.get("status") or "UNKNOWN") scr_damage = _f(scr.get("value_damage_pct_avg")) hard_meta = hardening.get("meta_scores") if isinstance(hardening.get("meta_scores"), dict) else {} readiness_gate = str(hard_meta.get("readiness_gate") or "MISSING") matrix_gate = str(matrix.get("gate") or "MISSING") matrix_min = _f(matrix.get("min_axis_score")) order_rows = _rows(hctx.get("order_blueprint_json")) hts_candidate_rows = [r for r in order_rows if str(r.get("validation_status") or "").upper() == "PASS"] # ── 차단 이유 수집 ──────────────────────────────────────────────────────────── blocking: list[str] = [] if truth_gate != "PASS_100": blocking.append(f"TRUTH_GATE={truth_gate}") if truth_score < 100.0: blocking.append(f"TRUTH_SCORE={truth_score:.2f}") if not scr_child_internal_allowed or scr_status != "PASS": blocking.append("SMART_CASH_BLOCKED") if scr_damage > 10.0: blocking.append("VALUE_DAMAGE_GT_10") if readiness_gate != "PERFORMANCE_READY": blocking.append(f"READINESS_GATE={readiness_gate}") if matrix_gate != "PASS_100" or matrix_min < 100.0: blocking.append(f"EXECUTION_READINESS_MATRIX={matrix_gate}:{matrix_min:.2f}") # ── 전역 게이트 결정 (P0-004 핵심: 하위 엔진 허용 ≠ HTS 허용) ────────────── if not blocking and len(hts_candidate_rows) > 0: global_gate = "HTS_READY" buy_allowed = True sell_allowed = True hts_order_count = len(hts_candidate_rows) child_execution_state = "HTS_AUTHORIZED" llm_actions = ["HTS_READY"] else: global_gate = "AUDIT_ONLY" buy_allowed = False sell_allowed = False hts_order_count = 0 # global gate != HTS_READY → 반드시 0 child_execution_state = "THEORETICAL_ONLY" # 명시적: child 허용 ≠ HTS 허용 llm_actions = ["AUDIT_ONLY", "RENDER_LEDGER_ONLY", "SHADOW_LEDGER_ONLY"] result = { "formula_id": "FINAL_EXECUTION_DECISION_V4", "global_execution_gate": global_gate, "buy_allowed": buy_allowed, "sell_allowed": sell_allowed, "hts_order_count": hts_order_count, # P0-004 핵심: child_engine_internal_allowed는 HTS 실행 허가가 아님을 명시 "child_engine_internal_allowed": scr_child_internal_allowed, "child_execution_state": child_execution_state, "precedence_note": ( "child_engine_internal_allowed=True는 현금회복 계산이 내부적으로 허용됨을 의미한다. " "HTS 주문 실행은 global_execution_gate==HTS_READY일 때만 허용된다." ), "reason_codes": blocking, "llm_allowed_actions": llm_actions, "decision_basis": { "truth_gate": truth_gate, "truth_score_0_100": truth_score, "final_judgment_gate": fj_gate, "final_judgment_coverage_pct": fj_coverage, "smart_cash_recovery_status": scr_status, "smart_cash_recovery_child_engine_internal_allowed": scr_child_internal_allowed, "smart_cash_recovery_value_damage_pct": scr_damage, "readiness_gate": readiness_gate, "execution_readiness_matrix_gate": matrix_gate, "execution_readiness_min_axis_score": matrix_min, "hts_candidate_rows": len(hts_candidate_rows), }, "generated_at": datetime.now(timezone.utc).isoformat(), "input_hash": hashlib.sha256(json_path.read_bytes()).hexdigest(), } out = rp(args.out) out.parent.mkdir(parents=True, exist_ok=True) out.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8") print(json.dumps(result, ensure_ascii=False, indent=2)) return 0 if __name__ == "__main__": raise SystemExit(main())