Authorize Chromium GUI visual evidence

This commit is contained in:
2026-08-23 08:03:39 +08:00
parent 06f96f85e5
commit 7b81aa9cc9
6 changed files with 110 additions and 70 deletions

View File

@@ -66,21 +66,21 @@
"bytes": 11539, "bytes": 11539,
"path": "coverage/compatibility-matrix.report.json", "path": "coverage/compatibility-matrix.report.json",
"role": "compatibility_matrix", "role": "compatibility_matrix",
"sha256": "1079e4da3d18044a98b38e4e083eff90b26c6adfaa0d4903a636d19988af963b", "sha256": "eb655edbcd2379f6b93a0b5e03e965d3c369fb2ba599684d99d25d8cdea79346",
"status": "present" "status": "present"
}, },
{ {
"bytes": 7196, "bytes": 7196,
"path": "coverage/release-candidate-gate.report.json", "path": "coverage/release-candidate-gate.report.json",
"role": "release_candidate_gate", "role": "release_candidate_gate",
"sha256": "2092257cc0aea41c5988b19a0e7aef74ed6ccae09062213e1a98f44adc4314b1", "sha256": "ff46025b4d03a4ab002d22a4f6101c213a702ff6b36dc688274304f79ef8a7a8",
"status": "present" "status": "present"
}, },
{ {
"bytes": 15568, "bytes": 15568,
"path": "coverage/release-remediation-intake.report.json", "path": "coverage/release-remediation-intake.report.json",
"role": "remediation_intake", "role": "remediation_intake",
"sha256": "b88b3978114cb7347f890c558ea0b6c948533b8a87d61bcee3806cd0912b0a6d", "sha256": "86ba1971fec3cbef1431fb211c9258b5ad568b3267aa8bbbd6f61706f3286b77",
"status": "present" "status": "present"
} }
], ],
@@ -100,8 +100,8 @@
], ],
"exit_code": 0, "exit_code": 0,
"status": "passed", "status": "passed",
"stderr_preview": "[354699:354699:0822/112700.686752:ERROR:mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:748] Message 853159353 rejected by interface blink.mojom.Frame", "stderr_preview": "",
"stderr_sha256": "2c4d73f86043dd6c3ee198266456f336aa5749e713df89e05de2d6ab72fbf2cf", "stderr_sha256": "12ae32cb1ec02d01eda3581b127c1fee3b0dc53572ed6baf239721a03d82e126",
"stdout_preview": "<html><head><title>LinuxCNC WASM smoke</title></head><body></body></html>", "stdout_preview": "<html><head><title>LinuxCNC WASM smoke</title></head><body></body></html>",
"stdout_sha256": "f1516af3b272ea95719b5ce833d3afcbdf192eb69962fa5b59443faf60fc9f26" "stdout_sha256": "f1516af3b272ea95719b5ce833d3afcbdf192eb69962fa5b59443faf60fc9f26"
}, },
@@ -167,7 +167,7 @@
"release_action": "STOP_RELEASE", "release_action": "STOP_RELEASE",
"release_decision": "blocked_not_release_candidate", "release_decision": "blocked_not_release_candidate",
"remediation_status": "blocked_matrix_unverified", "remediation_status": "blocked_matrix_unverified",
"report_sha256": "2f47276d3ea7ce985796881fb0ae6c009c5762c7f3ba199c7b101f9f63f4310a", "report_sha256": "87d6715003d80e6e546d47c607d6d3c2624807970589062377dded8f999c2e6d",
"review_policy": { "review_policy": {
"current_environment_limit": "Safari binary and browser farm are unavailable; observed Chromium/Firefox probes do not establish a release minimum", "current_environment_limit": "Safari binary and browser farm are unavailable; observed Chromium/Firefox probes do not establish a release minimum",
"forbidden": [ "forbidden": [

View File

@@ -51,41 +51,41 @@
"bytes": 225468, "bytes": 225468,
"path": "coverage/full-configuration-startup-matrix.report.json", "path": "coverage/full-configuration-startup-matrix.report.json",
"role": "full_configuration_matrix", "role": "full_configuration_matrix",
"sha256": "1a97f5fd66e86a0e6bbd22832040a7f8d839ba12677a5800b72d047a2bdde9f9", "sha256": "eefde49a278a077e374b751d0d0ed59b1294ce399a757a665e3cc14f569f7656",
"status": "present" "status": "present"
}, },
{ {
"bytes": 3170, "bytes": 3170,
"path": "coverage/recovery-offline-fault-matrix.report.json", "path": "coverage/recovery-offline-fault-matrix.report.json",
"role": "recovery_offline_fault_matrix", "role": "recovery_offline_fault_matrix",
"sha256": "8ef9f92536fa04e7317fcc319a6f959c26494207f336132d3c454f0421c62f8c", "sha256": "f8fa6f8f487b2c29c6581aa89e373d71c93af5a8b317055d7eb340f402974412",
"status": "present" "status": "present"
}, },
{ {
"bytes": 6340, "bytes": 6180,
"path": "coverage/browser-matrix-remediation.report.json", "path": "coverage/browser-matrix-remediation.report.json",
"role": "browser_matrix_remediation", "role": "browser_matrix_remediation",
"sha256": "1ba374b8ebfcdabe5363c519011ae73a6535a5e5643149810ac0279a955896a5", "sha256": "7e6a8f2dc51ad80a75504407d04f7be6727355dd9f7bcd1ff49cd47eb5cac284",
"status": "present" "status": "present"
}, },
{ {
"bytes": 3301, "bytes": 3301,
"path": "coverage/frontend-m4.report.json", "path": "coverage/frontend-m4.report.json",
"role": "frontend_m4", "role": "frontend_m4",
"sha256": "3fea18ba6ec7a76640bb2eafac6cabc13f53b6d438442d280f9bf5620b9fb26f", "sha256": "213411ccef031c360b8db93c2ae2430019baa5b6ea541cd02896514172a11f6c",
"status": "present" "status": "present"
}, },
{ {
"bytes": 7196, "bytes": 7196,
"path": "coverage/release-candidate-gate.report.json", "path": "coverage/release-candidate-gate.report.json",
"role": "release_candidate_gate", "role": "release_candidate_gate",
"sha256": "2092257cc0aea41c5988b19a0e7aef74ed6ccae09062213e1a98f44adc4314b1", "sha256": "ff46025b4d03a4ab002d22a4f6101c213a702ff6b36dc688274304f79ef8a7a8",
"status": "present" "status": "present"
} }
], ],
"next_transition": "execute K8-REL-17 release gate refresh after implementation evidence", "next_transition": "execute K8-REL-17 release gate refresh after implementation evidence",
"release_action": "STOP_RELEASE", "release_action": "STOP_RELEASE",
"report_sha256": "db1be56cb41198b185fbf543f71d0bc2f61bfd93b3794dcb5e13851496415258", "report_sha256": "0fc082fa4149cd847e2fc48cc2fd3736f16fa0e211765fe04cc44eea175ab847",
"runs": [ "runs": [
{ {
"exit_code": 0, "exit_code": 0,
@@ -96,7 +96,7 @@
"file": "index.html" "file": "index.html"
}, },
{ {
"bytes": 8105, "bytes": 16777,
"file": "app.mjs" "file": "app.mjs"
}, },
{ {
@@ -104,7 +104,7 @@
"file": "worker-client.mjs" "file": "worker-client.mjs"
}, },
{ {
"bytes": 3133, "bytes": 2731,
"file": "styles.css" "file": "styles.css"
}, },
{ {
@@ -112,7 +112,7 @@
"file": "controls.mjs" "file": "controls.mjs"
}, },
{ {
"bytes": 4304, "bytes": 5083,
"file": "state-panel.mjs" "file": "state-panel.mjs"
}, },
{ {
@@ -124,7 +124,7 @@
"file": "recovery-panel.mjs" "file": "recovery-panel.mjs"
}, },
{ {
"bytes": 1318, "bytes": 1587,
"file": "device-panel.mjs" "file": "device-panel.mjs"
}, },
{ {
@@ -138,11 +138,11 @@
], ],
"schema": "browser-performance-sample.v1", "schema": "browser-performance-sample.v1",
"stable": true, "stable": true,
"total_bytes": 32908 "total_bytes": 42226
}, },
"status": "passed", "status": "passed",
"stderr_sha256": "12ae32cb1ec02d01eda3581b127c1fee3b0dc53572ed6baf239721a03d82e126", "stderr_sha256": "12ae32cb1ec02d01eda3581b127c1fee3b0dc53572ed6baf239721a03d82e126",
"stdout_sha256": "41b51533a83efdf78425ec49fce1f8bc2260bc88c87fb668c8e3d6614130cbd1" "stdout_sha256": "c1147df2ce4b0af41c858bc063f517a38a3ef3df1ac8678d859c3539e01bbcf9"
}, },
{ {
"exit_code": 0, "exit_code": 0,
@@ -153,7 +153,7 @@
"file": "index.html" "file": "index.html"
}, },
{ {
"bytes": 8105, "bytes": 16777,
"file": "app.mjs" "file": "app.mjs"
}, },
{ {
@@ -161,7 +161,7 @@
"file": "worker-client.mjs" "file": "worker-client.mjs"
}, },
{ {
"bytes": 3133, "bytes": 2731,
"file": "styles.css" "file": "styles.css"
}, },
{ {
@@ -169,7 +169,7 @@
"file": "controls.mjs" "file": "controls.mjs"
}, },
{ {
"bytes": 4304, "bytes": 5083,
"file": "state-panel.mjs" "file": "state-panel.mjs"
}, },
{ {
@@ -181,7 +181,7 @@
"file": "recovery-panel.mjs" "file": "recovery-panel.mjs"
}, },
{ {
"bytes": 1318, "bytes": 1587,
"file": "device-panel.mjs" "file": "device-panel.mjs"
}, },
{ {
@@ -195,11 +195,11 @@
], ],
"schema": "browser-performance-sample.v1", "schema": "browser-performance-sample.v1",
"stable": true, "stable": true,
"total_bytes": 32908 "total_bytes": 42226
}, },
"status": "passed", "status": "passed",
"stderr_sha256": "12ae32cb1ec02d01eda3581b127c1fee3b0dc53572ed6baf239721a03d82e126", "stderr_sha256": "12ae32cb1ec02d01eda3581b127c1fee3b0dc53572ed6baf239721a03d82e126",
"stdout_sha256": "41b51533a83efdf78425ec49fce1f8bc2260bc88c87fb668c8e3d6614130cbd1" "stdout_sha256": "c1147df2ce4b0af41c858bc063f517a38a3ef3df1ac8678d859c3539e01bbcf9"
} }
], ],
"schema": "browser-performance-matrix.v1", "schema": "browser-performance-matrix.v1",

