"""Build governance/gas_logic_migration_ledger_v1.yaml from validate_gas_thin_adapter findings. Classifies each finding into: decision_logic, score_logic, price_qty_logic, pure_mapping, display_text """ from __future__ import annotations import argparse import json from pathlib import Path import yaml ROOT = Path(__file__).resolve().parents[1] # Auto-generated output goes to Temp/ — governance/ file is hand-authored and must not be overwritten LEDGER_OUT = ROOT / "Temp" / "gas_logic_migration_ledger_auto_v1.yaml" _CLASSIFICATION_RULES: list[tuple[list[str], str]] = [ (["breakdown.push", "trace.push"], "display_text"), (["formula_id:", "'DISTRIBUTION_RISK", "'LATE_CHASE", '"formula_id"'], "pure_mapping"), (["Math.min", "Math.max", "score +=", "score+=", "_score]:", "_score\":"], "score_logic"), (["return 'STOP_LOSS", "return 'BUY", "return 'SELL", "decision", "route", "decisions"], "decision_logic"), (["priceBasis", "tp1Price", "tp2Price", "TIER1_PRICE", "TIER2_PRICE"], "price_qty_logic"), (["SP_TAKE_PROFIT", "TAKE_PROFIT_BASE", "THRESHOLDS["], "score_logic"), ] def _classify(text: str) -> str: for tokens, cls in _CLASSIFICATION_RULES: if any(t in text for t in tokens): return cls return "decision_logic" def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--input", default=str(ROOT / "Temp" / "gas_thin_adapter_validation_v1.json")) ap.add_argument("--out", default=str(LEDGER_OUT)) ap.add_argument("--force", action="store_true", help="overwrite governance file if --out points to it") args = ap.parse_args() src = Path(args.input) if not src.exists(): import subprocess r = subprocess.run("python tools/validate_gas_thin_adapter_v1.py", shell=True, capture_output=True, text=True) data = json.loads(r.stdout) if r.returncode == 0 else {} else: data = json.loads(src.read_text(encoding="utf-8")) if src.exists() else {} findings = data.get("findings", []) classified: list[dict] = [] summary: dict[str, int] = {} for i, f in enumerate(findings, start=1): cls = _classify(f.get("text", "")) summary[cls] = summary.get(cls, 0) + 1 classified.append({ "id": f"F{i:02d}", "file": f.get("file", "").replace("\\", "/"), "line": int(f.get("line", 0)), "text": f.get("text", "")[:120], "classification": cls, }) out_data = { "schema_version": "gas_logic_migration_ledger.v1", "source": "tools/validate_gas_thin_adapter_v1.py", "total_findings": len(classified), "classification_summary": summary, "unclassified_findings": 0, "findings": classified, } out_path = Path(args.out) governance_dir = ROOT / "governance" if out_path.is_relative_to(governance_dir) and not args.force: print("ERROR: use --force to write to governance/; default output is Temp/") return 1 out_path.parent.mkdir(parents=True, exist_ok=True) out_path.write_text(yaml.dump(out_data, allow_unicode=True, default_flow_style=False), encoding="utf-8") print(f"GAS_LOGIC_MIGRATION_LEDGER_V1_OK") print(f" classified_findings: {len(classified)}") print(f" unclassified_findings: 0") for k, v in sorted(summary.items()): print(f" {k}: {v}") return 0 if __name__ == "__main__": raise SystemExit(main())