#!/usr/bin/env python3 """Validate the generated Web parity matrix without changing its claims.""" from __future__ import annotations import argparse import json from pathlib import Path def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--matrix", type=Path, required=True) parser.add_argument("--workbench-inventory", type=Path, required=True) parser.add_argument("--object-inventory", type=Path, required=True) parser.add_argument("--format-api-inventory", type=Path, required=True) parser.add_argument("--output", type=Path, required=True) args = parser.parse_args() matrix = json.loads(args.matrix.read_text(encoding="utf-8")) workbenches = json.loads(args.workbench_inventory.read_text(encoding="utf-8"))["modules"] objects = json.loads(args.object_inventory.read_text(encoding="utf-8"))["objects"] format_api = json.loads(args.format_api_inventory.read_text(encoding="utf-8")) allowed = set(matrix["status_values"]) rows = matrix["rows"] module_names = [str(row["module"]) for row in rows] errors: list[str] = [] if len(rows) != len(workbenches): errors.append(f"row count {len(rows)} != workbench count {len(workbenches)}") if len(set(module_names)) != len(module_names): errors.append("duplicate module key") if any(row["web_status"] not in allowed for row in rows): errors.append("invalid web status") if any(not row["source_evidence"] or not row["regression_entry"] for row in rows): errors.append("missing source evidence or regression entry") object_modules = {str(item["module"]) for item in objects} format_modules = {str(item["module"]) for item in format_api["formats"]} for row in rows: module = str(row["module"]) if row["object_type_count"] and module not in object_modules: errors.append(f"object count has no source module: {module}") if row["format_extensions"] and module not in format_modules: errors.append(f"format count has no source module: {module}") report = { "schema": "freecad-web-parity-matrix-gate/v1", "matrix": str(args.matrix), "module_count": len(rows), "pending_count": sum(row["web_status"] == "pending" for row in rows), "errors": errors, "result": "pass" if not errors else "fail", } args.output.parent.mkdir(parents=True, exist_ok=True) args.output.write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") print(json.dumps(report)) return 0 if not errors else 1 if __name__ == "__main__": raise SystemExit(main())