Record AXIS browser and parity test matrix

This commit is contained in:
2026-08-23 10:12:09 +08:00
parent c96c48a0eb
commit 00d97fc2d4
5 changed files with 216 additions and 1 deletions

View File

@@ -0,0 +1,114 @@
{
"boundaries": [
"Chromium authorization closes only the Chromium visual/performance slice",
"Firefox/Safari and OPFS recovery remain independently blocked",
"case resource/oracle blockers are not promoted by visual smoke"
],
"checks": {
"browser_minimum_matrix": {
"reason": "Firefox/Safari minimums are TBD; Safari unavailable",
"release_action": "STOP_RELEASE",
"source": "coverage/browser-matrix-remediation.report.json",
"status": "blocked"
},
"browser_performance": {
"repeat_determinism": "verified",
"scope": [
"chromium"
],
"status": "verified"
},
"canonical_visual": {
"chromium_authorized": true,
"desktop": "verified",
"mobile": "verified",
"status": "verified"
},
"dom_accessibility": {
"details": {
"desktop": {
"aria_label_count": 36,
"tab_controls_resolve": true,
"tab_count": 4,
"tabpanel_count": 4,
"toolbar_icon_count": 20,
"toolbar_icon_scope": "axis-toolbar"
},
"mobile": {
"aria_label_count": 36,
"tab_controls_resolve": true,
"tab_count": 4,
"tabpanel_count": 4,
"toolbar_icon_count": 20,
"toolbar_icon_scope": "axis-toolbar"
},
"status": "verified"
},
"source": "coverage/gui-browser-visual-fe-m4.report.json",
"status": "verified"
},
"interaction_replay": {
"current_line": true,
"operation_trace": true,
"source": [
"coverage/axis-control.report.json",
"coverage/axis-view-edit.report.json"
],
"status": "verified"
},
"native_worker_case_parity": {
"blocked_cases": 6,
"blocked_families": [
"lathe",
"gantry",
"vismach-5axis"
],
"source": "coverage/axis-case-parity.report.json",
"status": "partial",
"verified_cases": 5
},
"opfs_recovery": {
"reason": "OPFS worker timeout and Playwright crash/restart unavailable",
"release_action": "STOP_RELEASE",
"status": "blocked"
}
},
"context_id": "linuxcnc-2.10.0-pre0-wasm-m1-py-c1",
"implementation_status": "evidence_aggregated",
"inputs": [
{
"path": "coverage/gui-browser-visual-fe-m4.report.json",
"sha256": "47cca469a22986235ea147333f8b9b6902480793db5c554a6267840c0b572f95",
"status": "present"
},
{
"path": "coverage/browser-performance-matrix.report.json",
"sha256": "58291be3c636a4df4373d93f81dbd0bab94d6386d122045c7a9b3641f98cd7ad",
"status": "present"
},
{
"path": "coverage/browser-matrix-remediation.report.json",
"sha256": "7e6a8f2dc51ad80a75504407d04f7be6727355dd9f7bcd1ff49cd47eb5cac284",
"status": "present"
},
{
"path": "coverage/axis-case-parity.report.json",
"sha256": "3b72163e5ed029b30f4637b3794d404d1f7bf55cdb7a3f6ee0e278b1ddc52211",
"status": "present"
},
{
"path": "coverage/axis-control.report.json",
"sha256": "90baa63d72ccdef3d55b9611e130a041ac813fc744d1311465e5dd5a18ddd7d9",
"status": "present"
},
{
"path": "coverage/axis-view-edit.report.json",
"sha256": "452a1b13aa4fe75f9fe4cfe54679360756acea7dac87e4abdcb5118fe7ed6bab",
"status": "present"
}
],
"report_sha256": "9ba5de25bd8cfbfd61bd0a87bcb282170fa1de44b28a172b1c6ba649f580c357",
"schema": "axis-test-matrix-report.v1",
"status": "partial",
"task_id": "AXIS-TEST-01..06"
}

View File

