from __future__ import annotations import argparse import json from pathlib import Path from typing import Any ROOT = Path(__file__).resolve().parents[1] DEFAULT_PATH = ROOT / "Temp" / "operational_truth_score_v1.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 main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--json", default=str(DEFAULT_PATH)) args = ap.parse_args() path = Path(args.json) if not path.is_absolute(): path = ROOT / path payload = _load(path) errors: list[str] = [] if str(payload.get("formula_id") or "") != "OPERATIONAL_TRUTH_SCORE_V1": errors.append("formula_id mismatch") score = payload.get("score_0_100") if not isinstance(score, (int, float)): errors.append("score_0_100 must be numeric") else: if score < 0 or score > 100: errors.append("score_0_100 out of range") gate = str(payload.get("gate") or "") if gate not in {"PASS_100", "BLOCK_EXECUTION", "WATCH_PENDING_SAMPLE", "DATA_CONFLICT"}: errors.append(f"gate={gate}") if not isinstance(payload.get("blocking_reasons"), list): errors.append("blocking_reasons must be list") if not isinstance(payload.get("llm_allowed_actions"), list): errors.append("llm_allowed_actions must be list") for key in ( "data_truth_score", "decision_truth_score", "execution_truth_score", "performance_readiness_score", "report_consistency_score", ): if not isinstance(payload.get(key), (int, float)): errors.append(f"{key} must be numeric") if gate == "PASS_100" and float(score or 0.0) < 100.0: errors.append("PASS_100 requires score_0_100=100") if gate != "PASS_100" and float(score or 0.0) >= 100.0: errors.append("non-PASS_100 gate cannot have score_0_100=100") if errors: print("OPERATIONAL_TRUTH_SCORE_V1_FAIL") for err in errors: print(f" {err}") return 1 print("OPERATIONAL_TRUTH_SCORE_V1_OK") print(f" score_0_100: {float(score):.2f}") print(f" gate: {gate}") return 0 if __name__ == "__main__": raise SystemExit(main())