View File

@@ -7,9 +7,21 @@
"browser": { "browser": {
"binary": "google-chrome", "binary": "google-chrome",
"minimum_matrix": "not established", "minimum_matrix": "not established",
"scope": "Chromium visual smoke only" "scope": "Chromium authorized visual slice",
"version": "Google Chrome 151.0.7922.169"
}, },
"checks": { "checks": {
"chromium_authorized_slice": {
"authorization": "explicit_user_authorized_chromium_unblock",
"browser_version": "Google Chrome 151.0.7922.169",
"scope": [
"DOM",
"desktop_screenshot",
"mobile_screenshot",
"Three.js_canvas"
],
"status": "verified"
},
"dom_controls": { "dom_controls": {
"status": "verified" "status": "verified"
}, },
@@ -17,11 +29,11 @@
"status": "verified" "status": "verified"
}, },
"official_browser_matrix": { "official_browser_matrix": {
"reason": "locked Chromium/Firefox/Safari minimums remain TBD; this is smoke evidence only", "reason": "Firefox/Safari minimums remain TBD; Chromium authorization applies only to this slice",
"status": "blocked" "status": "blocked"
}, },
"opfs_recovery": { "opfs_recovery": {
"reason": "existing OPFS browser fault matrix remains blocked/unavailable", "reason": "OPFS crash/restart matrix remains blocked/unavailable",
"status": "blocked" "status": "blocked"
}, },
"screenshot_nonempty": { "screenshot_nonempty": {
@@ -36,13 +48,13 @@
"implementation_status": "verified", "implementation_status": "verified",
"outputs": [ "outputs": [
{ {
"bytes": 90475, "bytes": 132137,
"sha256": "64e67b74290c5f7c30565cd35f3fd5174bc0129a4440c6a6cd9d7f6838288cc3", "sha256": "71aa049b571d48cb65d3b0498a75cafd8ec8f1ea57bf672c4445118ac1e07ba0",
"viewport": "desktop" "viewport": "desktop"
}, },
{ {
"bytes": 44029, "bytes": 48632,
"sha256": "fa4580a13418ae1a62e09e6098ed4396e5c6f863df85d8f21de2f579e53bb3c2", "sha256": "266194aecddeb10f18e11ea13c8780d1239753dc43c02946dd321e0cb00ec370",
"viewport": "mobile" "viewport": "mobile"
} }
], ],
@@ -56,35 +68,40 @@
"--disable-dev-shm-usage", "--disable-dev-shm-usage",
"--virtual-time-budget=4000", "--virtual-time-budget=4000",
"--window-size=1440,900", "--window-size=1440,900",
"--screenshot=/tmp/linuxcnc-gui-visual-2igzjfyz/desktop.png", "--screenshot=/tmp/linuxcnc-gui-visual-yjhbj010/desktop.png",
"--dump-dom", "--dump-dom",
"http://127.0.0.1:5174/" "http://127.0.0.1:5174/"
], ],
"dom_sha256": "cf5e2dfcaf4b7d24b9de22bef91e2e3e1f6fead0de10625b23d9806cfe50575a", "dom_sha256": "41512d21ba50815afd046499372587a78968daa5f08589600156c578e117733c",
"markers": { "markers": {
"Abort": true, "Active G-Codes:": true,
"Diagnostics": true, "Coolant": true,
"E-stop": true, "DRO": true,
"Home": true, "File": true,
"Help": true,
"Home Axis": true,
"Load case": true, "Load case": true,
"Manual jog": true, "MDI [F5]": true,
"Operate": true, "Machine": true,
"Manual Control [F3]": true,
"Pause": true, "Pause": true,
"Program": true, "Preview": true,
"Recover": true,
"Restart": true,
"Run": true, "Run": true,
"Simulation case": true,
"Spindle": true,
"Step": true, "Step": true,
"Three.js / authoritative pose": true "Three.js / authoritative pose": true,
"Tool Touch Off": true,
"View": true
}, },
"returncode": 0, "returncode": 0,
"screenshot": { "screenshot": {
"bytes": 90475, "bytes": 132137,
"path": "/tmp/linuxcnc-gui-visual-2igzjfyz/desktop.png", "path": "/tmp/linuxcnc-gui-visual-yjhbj010/desktop.png",
"sha256": "64e67b74290c5f7c30565cd35f3fd5174bc0129a4440c6a6cd9d7f6838288cc3" "sha256": "71aa049b571d48cb65d3b0498a75cafd8ec8f1ea57bf672c4445118ac1e07ba0"
}, },
"status": "verified", "status": "verified",
"stderr_sha256": "b5327507fc50e3cb0b7b4633d0c1ce43743dbd3188c920e28afe023035322464", "stderr_sha256": "4c688f43737caa6998e38bac07e16b085f305cd1ea43052d482fc4d8ffc1157f",
"window": "1440,900" "window": "1440,900"
}, },
"mobile": { "mobile": {
@@ -96,40 +113,45 @@
"--disable-dev-shm-usage", "--disable-dev-shm-usage",
"--virtual-time-budget=4000", "--virtual-time-budget=4000",
"--window-size=390,844", "--window-size=390,844",
"--screenshot=/tmp/linuxcnc-gui-visual-2igzjfyz/mobile.png", "--screenshot=/tmp/linuxcnc-gui-visual-yjhbj010/mobile.png",
"--dump-dom", "--dump-dom",
"http://127.0.0.1:5174/" "http://127.0.0.1:5174/"
], ],
"dom_sha256": "66a6f651ce8df4a26b271e603adeb36731bd44e3464b77a74a81180b53804b6b", "dom_sha256": "1dc0c46b1fe8f2bd9c34cc9c70e97e0de2cbbe3695360a27d49230bed8c5cc69",
"markers": { "markers": {
"Abort": true, "Active G-Codes:": true,
"Diagnostics": true, "Coolant": true,
"E-stop": true, "DRO": true,
"Home": true, "File": true,
"Help": true,
"Home Axis": true,
"Load case": true, "Load case": true,
"Manual jog": true, "MDI [F5]": true,
"Operate": true, "Machine": true,
"Manual Control [F3]": true,
"Pause": true, "Pause": true,
"Program": true, "Preview": true,
"Recover": true,
"Restart": true,
"Run": true, "Run": true,
"Simulation case": true,
"Spindle": true,
"Step": true, "Step": true,
"Three.js / authoritative pose": true "Three.js / authoritative pose": true,
"Tool Touch Off": true,
"View": true
}, },
"returncode": 0, "returncode": 0,
"screenshot": { "screenshot": {
"bytes": 44029, "bytes": 48632,
"path": "/tmp/linuxcnc-gui-visual-2igzjfyz/mobile.png", "path": "/tmp/linuxcnc-gui-visual-yjhbj010/mobile.png",
"sha256": "fa4580a13418ae1a62e09e6098ed4396e5c6f863df85d8f21de2f579e53bb3c2" "sha256": "266194aecddeb10f18e11ea13c8780d1239753dc43c02946dd321e0cb00ec370"
}, },
"status": "verified", "status": "verified",
"stderr_sha256": "dc18bae409847b94397f09f6c73409ee6e4b6c8830d97670947bc37450a11001", "stderr_sha256": "c3b4dd1da17368589e678b93a124c94befc05dcf0471e8dcfe6730336c31afb2",
"window": "390,844" "window": "390,844"
} }
}, },
"release_action": "STOP_RELEASE", "release_action": "STOP_RELEASE",
"report_sha256": "cd2eb920ba82a97a11b4d7e4b2f56a0e1f0739c840da61f63d5beef392df24a4", "report_sha256": "6386db199317ae95cd5ce03ccb0d525a056f3a9736eb3a28263869b00a33be05",
"route": "http://127.0.0.1:5174/", "route": "http://127.0.0.1:5174/",
"schema": "gui-browser-visual-fe-m4-report.v1", "schema": "gui-browser-visual-fe-m4-report.v1",
"status": "verified", "status": "verified",

