Implement AXIS parity UI and execution baseline
This commit is contained in:
98
scripts/generate_linuxcnc_source_config_s5.py
Normal file
98
scripts/generate_linuxcnc_source_config_s5.py
Normal file
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate the S5-07 full simulation configuration startup matrix."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
CONTEXT_ID = "linuxcnc-2.10.0-pre0-wasm-m1-py-c1"
|
||||
WORKER = ("node", "web/worker/test_source_config_s5.mjs")
|
||||
BATCH = ("node", "web/worker/test_configuration_batch.mjs")
|
||||
STARTUP = ("node", "web/worker/test_configuration_startup_runtime.mjs")
|
||||
MATRIX = Path("coverage/full-configuration-startup-matrix.report.json")
|
||||
STARTUP_REPORT = Path("coverage/configuration-startup-runtime.report.json")
|
||||
|
||||
|
||||
def canonical(value: Any) -> str:
|
||||
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
|
||||
|
||||
|
||||
def digest(value: bytes) -> str:
|
||||
return hashlib.sha256(value).hexdigest()
|
||||
|
||||
|
||||
def command(root: Path, args: tuple[str, ...]) -> dict[str, Any]:
|
||||
result = subprocess.run(args, cwd=root, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
|
||||
return {"command": list(args), "status": "PASSED" if result.returncode == 0 else "FAILED", "returncode": result.returncode, "stdout_sha256": digest(result.stdout), "stderr_sha256": digest(result.stderr), "stdout": result.stdout.decode("utf-8", errors="replace"), "stderr": result.stderr.decode("utf-8", errors="replace")}
|
||||
|
||||
|
||||
def parse(result: dict[str, Any]) -> dict[str, Any] | None:
|
||||
try:
|
||||
return json.loads(result["stdout"])
|
||||
except json.JSONDecodeError:
|
||||
return None
|
||||
|
||||
|
||||
def artifact(root: Path, path: Path) -> dict[str, Any]:
|
||||
value = root / path
|
||||
return {"path": path.as_posix(), "bytes": value.stat().st_size, "sha256": digest(value.read_bytes())} if value.is_file() else {"path": path.as_posix(), "status": "missing"}
|
||||
|
||||
|
||||
def generate(root: Path, output: Path) -> dict[str, Any]:
|
||||
matrix = json.loads((root / MATRIX).read_text(encoding="utf-8"))
|
||||
startup_report = json.loads((root / STARTUP_REPORT).read_text(encoding="utf-8"))
|
||||
worker = command(root, WORKER)
|
||||
batch = command(root, BATCH)
|
||||
startup = command(root, STARTUP)
|
||||
worker_json = parse(worker)
|
||||
batch_json = parse(batch)
|
||||
startup_json = parse(startup) or {"status": startup["status"], "stdout_sha256": startup["stdout_sha256"]}
|
||||
rows = worker_json.get("entrypoint_results", []) if worker_json else []
|
||||
worker_ok = worker["returncode"] == 0 and worker_json is not None and len(rows) == 264 and worker_json.get("counts") == {"total": 264, "sim_configs": 216, "test_configs": 48, "READY": 56, "BLOCKED": 208}
|
||||
runtime_ok = batch["returncode"] == 0 and startup["returncode"] == 0 and batch_json is not None
|
||||
status_ok = worker_ok and runtime_ok and startup_report.get("implementation_status") == "verified"
|
||||
report: dict[str, Any] = {
|
||||
"schema": "linuxcnc-source-config-execution.v1",
|
||||
"task_id": "S5-07",
|
||||
"context_id": CONTEXT_ID,
|
||||
"status": "verified" if status_ok else "blocked",
|
||||
"scope": {"sim_configs": 216, "test_config_entries": 48, "registered_matrix_entries": 264, "reported_entrypoints": 233},
|
||||
"matrix_input": {"artifact": artifact(root, MATRIX), "schema": matrix.get("schema"), "status": matrix.get("status"), "implementation_status": matrix.get("implementation_status"), "counts": matrix.get("counts")},
|
||||
"entrypoints": rows,
|
||||
"counts": worker_json.get("counts", {}) if worker_json else {},
|
||||
"workflow": {
|
||||
"batch": {"execution": {key: value for key, value in batch.items() if key not in {"stdout", "stderr"}}, "sample": batch_json},
|
||||
"startup": {"execution": {key: value for key, value in startup.items() if key not in {"stdout", "stderr"}}, "sample": startup_json},
|
||||
"native_wasm_worker_startup_report": {"path": STARTUP_REPORT.as_posix(), "sha256": digest((root / STARTUP_REPORT).read_bytes()), "status": startup_report.get("status"), "implementation_status": startup_report.get("implementation_status"), "compatibility": startup_report.get("checks", {}).get("native_wasm_worker_compatibility", {}).get("status")},
|
||||
},
|
||||
"boundaries": [
|
||||
"READY means static startup preflight only; it is not an official LinuxCNC runtime oracle",
|
||||
"BLOCKED rows retain resource_missing/unindexed/kinematics_unregistered diagnostics and are never promoted",
|
||||
"full native/WASM/Worker startup probes and batch checkpoint/restore are recorded separately",
|
||||
"official kinematics/recovery oracle remains blocked by the locked source context",
|
||||
],
|
||||
}
|
||||
report["report_sha256"] = digest(canonical({key: value for key, value in report.items() if key != "report_sha256"}).encode("utf-8"))
|
||||
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("--report", type=Path, default=Path("coverage/linuxcnc-source-config-s5.report.json"))
|
||||
args = parser.parse_args()
|
||||
report = generate(args.repo_root.resolve(), args.repo_root.resolve() / args.report)
|
||||
print(f"linuxcnc_source_config_s5={report['status']} entries={report['counts'].get('total', 0)} ready={report['counts'].get('READY', 0)} blocked={report['counts'].get('BLOCKED', 0)}")
|
||||
return 0 if report["status"] == "verified" else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user