from __future__ import annotations import argparse from pathlib import Path from typing import Any import yaml ROOT = Path(__file__).resolve().parents[1] DEFAULT_CONTRACT = ROOT / "spec" / "21_harness_governance_contract.yaml" def load_yaml(path: Path) -> dict[str, Any]: payload = yaml.safe_load(path.read_text(encoding="utf-8")) return payload if isinstance(payload, dict) else {} def main() -> int: parser = argparse.ArgumentParser(description="Validate harness governance contract presence and required files.") parser.add_argument("--contract", default=str(DEFAULT_CONTRACT)) args = parser.parse_args() contract_path = Path(args.contract) if not contract_path.is_absolute(): contract_path = ROOT / contract_path if not contract_path.exists(): print("HARNESS_GOVERNANCE_FAIL: contract missing") return 1 c = load_yaml(contract_path) errors: list[str] = [] governance = c.get("governance") if isinstance(c.get("governance"), dict) else {} layers = governance.get("required_layers") if isinstance(governance.get("required_layers"), list) else [] if not layers: errors.append("required_layers missing") for layer in layers: if not isinstance(layer, dict): errors.append("layer must be object") continue for key in ("required_files", "required_validators", "required_runners"): vals = layer.get(key) if isinstance(vals, list): for rel in vals: p = ROOT / str(rel) if not p.exists(): errors.append(f"missing required path: {rel}") if errors: print("HARNESS_GOVERNANCE_FAIL") for e in errors: print(f"- {e}") return 1 print("HARNESS_GOVERNANCE_OK") return 0 if __name__ == "__main__": raise SystemExit(main())