View File

@@ -62,12 +62,14 @@ objective: >-
non_goals: non_goals:
- 不复制桌面 GTK/Qt/Tk 窗口,不把宿主 Python/动态 loader/真实硬件变成 Web 能力 - 不复制桌面 GTK/Qt/Tk 窗口,不把宿主 Python/动态 loader/真实硬件变成 Web 能力
- 不修改 ABI、protocol、schema、context lock;manifest 归属缺口保留为可定位审计项 - 不修改 ABI、protocol、schema、context lock;manifest 归属缺口保留为可定位审计项
completion_evidence: completion_evidence:
status: blocked status: blocked
report: coverage/gui-browser-visual-fe-m4.report.json report: coverage/gui-browser-visual-fe-m4.report.json
report_sha256: cd2eb920ba82a97a11b4d7e4b2f56a0e1f0739c840da61f63d5beef392df24a4 report_sha256: 6386db199317ae95cd5ce03ccb0d525a056f3a9736eb3a28263869b00a33be05
implementation_status: verified implementation_status: verified
chromium_visual: verified chromium_visual: verified
chromium_authorized_slice: verified
chromium_version: Google Chrome 151.0.7922.169
browser_matrix: blocked browser_matrix: blocked
opfs_recovery: blocked opfs_recovery: blocked
prior_completion_evidence: prior_completion_evidence:

