Implement AXIS parity UI and execution baseline
This commit is contained in:
75
scripts/generate_axis_web_workflow_report.py
Normal file
75
scripts/generate_axis_web_workflow_report.py
Normal file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate FE-M4 evidence for the AXIS Web-equivalent workflow."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
REPORT = ROOT / "coverage/axis-web-workflow-fe-m4.report.json"
|
||||
CONTEXT_ID = "linuxcnc-2.10.0-pre0-wasm-m1-py-c1"
|
||||
SOURCE_FILES = (
|
||||
"linuxcnc/src/emc/usr_intf/axis/scripts/axis.py",
|
||||
"linuxcnc/src/emc/usr_intf/gremlin/gremlin.py",
|
||||
"linuxcnc/src/emc/usr_intf/gremlin/qt5_graphics.py",
|
||||
"linuxcnc/lib/python/rs274/glcanon.py",
|
||||
"web/react/src/App.tsx",
|
||||
"web/react/src/store.ts",
|
||||
"web/react/src/worker-client.ts",
|
||||
"web/react/src/gui-domain.ts",
|
||||
"web/react/src/ThreeMachineView.tsx",
|
||||
"web/worker/sim-session.mjs",
|
||||
)
|
||||
|
||||
|
||||
def canonical(value: Any) -> str:
|
||||
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
|
||||
|
||||
|
||||
def digest(path: Path) -> str:
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def run(command: list[str], cwd: Path) -> dict[str, Any]:
|
||||
result = subprocess.run(command, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
|
||||
return {"command": command, "returncode": result.returncode, "status": "verified" if result.returncode == 0 else "blocked", "stdout_sha256": hashlib.sha256(result.stdout).hexdigest(), "stderr_sha256": hashlib.sha256(result.stderr).hexdigest(), "stdout_tail": result.stdout.decode("utf-8", errors="replace")[-900:], "stderr_tail": result.stderr.decode("utf-8", errors="replace")[-900:]}
|
||||
|
||||
|
||||
def generate() -> dict[str, Any]:
|
||||
sources = [{"path": path, "status": "present" if (ROOT / path).is_file() else "missing", **({"bytes": (ROOT / path).stat().st_size, "sha256": digest(ROOT / path)} if (ROOT / path).is_file() else {})} for path in SOURCE_FILES]
|
||||
app_text = (ROOT / "web/react/src/App.tsx").read_text(encoding="utf-8")
|
||||
required_controls = ["PROGRAM_RUN", "PROGRAM_PAUSE", "PROGRAM_STEP", "PROGRAM_RESTART", "PROGRAM_ABORT", "JOG_START", "JOG_STOP", "HOME", "SET_OVERRIDE", "SPINDLE_COMMAND", "COOLANT_COMMAND", "TOOL_PREPARE", "TOOL_CHANGE", "PROBE_CONFIG", "ESTOP", "IO_RECOVER"]
|
||||
source_icons = sorted((ROOT / "linuxcnc/configs/sim/qtvcp_screens/qtaxis_lathe/qtaxis/images").glob("tool_*.gif"))
|
||||
checks = {
|
||||
"source_mapping": {"status": "verified" if all(row["status"] == "present" for row in sources) else "blocked", "files": len(sources)},
|
||||
"worker_commands": {"status": "verified" if all(command in app_text for command in required_controls) else "blocked", "commands": len(required_controls)},
|
||||
"source_axis_icons": {"status": "verified" if source_icons else "blocked", "assets": len(source_icons), "paths": [path.relative_to(ROOT).as_posix() for path in source_icons]},
|
||||
"three_viewer": {"status": "verified" if "ThreeMachineView" in app_text and "axes" in (ROOT / "web/react/src/ThreeMachineView.tsx").read_text(encoding="utf-8") else "blocked"},
|
||||
"worker_regression": run(["node", "web/worker/test_minimal_xyz_vertical_s8_04.mjs"], ROOT),
|
||||
"frontend_regression": run(["npm", "run", "build"], ROOT / "web/react"),
|
||||
}
|
||||
report: dict[str, Any] = {
|
||||
"schema": "axis-web-workflow-fe-m4-report.v1",
|
||||
"task_id": "FE-M4-GUI-03",
|
||||
"context_id": CONTEXT_ID,
|
||||
"status": "verified" if all(value["status"] == "verified" for value in checks.values()) else "blocked",
|
||||
"implementation_status": "verified" if all(value["status"] == "verified" for value in checks.values()) else "blocked",
|
||||
"workflow": ["case_load", "program_load", "program_run", "pause_resume_step", "abort_restart", "mdi", "jog_home", "feed_spindle_override", "spindle_coolant", "tool_prepare_change", "probe", "estop_recover", "dro", "threejs_pose"],
|
||||
"checks": checks,
|
||||
"source_files": sources,
|
||||
"boundaries": ["AXIS desktop window is WEB-EQUIV, not a GTK/Tk window copy", "Worker remains authoritative for task/motion/IO/tool/alarm state", "REAL-EXCLUDED hardware safety and host processes remain explicit", "full GUI family acceptance continues in FE-M4-GUI-04+"],
|
||||
}
|
||||
report["report_sha256"] = hashlib.sha256(canonical(report).encode()).hexdigest()
|
||||
REPORT.parent.mkdir(parents=True, exist_ok=True)
|
||||
REPORT.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
|
||||
return report
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
report = generate()
|
||||
print(f"axis_web_workflow={report['status']} report_sha256={report['report_sha256']}")
|
||||
Reference in New Issue
Block a user