88 lines
5.6 KiB
Python
88 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Compare native AXIS and Web/WASM manual-tool evidence."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
OUTPUT = Path("coverage/axis3-tutorial-native-web-tool-comparison.report.json")
|
|
CASE = "linuxcnc/configs/sim/axis/vismach/3axis-tutorial/3axis-tutorial.ini"
|
|
CONTEXT_ID = "linuxcnc-2.10.0-pre0-wasm-m1-py-c1"
|
|
|
|
|
|
def canonical(value: Any) -> str:
|
|
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
|
|
|
|
|
|
def digest(value: Any) -> str:
|
|
return hashlib.sha256(canonical(value).encode()).hexdigest()
|
|
|
|
|
|
def load(root: Path, path: str) -> dict[str, Any]:
|
|
return json.loads((root / path).read_text(encoding="utf-8"))
|
|
|
|
|
|
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
|
|
root = root.resolve()
|
|
native = load(root, "coverage/axis3-tutorial-manual-ui-verification.report.json")
|
|
web = load(root, "coverage/axis3-tutorial-web-manual-verification.report.json")
|
|
parity = load(root, "coverage/axis3-tutorial-web-wasm-complete-parity.report.json")
|
|
native_ok = native.get("status") == "verified" and native.get("window", {}).get("title", "").find("3dtest.ngc") >= 0 and all(item.get("returncode") == 0 for item in native.get("screenshots", []))
|
|
web_ok = web.get("status") == "verified" and web.get("case") == CASE and all(item.get("bytes", 0) > 0 for item in web.get("screenshots", []))
|
|
shared = {
|
|
"case": CASE,
|
|
"context_id": CONTEXT_ID,
|
|
"program": "linuxcnc/nc_files/3dtest.ngc",
|
|
"native_source_files": "coverage/axis3-tutorial-native-run.report.json",
|
|
"wasm_source_files": "coverage/axis3-tutorial-web-wasm-complete-parity.report.json",
|
|
}
|
|
checks = {
|
|
"native_tool_verified": {"status": "verified" if native_ok else "blocked", "report": "coverage/axis3-tutorial-manual-ui-verification.report.json"},
|
|
"web_tool_verified": {"status": "verified" if web_ok else "blocked", "report": "coverage/axis3-tutorial-web-manual-verification.report.json"},
|
|
"same_case_and_context": {"status": "verified" if native.get("case") == "linuxcnc/configs/sim/axis/vismach/3axis-tutorial" and web.get("case") == CASE else "blocked", **shared},
|
|
"same_operation_intent": {"status": "verified" if [row.get("state") for row in native.get("transitions", [])] == ["WINDOW_VISIBLE", "ESTOP_RESET", "ON", "ALL_HOMED_REQUESTED", "AUTO_RUN_REQUESTED"] and [row.get("state") for row in web.get("states", []) if row.get("label") in {"ready", "estop", "power", "homed", "running", "complete"}] else "blocked", "native": [row.get("state") for row in native.get("transitions", [])], "web_labels": [row.get("label") for row in web.get("states", []) if row.get("label") in {"ready", "estop", "power", "homed", "running", "complete"}]},
|
|
"visual_evidence_nonempty": {"status": "verified" if native_ok and web_ok else "blocked", "native_screenshots": len(native.get("screenshots", [])), "web_screenshots": len(web.get("screenshots", []))},
|
|
"wasm_acceptance_regression": {"status": "verified" if parity.get("status") == "verified" and parity.get("passed_command_count") == parity.get("required_command_count") else "blocked", "passed": parity.get("passed_command_count"), "required": parity.get("required_command_count")},
|
|
}
|
|
report: dict[str, Any] = {
|
|
"schema": "axis3-tutorial-native-web-tool-comparison.v1",
|
|
"task_id": "AXIS3-NATIVE-WEB-TOOL-COMPARISON-01",
|
|
"context_id": CONTEXT_ID,
|
|
"case": CASE,
|
|
"status": "verified" if all(item["status"] == "verified" for item in checks.values()) else "blocked",
|
|
"conclusion": "native_and_web_tools_match_selected_case_workflow" if all(item["status"] == "verified" for item in checks.values()) else "tool_comparison_blocked",
|
|
"shared_inputs": shared,
|
|
"tools": {
|
|
"native": {"tool": "tool/linuxcnc-axis-manual-execution", "report": "coverage/axis3-tutorial-manual-ui-verification.report.json", "window": native.get("window"), "screenshots": native.get("screenshots"), "transitions": native.get("transitions")},
|
|
"web": {"tool": "tool/linuxcnc-web-wasm-manual-execution", "report": "coverage/axis3-tutorial-web-manual-verification.report.json", "browser": web.get("browser"), "screenshots": web.get("screenshots"), "states": [row for row in web.get("states", []) if row.get("label") in {"ready", "estop", "power", "homed", "running", "complete"}]},
|
|
},
|
|
"checks": checks,
|
|
"boundaries": ["simulation-only", "native process uses POSIX non-realtime fallback", "Web visual uses Chromium SwiftShader", "real hardware and full LinuxCNC parity are outside selected-case tool comparison"],
|
|
"report_sha256": None,
|
|
}
|
|
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
|
|
destination = output if output.is_absolute() else root / output
|
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
destination.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()
|
|
parser.add_argument("--repo-root", type=Path, default=ROOT)
|
|
parser.add_argument("--output", type=Path, default=OUTPUT)
|
|
args = parser.parse_args()
|
|
report = generate(args.repo_root.resolve(), args.output)
|
|
print(f"axis3_tool_comparison={report['status']} conclusion={report['conclusion']}")
|
|
return 0 if report["status"] == "verified" else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|