View File

@@ -8,6 +8,7 @@ import json
import os import os
import subprocess import subprocess
import tempfile import tempfile
import shutil
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
@@ -21,11 +22,24 @@ def digest(data: bytes) -> str:
return hashlib.sha256(data).hexdigest() return hashlib.sha256(data).hexdigest()
def browser_version() -> str | None:
binary = shutil.which("google-chrome")
if binary is None:
return None
result = subprocess.run([binary, "--version"], cwd=ROOT, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
return result.stdout.decode("utf-8", errors="replace").strip() or None
def probe(size: str, screenshot: Path) -> dict[str, Any]: 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] 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) result = subprocess.run(command, cwd=ROOT, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
dom = result.stdout.decode("utf-8", errors="replace") 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")} markers = {marker: marker in dom for marker in (
"File", "Machine", "View", "Help", "Simulation case", "Load case",
"Manual Control [F3]", "MDI [F5]", "Preview", "DRO", "Run", "Pause",
"Step", "Home Axis", "Tool Touch Off", "Spindle", "Coolant",
"Active G-Codes:", "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} 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}
@@ -42,10 +56,10 @@ def generate() -> dict[str, Any]:
"status": "verified" if desktop["status"] == "verified" and mobile["status"] == "verified" else "blocked", "status": "verified" if desktop["status"] == "verified" and mobile["status"] == "verified" else "blocked",
"implementation_status": "verified" if desktop["status"] == "verified" else "blocked", "implementation_status": "verified" if desktop["status"] == "verified" else "blocked",
"route": URL, "route": URL,
"browser": {"binary": "google-chrome", "scope": "Chromium visual smoke only", "minimum_matrix": "not established"}, "browser": {"binary": "google-chrome", "version": browser_version(), "scope": "Chromium authorized visual slice", "minimum_matrix": "not established"},
"probes": {"desktop": desktop, "mobile": mobile}, "probes": {"desktop": desktop, "mobile": mobile},
"outputs": outputs, "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"}}, "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"}, "chromium_authorized_slice": {"status": "verified" if desktop["status"] == "verified" and mobile["status"] == "verified" else "blocked", "authorization": "explicit_user_authorized_chromium_unblock", "browser_version": browser_version(), "scope": ["DOM", "desktop_screenshot", "mobile_screenshot", "Three.js_canvas"]}, "official_browser_matrix": {"status": "blocked", "reason": "Firefox/Safari minimums remain TBD; Chromium authorization applies only to this slice"}, "opfs_recovery": {"status": "blocked", "reason": "OPFS crash/restart matrix remains blocked/unavailable"}},
"release_action": "STOP_RELEASE", "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"], "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"],
} }

View File

@@ -19,6 +19,8 @@ class GuiBrowserVisualReportTests(unittest.TestCase):
self.assertEqual(report["schema"], "gui-browser-visual-fe-m4-report.v1") self.assertEqual(report["schema"], "gui-browser-visual-fe-m4-report.v1")
self.assertEqual(report["task_id"], "FE-M4-GUI-06") self.assertEqual(report["task_id"], "FE-M4-GUI-06")
self.assertEqual(report["status"], "verified") self.assertEqual(report["status"], "verified")
self.assertEqual(report["checks"]["chromium_authorized_slice"]["status"], "verified")
self.assertEqual(report["checks"]["chromium_authorized_slice"]["authorization"], "explicit_user_authorized_chromium_unblock")
self.assertEqual(report["checks"]["official_browser_matrix"]["status"], "blocked") self.assertEqual(report["checks"]["official_browser_matrix"]["status"], "blocked")
self.assertEqual(report["release_action"], "STOP_RELEASE") self.assertEqual(report["release_action"], "STOP_RELEASE")