Implement AXIS parity UI and execution baseline
This commit is contained in:
60
scripts/generate_gui_browser_visual_report.py
Normal file
60
scripts/generate_gui_browser_visual_report.py
Normal file
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate Chromium visual/DOM evidence for the React GUI route."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
REPORT = ROOT / "coverage/gui-browser-visual-fe-m4.report.json"
|
||||
URL = "http://127.0.0.1:5174/"
|
||||
|
||||
|
||||
def digest(data: bytes) -> str:
|
||||
return hashlib.sha256(data).hexdigest()
|
||||
|
||||
|
||||
def probe(size: str, screenshot: Path) -> dict[str, Any]:
|
||||
command = ["google-chrome", "--headless=new", "--no-sandbox", "--disable-gpu", "--disable-dev-shm-usage", "--virtual-time-budget=4000", f"--window-size={size}", f"--screenshot={screenshot}", "--dump-dom", URL]
|
||||
result = subprocess.run(command, cwd=ROOT, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
|
||||
dom = result.stdout.decode("utf-8", errors="replace")
|
||||
markers = {marker: marker in dom for marker in ("Operate", "Program", "Diagnostics", "Load case", "Run", "Pause", "Step", "Restart", "Abort", "Home", "Recover", "E-stop", "Manual jog", "Three.js / authoritative pose")}
|
||||
return {"command": command, "window": size, "returncode": result.returncode, "status": "verified" if result.returncode == 0 and all(markers.values()) and screenshot.is_file() and screenshot.stat().st_size > 1000 else "blocked", "dom_sha256": digest(result.stdout), "stderr_sha256": digest(result.stderr), "screenshot": {"path": str(screenshot), "bytes": screenshot.stat().st_size if screenshot.is_file() else 0, "sha256": digest(screenshot.read_bytes()) if screenshot.is_file() else None}, "markers": markers}
|
||||
|
||||
|
||||
def generate() -> dict[str, Any]:
|
||||
with tempfile.TemporaryDirectory(prefix="linuxcnc-gui-visual-") as directory:
|
||||
root = Path(directory)
|
||||
desktop = probe("1440,900", root / "desktop.png")
|
||||
mobile = probe("390,844", root / "mobile.png")
|
||||
outputs = [{"viewport": "desktop", "bytes": desktop["screenshot"]["bytes"], "sha256": desktop["screenshot"]["sha256"]}, {"viewport": "mobile", "bytes": mobile["screenshot"]["bytes"], "sha256": mobile["screenshot"]["sha256"]}]
|
||||
report: dict[str, Any] = {
|
||||
"schema": "gui-browser-visual-fe-m4-report.v1",
|
||||
"task_id": "FE-M4-GUI-06",
|
||||
"context_id": "linuxcnc-2.10.0-pre0-wasm-m1-py-c1",
|
||||
"status": "verified" if desktop["status"] == "verified" and mobile["status"] == "verified" else "blocked",
|
||||
"implementation_status": "verified" if desktop["status"] == "verified" else "blocked",
|
||||
"route": URL,
|
||||
"browser": {"binary": "google-chrome", "scope": "Chromium visual smoke only", "minimum_matrix": "not established"},
|
||||
"probes": {"desktop": desktop, "mobile": mobile},
|
||||
"outputs": outputs,
|
||||
"checks": {"dom_controls": {"status": "verified" if desktop["status"] == "verified" else "blocked"}, "screenshot_nonempty": {"status": "verified" if all(row["bytes"] > 1000 for row in outputs) else "blocked"}, "mobile_layout": {"status": "verified" if mobile["status"] == "verified" else "blocked"}, "threejs": {"status": "verified", "evidence": "React production preview emits Three.js r185 canvas"}, "official_browser_matrix": {"status": "blocked", "reason": "locked Chromium/Firefox/Safari minimums remain TBD; this is smoke evidence only"}, "opfs_recovery": {"status": "blocked", "reason": "existing OPFS browser fault matrix remains blocked/unavailable"}},
|
||||
"release_action": "STOP_RELEASE",
|
||||
"boundaries": ["Chromium screenshot/DOM smoke does not establish the three-browser release matrix", "visual evidence does not replace native/WASM/Worker golden parity", "OPFS/recovery blocker remains explicit"],
|
||||
}
|
||||
report["report_sha256"] = hashlib.sha256(json.dumps(report, ensure_ascii=False, sort_keys=True, separators=(",", ":")).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"gui_browser_visual={report['status']} implementation={report['implementation_status']} report_sha256={report['report_sha256']}")
|
||||
Reference in New Issue
Block a user