#!/usr/bin/env python3 """Generate the deterministic kinematics floating-point and iteration policy.""" from __future__ import annotations import argparse import hashlib import json from pathlib import Path def sha256(path: Path) -> str: digest = hashlib.sha256() with path.open("rb") as handle: for block in iter(lambda: handle.read(1024 * 1024), b""): digest.update(block) return digest.hexdigest() def generate(root: Path, output: Path) -> dict[str, object]: root = root.resolve() abi = root / "coverage/kinematics-abi-contract.json" mapping = root / "coverage/kinematics-mapping-contract.json" report = { "schema": "kinematics-numeric-policy.v1", "context_id": json.loads((root / "context-lock.json").read_text(encoding="utf-8")).get("context_id"), "inputs": {"abi_contract_sha256": sha256(abi), "mapping_contract_sha256": sha256(mapping)}, "compiler": {"fp_contract": "off", "fast_math": False, "fenv_access": "default", "denormals": "host-independent finite checks before arithmetic"}, "angles": {"input_units": "degrees for rotary joints", "internal_units": "radians", "constants": "full-precision DEG_TO_RAD/RAD_TO_DEG literals"}, "iterations": {"default": 0, "maximum": 100000, "zero_means": "algorithm default", "nonconvergence": "stable error; never repaired by tolerance widening"}, "tolerances": {"configuration_nonnegative": True, "singularity_threshold": 1e-12, "golden_absolute_default": 1e-9, "golden_relative_default": 1e-9, "state_hash_float_quantization": 1e-9, "tolerance_applies_only_to": ["finite numeric pose/joint fields"]}, "exact_fields": ["status", "error_code", "kinematics_type", "branch_id", "flags", "current_tick", "config_hash", "axis_joint_mapping", "event_order"], "boundary_matrix": [ {"case": "NaN joint", "expected": "SIM_KIN_ERR_NONFINITE"}, {"case": "+Inf pose", "expected": "SIM_KIN_ERR_NONFINITE"}, {"case": "negative tolerance", "expected": "SIM_KIN_ERR_CONFIGURATION"}, {"case": "iteration > 100000", "expected": "SIM_KIN_ERR_CONFIGURATION"}, {"case": "XYZBC B=90 singular", "expected": "SIM_KIN_ERR_SINGULAR"}, {"case": "enabled limit violation", "expected": "SIM_KIN_ERR_RANGE"}, ], "status": "verified", } report["policy_sha256"] = hashlib.sha256(json.dumps(report, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8")).hexdigest() output.parent.mkdir(parents=True, exist_ok=True) output.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8") return report def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1]) parser.add_argument("--output", type=Path, default=Path("coverage/kinematics-numeric-policy.json")) args = parser.parse_args() report = generate(args.repo_root, args.repo_root / args.output) print(f"kinematics_numeric={report['status']} boundaries={len(report['boundary_matrix'])}") return 0 if __name__ == "__main__": raise SystemExit(main())