"""V2-M1 config gate: run all config guards, fail if any fails (V2-M1E). Chains the canonical check, the Excel→JSON byte-equal check, and the three config validators. Any non-zero child exit fails the gate. Run with openpyxl available (the Excel checks need it): uv run --with openpyxl python scripts/run_config_gate.py """ from __future__ import annotations import json import subprocess import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] GATES = [ ("canonical", ["scripts/check_config_json_canonical.py"]), ("excel_json_byte_equal", ["scripts/build_config_from_excel.py", "--check"]), ("rule_pack_fk", ["scripts/validate_rule_pack_config.py"]), ("excel_json_sync", ["scripts/validate_config_excel_sync.py"]), ("query_prompts", ["scripts/validate_query_prompts_config.py"]), ] def main() -> int: results = [] failed = False for name, argv in GATES: proc = subprocess.run([sys.executable, *argv], cwd=ROOT, capture_output=True, text=True) ok = proc.returncode == 0 failed = failed or not ok results.append({"gate": name, "status": "pass" if ok else "fail", "returncode": proc.returncode}) print(json.dumps({"status": "fail" if failed else "pass", "gates": results}, ensure_ascii=False, indent=2)) return 1 if failed else 0 if __name__ == "__main__": sys.exit(main())