#!/usr/bin/env python3 """Verify that every canonical Tier-2 pure API has terminal native evidence.""" from __future__ import annotations import hashlib import json from collections import Counter from pathlib import Path ROOT = Path(__file__).resolve().parents[1] P6 = ROOT / "docs/p6" MANIFEST = P6 / "python-api-manifest.json" manifest_bytes = MANIFEST.read_bytes() manifest = json.loads(manifest_bytes) rows = [row for row in manifest["records"] if row.get("tier") == "tier-2-pure"] terminal = {"exposed", "restricted", "nonportable", "not_implemented"} missing = [row["id"] for row in rows if row.get("disposition") not in terminal or not row.get("dispositionEvidence")] modules = sorted({row["module"] for row in rows}) artifact_index = {} for module in modules: candidates = sorted(P6.glob(f"{module.lower()}*tier2*pure*family-runtime.json")) if module == "OpenSCAD": candidates = sorted(P6.glob("openscad-tier2-pure-family-runtime.json")) if not candidates: missing.append(f"artifact:{module}") continue path = candidates[-1] raw = path.read_bytes() value = json.loads(raw) artifact_index[module] = {"path": str(path.relative_to(ROOT)), "sha256": hashlib.sha256(raw).hexdigest(), "status": value.get("status")} if value.get("status") not in {"pass", "pass_with_boundaries"}: missing.append(f"artifact_status:{module}") counts = Counter(row.get("disposition") for row in rows) report = { "schema": "freecad-web-p6-python-api-pure-aggregate-gate/v1", "taskId": "FW-P6-FPA-F2", "result": "pass_with_boundaries" if len(rows) == 6417 and not missing else "fail", "source": {"manifest": "docs/p6/python-api-manifest.json", "manifestSha256": hashlib.sha256(manifest_bytes).hexdigest()}, "coverage": {"tier": "tier-2-pure", "records": len(rows), "counts": dict(sorted(counts.items())), "modules": modules, "missing": missing}, "evidence": artifact_index, "boundaries": [ "Every Tier-2 record has a terminal disposition and a module-scoped native evidence reference.", "Terminal not_implemented/restricted records remain capability denials; no JavaScript result is substituted.", "Later Tier-3/stateful and exhaustive Chrome gates remain outside this aggregate implementation gate.", ], } (P6 / "python-api-pure-aggregate-gate.json").write_text(json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") (ROOT / "docs/freecad-p6-python-api-pure-aggregate-gate.log").write_text(json.dumps({"result": report["result"], "coverage": report["coverage"]}, ensure_ascii=False) + "\n", encoding="utf-8") print(json.dumps({"result": report["result"], "coverage": report["coverage"]}, ensure_ascii=False)) raise SystemExit(0 if report["result"] != "fail" else 1)