@@ -557,7 +557,7 @@ M0 的 `AXIS-INV-01…04` 已执行:[`coverage/axis-source-inventory.report.js
4. `AXIS-CTRL-01…08` 已完成:[`coverage/axis-control.report.json`](../coverage/axis-control.report.json) 固化 Worker-backed command mapping、单调 operation ID、pending/result/error/blocked trace、门控前置检查和 F1/F2/F3/F5/R/T/P/S/Escape/Ctrl-K 快捷键;报告哈希 `cc12b349cc3fc3e7d1882530f123ca92e4a510f3f40fec4c72bcfd4e876f0a3e`。
5. `AXIS-VIEW-01…04` 和 `AXIS-EDIT-01` 已完成:[`coverage/axis-view-edit.report.json`](../coverage/axis-view-edit.report.json) 固化 Worker authoritative planner trajectory、6 camera modes、8 preview layers、DRO coordinate/display/unit modes、current-line/aria-current/diagnostic editor evidence;报告哈希 `39785b377806de18cb48a1d3c38c129d84a000b9c81d2478cc1a5567ec754e9b`。
6. `AXIS-CASE-01…04` 已形成案例矩阵:[`coverage/axis-case-parity.report.json`](../coverage/axis-case-parity.report.json) 中 Minimal XYZ、CoreXY kins/HAL、Linear/Rotary Delta representative verified;lathe/gantry/VisMach-5-axis 仍按 exact resource/startup 与 official kinematics oracle 保持 blocked。报告哈希 `a6fcc5eec964a02b821f9a52f30b8e0d3303b8c94507b6d44d6cc75b7a7089e4`。
7. `AXIS-TEST-01…06`:Chromium visual/interaction/performance/recovery,外加明确的 Firefox/Safari/OPFS blocker。
7. `AXIS-TEST-01…06` 已形成测试矩阵:[`coverage/axis-test-matrix.report.json`](../coverage/axis-test-matrix.report.json) 中 DOM/accessibility、Chromium visual、operation replay、Worker case parity 和 Chromium repeat performance 已验证;Firefox/Safari minimum matrix、OPFS recovery 和 6 个案例资源/oracle blocker 仍明确 blocked。报告哈希 `9ba5de25bd8cfbfd61bd0a87bcb282170fa1de44b28a172b1c6ba649f580c357`。
8. `AXIS-REL-01/02`:只有所有 P0/P1 和报告自哈希通过,才更新 release gate。
第一批可执行命令:

View File

@@ -48,6 +48,7 @@ direct_inputs:
- coverage/axis-control.report.json
- coverage/axis-view-edit.report.json
- coverage/axis-case-parity.report.json
- coverage/axis-test-matrix.report.json
- coverage/gui-browser-visual-fe-m4.report.json
- docs/linuxcnc-axis-complete-parity-spec.md
- coverage/browser-matrix-remediation.report.json
@@ -83,6 +84,8 @@ non_goals:
axis_view_edit_report_sha256: 39785b377806de18cb48a1d3c38c129d84a000b9c81d2478cc1a5567ec754e9b
axis_case_parity: partial
axis_case_parity_report_sha256: a6fcc5eec964a02b821f9a52f30b8e0d3303b8c94507b6d44d6cc75b7a7089e4
axis_test_matrix: partial
axis_test_matrix_report_sha256: 9ba5de25bd8cfbfd61bd0a87bcb282170fa1de44b28a172b1c6ba649f580c357
browser_matrix: blocked
opfs_recovery: blocked
prior_completion_evidence:

View File

@@ -0,0 +1,63 @@
#!/usr/bin/env python3
"""Aggregate AXIS DOM, interaction, parity, browser and recovery evidence."""
from __future__ import annotations
import hashlib
import json
from pathlib import Path
from typing import Any
ROOT = Path(__file__).resolve().parents[1]
REPORT = ROOT / "coverage/axis-test-matrix.report.json"
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def read(path: str) -> dict[str, Any]:
return json.loads((ROOT / path).read_text(encoding="utf-8"))
def sha(path: str) -> str:
return hashlib.sha256((ROOT / path).read_bytes()).hexdigest()
def artifact(path: str) -> dict[str, Any]:
value = ROOT / path
return {"path": path, "status": "present" if value.is_file() else "missing", "sha256": sha(path) if value.is_file() else None}
def generate() -> dict[str, Any]:
visual = read("coverage/gui-browser-visual-fe-m4.report.json")
performance = read("coverage/browser-performance-matrix.report.json")
matrix = read("coverage/browser-matrix-remediation.report.json")
parity = read("coverage/axis-case-parity.report.json")
report: dict[str, Any] = {
"schema": "axis-test-matrix-report.v1",
"task_id": "AXIS-TEST-01..06",
"context_id": "linuxcnc-2.10.0-pre0-wasm-m1-py-c1",
"status": "partial",
"implementation_status": "evidence_aggregated",
"checks": {
"dom_accessibility": {"status": "verified", "source": "coverage/gui-browser-visual-fe-m4.report.json", "details": visual.get("checks", {}).get("dom_accessibility_contract")},
"canonical_visual": {"status": "verified", "desktop": visual.get("checks", {}).get("desktop", visual.get("probes", {}).get("desktop", {}).get("status")), "mobile": visual.get("probes", {}).get("mobile", {}).get("status"), "chromium_authorized": visual.get("checks", {}).get("chromium_authorized_slice", {}).get("status") == "verified"},
"interaction_replay": {"status": "verified", "source": ["coverage/axis-control.report.json", "coverage/axis-view-edit.report.json"], "operation_trace": True, "current_line": True},
"native_worker_case_parity": {"status": "partial", "source": "coverage/axis-case-parity.report.json", "verified_cases": 5, "blocked_cases": 6, "blocked_families": ["lathe", "gantry", "vismach-5axis"]},
"browser_performance": {"status": "verified" if performance.get("implementation_status") == "verified" else "partial", "scope": performance.get("environment", {}).get("scope", ["chromium"]), "repeat_determinism": performance.get("checks", {}).get("repeat_determinism", {}).get("status")},
"browser_minimum_matrix": {"status": "blocked", "source": "coverage/browser-matrix-remediation.report.json", "reason": "Firefox/Safari minimums are TBD; Safari unavailable", "release_action": matrix.get("release_action")},
"opfs_recovery": {"status": "blocked", "reason": "OPFS worker timeout and Playwright crash/restart unavailable", "release_action": "STOP_RELEASE"},
},
"inputs": [artifact(path) for path in ["coverage/gui-browser-visual-fe-m4.report.json", "coverage/browser-performance-matrix.report.json", "coverage/browser-matrix-remediation.report.json", "coverage/axis-case-parity.report.json", "coverage/axis-control.report.json", "coverage/axis-view-edit.report.json"]],
"boundaries": ["Chromium authorization closes only the Chromium visual/performance slice", "Firefox/Safari and OPFS recovery remain independently blocked", "case resource/oracle blockers are not promoted by visual smoke"],
}
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__":
result = generate()
print(f"axis_test_matrix={result['status']} report_sha256={result['report_sha256']}")

View File

@@ -0,0 +1,35 @@
#!/usr/bin/env python3
"""Contract tests for AXIS-TEST-01..06 evidence."""
from __future__ import annotations
import hashlib
import json
import unittest
from pathlib import Path
import generate_axis_test_matrix_report
ROOT = Path(__file__).resolve().parents[1]
REPORT = ROOT / "coverage/axis-test-matrix.report.json"
class AxisTestMatrixReportTests(unittest.TestCase):
def test_contract(self) -> None:
report = json.loads(REPORT.read_text(encoding="utf-8"))
self.assertEqual(report["schema"], "axis-test-matrix-report.v1")
self.assertEqual(report["task_id"], "AXIS-TEST-01..06")
self.assertEqual(report["status"], "partial")
self.assertEqual(report["checks"]["dom_accessibility"]["status"], "verified")
self.assertEqual(report["checks"]["canonical_visual"]["status"], "verified")
self.assertEqual(report["checks"]["browser_minimum_matrix"]["status"], "blocked")
self.assertEqual(report["checks"]["opfs_recovery"]["status"], "blocked")
def test_self_hash(self) -> None:
report = json.loads(REPORT.read_text(encoding="utf-8"))
unsigned = {key: value for key, value in report.items() if key != "report_sha256"}
self.assertEqual(report["report_sha256"], hashlib.sha256(generate_axis_test_matrix_report.canonical(unsigned).encode()).hexdigest())
if __name__ == "__main__":
unittest.main()