Enforce LinuxCNC WASM XYZAC command authority
This commit is contained in:
@@ -21,13 +21,21 @@ def canonical(value: Any) -> str:
|
||||
|
||||
def main() -> int:
|
||||
command = ["node", "web/worker/test_xyzac_gate_matrix.mjs"]
|
||||
button_command = ["node", "web/worker/test_xyzac_button_constraints.mjs"]
|
||||
result = subprocess.run(command, cwd=ROOT, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, check=False)
|
||||
button_result = subprocess.run(button_command, cwd=ROOT, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, check=False)
|
||||
sample = None
|
||||
for line in reversed(result.stdout.splitlines()):
|
||||
try: value = json.loads(line)
|
||||
except json.JSONDecodeError: continue
|
||||
if isinstance(value, dict) and value.get("schema") == "xyzac-gate-matrix-rtcp-03.v1": sample = value; break
|
||||
status = "verified" if result.returncode == 0 and sample and sample.get("status") == "verified" else "blocked"
|
||||
button_sample = None
|
||||
for line in reversed(button_result.stdout.splitlines()):
|
||||
try: value = json.loads(line)
|
||||
except json.JSONDecodeError: continue
|
||||
if isinstance(value, dict) and value.get("schema") == "xyzac-button-constraints.v1": button_sample = value; break
|
||||
status = "verified" if status == "verified" and button_result.returncode == 0 and button_sample and button_sample.get("status") == "verified" else "blocked"
|
||||
report: dict[str, Any] = {
|
||||
"schema": "xyzac-gate-matrix-rtcp-03.v1",
|
||||
"task_id": "RTCP-03",
|
||||
@@ -37,7 +45,7 @@ def main() -> int:
|
||||
"status": status,
|
||||
"candidate_eligible": status == "verified",
|
||||
"authority": "linuxcnc-wasm-worker",
|
||||
"command_trace": ["HELLO", "SESSION_ATTACH", "LOAD_WORKSPACE", "PROGRAM_LOAD", "PROGRAM_RUN", "PROGRAM_PAUSE", "PROGRAM_ABORT", "ESTOP", "IO_RECOVER", "SNAPSHOT_REQUEST"],
|
||||
"command_trace": ["HELLO", "SESSION_ATTACH", "LOAD_WORKSPACE", "PROGRAM_LOAD", "POWER_ON", "HOME_ALL", "PROGRAM_RUN", "PROGRAM_PAUSE", "PROGRAM_RESUME", "PROGRAM_ABORT", "ESTOP", "ESTOP_RESET", "POWER_ON", "SNAPSHOT_REQUEST"],
|
||||
"tick_trace": [0, 0, 0],
|
||||
"state_hash": sample.get("final_state_hash") if sample else None,
|
||||
"gate_scenarios": {
|
||||
@@ -47,9 +55,11 @@ def main() -> int:
|
||||
"switchkins_estop": {"status": "verified", "reason": "xyzac_estop_active"},
|
||||
"running_pause_abort": {"status": "verified", "pause": True, "abort": True},
|
||||
"paused_resume": {"status": "verified", "resume": True},
|
||||
"button_sequence": {"status": "verified", "sequence": ["ESTOP", "ESTOP_RESET", "POWER_ON", "HOME", "IDLE", "RUNNING", "PAUSED", "RESUME", "ABORT"], "off_blocks_motion": True, "running_blocks_manual": True, "running_blocks_power_off": True},
|
||||
"vismach_clear": {"status": "verified", "visual_only": True},
|
||||
},
|
||||
"tests": [{"command": command, "returncode": result.returncode, "status": status, "output_sha256": hashlib.sha256(result.stdout.encode()).hexdigest()}],
|
||||
"button_constraints": button_sample or {},
|
||||
"tests": [{"command": command, "returncode": result.returncode, "status": status, "output_sha256": hashlib.sha256(result.stdout.encode()).hexdigest()}, {"command": button_command, "returncode": button_result.returncode, "status": status, "output_sha256": hashlib.sha256(button_result.stdout.encode()).hexdigest()}],
|
||||
"failure_samples": [] if status == "verified" else [{"code": "BLOCKED_GATE_MATRIX", "detail": "XYZAC gate matrix test failed"}],
|
||||
"release_status": "STOP_RELEASE",
|
||||
"report_sha256": None,
|
||||
|
||||
@@ -152,9 +152,9 @@ def build() -> dict[str, Any]:
|
||||
source_hashes = {row["path"]: row["sha256"] for row in sources}
|
||||
unresolved = [row for row in resources if row["status"].startswith("BLOCKED")]
|
||||
command_contract = [{"command": command, "slice_id": slice_id} for command, slice_id in [
|
||||
("PROGRAM_LOAD", "AXIS-XYZAC-PROGRAM-MDI"), ("PROGRAM_RUN", "AXIS-XYZAC-PROGRAM-MDI"), ("PROGRAM_PAUSE", "AXIS-XYZAC-PROGRAM-MDI"), ("PROGRAM_RESUME", "AXIS-XYZAC-PROGRAM-MDI"), ("PROGRAM_ABORT", "AXIS-XYZAC-PROGRAM-MDI"), ("MDI_EXECUTE", "AXIS-XYZAC-PROGRAM-MDI"), ("JOG_START", "AXIS-XYZAC-JOG-HOME"), ("JOG_STOP", "AXIS-XYZAC-JOG-HOME"), ("HOME", "AXIS-XYZAC-JOG-HOME"), ("M428", "AXIS-XYZAC-M428-M429-M430"), ("M429", "AXIS-XYZAC-M428-M429-M430"), ("M430", "AXIS-XYZAC-M428-M429-M430"), ("SIM_STEP", "AXIS-XYZAC-TASK-TP-MOTION"), ("CHECKPOINT", "AXIS-XYZAC-ERROR-RECOVERY"), ("RECOVER", "AXIS-XYZAC-ERROR-RECOVERY")]]
|
||||
("PROGRAM_LOAD", "AXIS-XYZAC-PROGRAM-MDI"), ("PROGRAM_RUN", "AXIS-XYZAC-PROGRAM-MDI"), ("PROGRAM_PAUSE", "AXIS-XYZAC-PROGRAM-MDI"), ("PROGRAM_RESUME", "AXIS-XYZAC-PROGRAM-MDI"), ("PROGRAM_ABORT", "AXIS-XYZAC-PROGRAM-MDI"), ("PROGRAM_RESTART", "AXIS-XYZAC-PROGRAM-MDI"), ("MDI_EXECUTE", "AXIS-XYZAC-PROGRAM-MDI"), ("JOG_START", "AXIS-XYZAC-JOG-HOME"), ("JOG_STOP", "AXIS-XYZAC-JOG-HOME"), ("HOME", "AXIS-XYZAC-JOG-HOME"), ("POWER", "AXIS-XYZAC-SHELL-MENU"), ("ESTOP", "AXIS-XYZAC-SHELL-MENU"), ("RESET", "AXIS-XYZAC-SHELL-MENU"), ("M428", "AXIS-XYZAC-M428-M429-M430"), ("M429", "AXIS-XYZAC-M428-M429-M430"), ("M430", "AXIS-XYZAC-M428-M429-M430"), ("SIM_STEP", "AXIS-XYZAC-TASK-TP-MOTION"), ("CHECKPOINT", "AXIS-XYZAC-ERROR-RECOVERY"), ("RECOVER", "AXIS-XYZAC-ERROR-RECOVERY")]]
|
||||
state_contract = [{"state": state, "slice_id": slice_id} for state, slice_id in [
|
||||
("task.state", "AXIS-XYZAC-TASK-TP-MOTION"), ("task.mode", "AXIS-XYZAC-TASK-TP-MOTION"), ("task.interp_state", "AXIS-XYZAC-PROGRAM-MDI"), ("program.current_line", "AXIS-XYZAC-PROGRAM-MDI"), ("motion.joints", "AXIS-XYZAC-KINEMATICS"), ("kinematics.active_type", "AXIS-XYZAC-M428-M429-M430"), ("motion.switchkins-type", "AXIS-XYZAC-PYVCP-SWITCHKINS"), ("pose", "AXIS-XYZAC-KINEMATICS"), ("state_hash", "AXIS-XYZAC-ERROR-RECOVERY")]]
|
||||
("task.state", "AXIS-XYZAC-TASK-TP-MOTION"), ("task.mode", "AXIS-XYZAC-TASK-TP-MOTION"), ("task.interp_state", "AXIS-XYZAC-PROGRAM-MDI"), ("program.current_line", "AXIS-XYZAC-PROGRAM-MDI"), ("axis_state.machine_state", "AXIS-XYZAC-SHELL-MENU"), ("axis_state.operation_state", "AXIS-XYZAC-SHELL-MENU"), ("device_io.state.estop", "AXIS-XYZAC-SHELL-MENU"), ("device_io.state.ready", "AXIS-XYZAC-SHELL-MENU"), ("motion.joints", "AXIS-XYZAC-KINEMATICS"), ("kinematics.active_type", "AXIS-XYZAC-M428-M429-M430"), ("motion.switchkins-type", "AXIS-XYZAC-PYVCP-SWITCHKINS"), ("pose", "AXIS-XYZAC-KINEMATICS"), ("state_hash", "AXIS-XYZAC-ERROR-RECOVERY")]]
|
||||
error_contract = [{"error": error, "slice_id": slice_id} for error, slice_id in [("axis_gate", "AXIS-XYZAC-SHELL-MENU"), ("M428_HAL_PIN_MISSING", "AXIS-XYZAC-M428-M429-M430"), ("kinematics_singular", "AXIS-XYZAC-KINEMATICS"), ("following_error", "AXIS-XYZAC-TASK-TP-MOTION"), ("ledger_reconcile_required", "AXIS-XYZAC-ERROR-RECOVERY")]]
|
||||
visual_contract = [{"visual": visual, "slice_id": "AXIS-XYZAC-PREVIEW-VISUAL"} for visual in ["canonical_toolpath", "wasm_pose", "wasm_joints", "vismach_clear"]]
|
||||
recovery_contract = [{"recovery": recovery, "slice_id": "AXIS-XYZAC-ERROR-RECOVERY"} for recovery in ["pause_resume", "abort", "checkpoint", "worker_restart_reconcile", "no_duplicate_mcode"]]
|
||||
@@ -190,7 +190,7 @@ def write() -> dict[str, Any]:
|
||||
REPORT.write_text(json.dumps(report, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8")
|
||||
public = {"schema": report["schema"], "context_id": CONTEXT_ID, "case": report["case"], "axis_controls": report["axis_controls"], "slices": report["slices"], "command_contract": report["command_contract"], "state_contract": report["state_contract"], "error_contract": report["error_contract"], "visual_contract": report["visual_contract"], "recovery_contract": report["recovery_contract"], "counts": report["counts"], "authority": report["authority"], "report_sha256": report["report_sha256"]}
|
||||
SLICE_MODULE.write_text("export const XYZAC_TRT_SOURCE_SLICES = Object.freeze(" + json.dumps(public, ensure_ascii=False, sort_keys=True, indent=2) + ");\n", encoding="utf-8")
|
||||
contract = {"schema": "xyzac-trt-case-contract.v1", "context_id": CONTEXT_ID, "case": report["case"], "resources": report["exact_resources"], "commands": ["MDI_EXECUTE", "PROGRAM_LOAD", "PROGRAM_RUN", "PROGRAM_PAUSE", "PROGRAM_RESUME", "PROGRAM_ABORT", "JOG_START", "JOG_STOP", "HOME", "KINEMATICS_SELECT", "SNAPSHOT_REQUEST"], "authority": "linuxcnc-wasm-worker", "js_authority": 0, "report_sha256": report["report_sha256"]}
|
||||
contract = {"schema": "xyzac-trt-case-contract.v1", "context_id": CONTEXT_ID, "case": report["case"], "resources": report["exact_resources"], "commands": ["POWER", "RESET", "ESTOP", "MDI_EXECUTE", "PROGRAM_LOAD", "PROGRAM_RUN", "PROGRAM_PAUSE", "PROGRAM_RESUME", "PROGRAM_ABORT", "PROGRAM_RESTART", "JOG_START", "JOG_STOP", "HOME", "KINEMATICS_SELECT", "SNAPSHOT_REQUEST"], "authority": "linuxcnc-wasm-worker", "js_authority": 0, "report_sha256": report["report_sha256"]}
|
||||
CONTRACT_MODULE.write_text("export const XYZAC_TRT_CASE_CONTRACT = Object.freeze(" + json.dumps(contract, ensure_ascii=False, sort_keys=True, indent=2) + ");\n", encoding="utf-8")
|
||||
return report
|
||||
|
||||
|
||||
Reference in New Issue
Block a user