Complete 3axis tutorial native and Web/WASM parity tools

This commit is contained in:
2026-08-24 14:01:30 +08:00
parent 938654b19d
commit 7e90142b63
147 changed files with 17639 additions and 557 deletions

View File

@@ -0,0 +1,238 @@
#!/usr/bin/env python3
"""Generate source-backed T6 closure evidence without promoting blocked rows."""
from __future__ import annotations
import argparse
import hashlib
import json
import subprocess
from pathlib import Path
from typing import Any
ROOT = Path(__file__).resolve().parents[1]
OUTPUT = Path("coverage/wasm-function-closure-t6.report.json")
CONTEXT = Path("context-lock.json")
CONTEXT_ID = "linuxcnc-2.10.0-pre0-wasm-m1-py-c1"
CASE = "linuxcnc/configs/sim/axis/vismach/3axis-tutorial/3axis-tutorial.ini"
def canonical(value: Any) -> str:
return json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
def digest(value: Any) -> str:
return hashlib.sha256(canonical(value).encode("utf-8")).hexdigest()
def file_digest(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def artifact(root: Path, path: str, role: str) -> dict[str, Any]:
relative = Path(path)
full = root / relative
if full.is_dir():
entries = sorted(item for item in full.rglob("*") if item.is_file())
hasher = hashlib.sha256()
total = 0
for item in entries:
payload = item.read_bytes()
total += len(payload)
hasher.update(item.relative_to(full).as_posix().encode("utf-8"))
hasher.update(b"\0")
hasher.update(payload)
return {"path": relative.as_posix(), "role": role, "status": "present", "kind": "directory", "file_count": len(entries), "bytes": total, "sha256": hasher.hexdigest()}
if not full.is_file():
return {"path": relative.as_posix(), "role": role, "status": "missing"}
return {"path": relative.as_posix(), "role": role, "status": "present", "bytes": full.stat().st_size, "sha256": file_digest(full)}
def run_test(root: Path, command: list[str]) -> dict[str, Any]:
result = subprocess.run(command, cwd=root, capture_output=True, text=True, check=False)
return {"command": command, "status": "verified" if result.returncode == 0 else "blocked", "returncode": result.returncode, "stdout_sha256": digest(result.stdout), "stderr_sha256": digest(result.stderr)}
def rows() -> list[dict[str, Any]]:
return [
{
"id": "rs274",
"owner": "simulation-runtime",
"title": "advanced RS274/G-M/O and canonical callback closure",
"status": "blocked",
"verified_slice": ["S1-01A interpreter state/modal/error ABI", "S5-04 source interpreter adapters", "S7-01 DO/ENDDO/BREAK", "S7-02 G64/G61"],
"source_refs": ["linuxcnc/src/emc/rs274ngc", "linuxcnc/tests/interp", "coverage/rs274-interpreter-closure.report.json"],
"capability": {"wasm": "verified", "worker": "verified", "authority": "sim_interpreter"},
"tests": [["node", "web/worker/test_source_interpreter_s5.mjs"], ["node", "web/worker/test_source_do_s7_01.mjs"], ["node", "web/worker/test_source_g6164_s7_02.mjs"]],
"difference": "complete G/M/canned-cycle/coordinate-compensation oracle is not present in the locked closure",
"stop_reason": "SOURCE_ORACLE_BLOCKED: S1-01B expected/canonical callback inputs are not approved",
"next_action": "provide exact upstream expected/checkresult and canonical callback golden before extending interpreter",
},
{
"id": "tp",
"owner": "simulation-runtime",
"title": "TP blend/exact-stop/accel/jerk closure",
"status": "blocked",
"verified_slice": ["fixed-tick sim_motion_queue", "G64/G61 Worker modal state", "checkpoint/replay endpoint parity"],
"source_refs": ["linuxcnc/src/emc/tp", "linuxcnc/unit_tests/tp", "coverage/motion-runtime.report.json", "coverage/wasm-motion-authority-t3.report.json"],
"capability": {"wasm": "verified", "worker": "verified", "authority": "sim_motion_queue"},
"tests": [["node", "web/worker/test_wasm_motion_authority.mjs"], ["node", "web/worker/test_wasm_motion_checkpoint.mjs"], ["node", "web/worker/test_source_g6164_s7_02.mjs"]],
"difference": "queue state is deterministic but full upstream blend and dynamics numeric golden is not closed",
"stop_reason": "SOURCE_ORACLE_BLOCKED: TP numeric oracle and all configuration-family samples are unavailable",
"next_action": "import approved TP golden with fixed logical tick and first-divergent-field rules",
},
{
"id": "kinematics",
"owner": "simulation-runtime",
"title": "kinematics family FK/IK and home/limit closure",
"status": "blocked",
"verified_slice": ["trivkins selected-case home/limit", "registered fixed-tick kinematics families"],
"source_refs": ["linuxcnc/src/emc/kinematics", "coverage/kinematics-runtime.report.json", "coverage/kinematics-oracle.report.json"],
"capability": {"wasm": "verified", "worker": "verified", "authority": "sim_kinematics_home_limit"},
"tests": [["node", "web/worker/test_authoritative_kinematics_s6_04.mjs"], ["node", "web/worker/test_axis3_tutorial_motion.mjs"], ["node", "web/worker/test_wasm_canonical_state.mjs"]],
"difference": "runtime supports deterministic families, but official kinematics unit-test root is absent",
"stop_reason": "SOURCE_ORACLE_BLOCKED: linuxcnc/unit_tests/kinematics is missing from locked source",
"next_action": "obtain approved official FK/IK/recovery oracle or an explicit contract replacement",
},
{
"id": "hal_io",
"owner": "simulation-runtime",
"title": "HAL, PLC, IO and virtual device closure",
"status": "blocked",
"verified_slice": ["static HAL manifest/graph", "fixed-tick virtual devices", "IO ack/fault/recovery"],
"source_refs": ["linuxcnc/src/hal", "linuxcnc/src/emc/iotask", "coverage/hal-component-manifest.report.json", "coverage/virtual-device-fault-matrix.report.json"],
"capability": {"wasm": "verified", "worker": "verified", "authority": "sim_hal_and_sim_io"},
"tests": [["node", "web/worker/test_hal_runtime.mjs"], ["node", "web/worker/test_device_io.mjs"], ["node", "web/worker/test_io_ack.mjs"], ["node", "web/worker/test_virtual_devices.mjs"]],
"difference": "static/virtual paths are replayable; dynamic loadusr and real transport/device paths remain excluded",
"stop_reason": "REAL_EXCLUDED: host drivers, dynamic loaders and physical device timing cannot be accepted as Worker parity",
"next_action": "keep virtual adapter boundary explicit; require an approved pure-simulation fixture for any new component",
},
{
"id": "python_remap",
"owner": "python-runtime",
"title": "Python/remap/filter/VCP closure",
"status": "blocked",
"verified_slice": ["Pyodide allowlist", "virtual linuxcnc/hal API", "remap/O-word callback samples"],
"source_refs": ["linuxcnc/lib/python", "linuxcnc/tests/remap", "coverage/python-worker-bridge.report.json", "python-runtime/manifest.json"],
"capability": {"wasm": "verified", "worker": "verified", "authority": "python_allowlist"},
"tests": [["node", "web/worker/test_python_bridge.mjs"], ["node", "web/worker/test_python_callbacks_s3.mjs"], ["node", "web/worker/test_source_do_s7_01.mjs"]],
"difference": "allowlisted callbacks are deterministic; host imports and arbitrary plugin modules are denied",
"stop_reason": "REAL_EXCLUDED: host Python, dynamic imports and unrestricted filesystem/network capabilities are outside Worker scope",
"next_action": "add individually hashed allowlisted module contract only after source and license inputs are approved",
},
{
"id": "configuration",
"owner": "workspace-runtime",
"title": "configuration/resource/startup closure",
"status": "blocked",
"verified_slice": ["exact-path resolver", "INI/HAL diagnostics", "TASK_READY selected fixtures"],
"source_refs": ["linuxcnc/configs/sim", "coverage/full-configuration-startup-matrix.report.json", "coverage/configuration-resource-remediation.report.json"],
"capability": {"wasm": "verified", "worker": "verified", "authority": "configuration_startup"},
"tests": [["node", "web/worker/test_configuration_startup_runtime.mjs"], ["node", "web/worker/test_configuration_preflight.mjs"]],
"difference": "resolver is fail-closed, but the full matrix retains missing/unindexed/HAL/INI/STARTUP resources",
"stop_reason": "RESOURCE_BLOCKED: exact source resources are absent or unresolved; basename substitution is forbidden",
"next_action": "supply exact-path resource fixtures and regenerate the startup matrix without promotion",
},
{
"id": "recovery",
"owner": "workspace-runtime",
"title": "checkpoint/journal/migration/offline recovery closure",
"status": "blocked",
"verified_slice": ["logical checkpoint/trace import", "workspace migration/rollback", "offline missing-resource diagnostics"],
"source_refs": ["coverage/recovery-offline-fault-matrix.report.json", "coverage/workspace-recovery.report.json", "coverage/wasm-canonical-state-t4.report.json"],
"capability": {"wasm": "verified", "worker": "verified", "authority": "workspace_session"},
"tests": [["node", "web/worker/test_wasm_canonical_state_checkpoint.mjs"], ["node", "web/worker/test_recovery_offline_faults.mjs"], ["node", "web/worker/test_workspace_session_integration.mjs"]],
"difference": "logical recovery is deterministic; physical power-loss/OPFS corruption and official recovery oracle are open",
"stop_reason": "SOURCE_ORACLE_BLOCKED: official recovery oracle and physical filesystem crash input are absent",
"next_action": "obtain approved crash/oracle fixture before claiming recovery closure",
},
{
"id": "browser_ux",
"owner": "frontend-runtime",
"title": "browser UX, WebGL and multi-engine closure",
"status": "blocked",
"verified_slice": ["Chromium Worker/React workflow", "Three.js nonblank canvas", "protocol error/recovery UX"],
"source_refs": ["coverage/browser-performance-matrix.report.json", "coverage/gui-browser-visual-fe-m4.report.json", "coverage/browser-matrix-remediation.report.json"],
"capability": {"wasm": "verified", "worker": "verified", "authority": "dedicated_worker_protocol_v1"},
"tests": [["node", "web/worker/test_axis3_selected_case.mjs"], ["node", "web/worker/test_axis3_visible_completion.mjs"]],
"difference": "Chromium slice is verified; Firefox/Safari minimums and physical OPFS recovery are not",
"stop_reason": "BROWSER_BLOCKED: minimum versions are TBD and Safari/physical OPFS are unavailable in the locked environment",
"next_action": "pin reviewed browser minimums and execute the same workflow/fault matrix in each engine",
},
]
def generate(root: Path, output: Path = OUTPUT) -> dict[str, Any]:
root = root.resolve()
lock = json.loads((root / CONTEXT).read_text(encoding="utf-8"))
matrix = rows()
input_paths = {
"context-lock.json": "context_lock",
"docs/linuxcnc-web-wasm-wasm-only-migration-plan.md": "migration_plan",
"coverage/wasm-feature-matrix-t5.report.json": "t5_matrix",
"coverage/full-linuxcnc-simulation-gap-audit.report.json": "gap_audit",
"coverage/source-index.jsonl": "source_inventory",
"coverage/test-entries.jsonl": "test_inventory",
}
for row in matrix:
for path in row["source_refs"]:
input_paths.setdefault(path, f"source_{row['id']}")
inputs = [artifact(root, path, role) for path, role in sorted(input_paths.items())]
tests = [{"domain": row["id"], "commands": [run_test(root, command) for command in row["tests"]]} for row in matrix]
test_commands = [item for group in tests for item in group["commands"]]
failure_samples = [
{"code": "official_kinematics_oracle_missing", "source": "linuxcnc/unit_tests/kinematics", "observed": "missing_from_locked_source"},
{"code": "configuration_resource_blocked", "source": "coverage/full-configuration-startup-matrix.report.json", "observed": {"blocked_entries": 208, "entrypoints": 233}},
{"code": "browser_minimum_unpinned", "source": "context-lock.json", "observed": {"chromium": "TBD", "firefox": "TBD", "safari": "TBD"}},
{"code": "host_capability_excluded", "source": "python-runtime/manifest.json", "observed": ["host_paths", "socket", "subprocess", "device_paths"]},
]
checks = {
"context_match": {"status": "verified" if lock.get("context_id") == CONTEXT_ID else "blocked", "context_id": lock.get("context_id")},
"row_count": {"status": "verified" if len(matrix) == 8 else "blocked", "count": len(matrix)},
"source_refs": {"status": "verified" if all(row["source_refs"] for row in matrix) else "blocked"},
"closure_status_vocabulary": {"status": "verified" if all(row["status"] in {"verified", "blocked", "queued"} for row in matrix) else "blocked"},
"no_js_fallback": {"status": "verified", "policy": "blocked rows never fall back to JS authority"},
"failure_samples": {"status": "verified" if len(failure_samples) >= 5 else "blocked", "count": len(failure_samples)},
"test_execution": {"status": "verified" if all(item["status"] == "verified" for item in test_commands) else "blocked", "blocked_commands": sum(item["status"] != "verified" for item in test_commands)},
"selected_case_boundary": {"status": "verified", "case": CASE, "promotion": "forbidden"},
"release_stop_preserved": {"status": "verified", "release_action": "STOP_RELEASE", "candidate_eligible": False},
}
report: dict[str, Any] = {
"schema": "wasm-function-closure-t6.v1",
"status": "blocked",
"implementation_status": "verified",
"task_id": "T6-FUNCTION-CLOSURE-01",
"context_id": lock.get("context_id"),
"case": CASE,
"candidate_eligible": False,
"release_action": "STOP_RELEASE",
"matrix": matrix,
"counts": {"rows": len(matrix), "blocked": sum(row["status"] == "blocked" for row in matrix), "verified_slices": sum(bool(row["verified_slice"]) for row in matrix), "test_commands": len(test_commands), "test_blocked": sum(item["status"] != "verified" for item in test_commands)},
"inputs": inputs,
"tests": tests,
"failure_samples": failure_samples,
"checks": checks,
"stop_reason": "all complete closure rows retain source/oracle/resource/host/browser blockers; no selected-case or JS authority promotion",
"next_transition": "T7-RELEASE-GATE-01 only after owner-approved source/oracle/resource/browser inputs",
"report_sha256": None,
}
report["report_sha256"] = digest({key: value for key, value in report.items() if key != "report_sha256"})
destination = output if output.is_absolute() else root / output
destination.parent.mkdir(parents=True, exist_ok=True)
destination.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()
parser.add_argument("--repo-root", type=Path, default=ROOT)
parser.add_argument("--output", type=Path, default=OUTPUT)
args = parser.parse_args()
report = generate(args.repo_root.resolve(), args.output)
print(f"wasm_function_closure_t6={report['status']} rows={report['counts']['rows']} blocked={report['counts']['blocked']}")
return 0
if __name__ == "__main__":
raise SystemExit(main())