From 00d97fc2d4fe743f79316388fdf2c0b521815fed Mon Sep 17 00:00:00 2001 From: wangdequan Date: Sun, 23 Aug 2026 10:12:09 +0800 Subject: [PATCH] Record AXIS browser and parity test matrix --- coverage/axis-test-matrix.report.json | 114 ++++++++++++++++++++ docs/linuxcnc-axis-complete-parity-spec.md | 2 +- nextTask1.md | 3 + scripts/generate_axis_test_matrix_report.py | 63 +++++++++++ scripts/test_axis_test_matrix_report.py | 35 ++++++ 5 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 coverage/axis-test-matrix.report.json create mode 100644 scripts/generate_axis_test_matrix_report.py create mode 100644 scripts/test_axis_test_matrix_report.py diff --git a/coverage/axis-test-matrix.report.json b/coverage/axis-test-matrix.report.json new file mode 100644 index 0000000..fca6db6 --- /dev/null +++ b/coverage/axis-test-matrix.report.json @@ -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" +} diff --git a/docs/linuxcnc-axis-complete-parity-spec.md b/docs/linuxcnc-axis-complete-parity-spec.md index 649cc4b..961b01b 100644 --- a/docs/linuxcnc-axis-complete-parity-spec.md +++ b/docs/linuxcnc-axis-complete-parity-spec.md @@ -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。 第一批可执行命令: diff --git a/nextTask1.md b/nextTask1.md index c5ed9a7..166f9a0 100644 --- a/nextTask1.md +++ b/nextTask1.md @@ -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: diff --git a/scripts/generate_axis_test_matrix_report.py b/scripts/generate_axis_test_matrix_report.py new file mode 100644 index 0000000..29e50e8 --- /dev/null +++ b/scripts/generate_axis_test_matrix_report.py @@ -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']}") diff --git a/scripts/test_axis_test_matrix_report.py b/scripts/test_axis_test_matrix_report.py new file mode 100644 index 0000000..ee56c64 --- /dev/null +++ b/scripts/test_axis_test_matrix_report.py @@ -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()