Implement WebAssembly runtime and kinematics coverage
This commit is contained in:
65
scripts/generate_kinematics_mapping_contract.py
Normal file
65
scripts/generate_kinematics_mapping_contract.py
Normal file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Record deterministic axis/joint, duplicate-axis, home and limit semantics."""
|
||||
|
||||
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()
|
||||
header = root / "wasm-core/include/sim_kinematics.h"
|
||||
source = root / "wasm-core/src/sim_kinematics.c"
|
||||
report = {
|
||||
"schema": "kinematics-mapping-contract.v1",
|
||||
"context_id": json.loads((root / "context-lock.json").read_text(encoding="utf-8")).get("context_id"),
|
||||
"inputs": {"header": header.as_posix(), "header_sha256": sha256(header), "source": source.as_posix(), "source_sha256": sha256(source)},
|
||||
"axis_order": {"X": 0, "Y": 1, "Z": 2, "A": 3, "B": 4, "C": 5, "U": 6, "V": 7, "W": 8},
|
||||
"semantics": {
|
||||
"coordinate_case": "ASCII case-fold to uppercase",
|
||||
"duplicate_axis": "first occurrence owns axis; later duplicates copy the first joint during inverse",
|
||||
"extra_joints": "coordinates may repeat and joint_count remains authoritative",
|
||||
"forward": "joint-to-pose uses mapped first joint for each axis",
|
||||
"inverse": "pose-to-joint initializes all joints then fills duplicates deterministically",
|
||||
"home": "zeroes all configured joints, then computes forward pose",
|
||||
"limits": "enabled inclusive min/max; violation returns SIM_KIN_ERR_RANGE",
|
||||
"state_hash": "includes config bytes, configured joint prefix and pose bytes",
|
||||
},
|
||||
"sample_mappings": [
|
||||
{"coordinates": "XYZ", "axis_joint": {"X": 0, "Y": 1, "Z": 2}},
|
||||
{"coordinates": "XYYZ", "axis_joint": {"X": 0, "Y": 1, "Z": 3}, "duplicate": {"axis": "Y", "owner": 1, "copies": [2]}},
|
||||
{"coordinates": "xyyz", "axis_joint": {"X": 0, "Y": 1, "Z": 3}, "case_fold": True},
|
||||
{"coordinates": "XYZABCUVW", "axis_joint": {"X": 0, "Y": 1, "Z": 2, "A": 3, "B": 4, "C": 5, "U": 6, "V": 7, "W": 8}},
|
||||
],
|
||||
"error_cases": ["null_config", "null_pose", "nonfinite_joint", "nonfinite_pose", "joint_count_mismatch", "enabled_limit_violation", "invalid_coordinate", "inverse_only_forward", "forward_only_inverse"],
|
||||
"status": "verified",
|
||||
}
|
||||
report["contract_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-mapping-contract.json"))
|
||||
args = parser.parse_args()
|
||||
report = generate(args.repo_root, args.repo_root / args.output)
|
||||
print(f"kinematics_mapping={report['status']} samples={len(report['sample_mappings'])} errors={len(report['error_cases'])}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user