# Compatibility Validation ## Purpose This document records how the standalone LinuxCNC WASM port currently proves that migrated behavior remains tied to LinuxCNC source code and fixture semantics. The primary native validation command is: ```bash wasm-port/tests/native/verify_native_probes.sh ``` The native LinuxCNC `nc_files` basic/example validation command is: ```bash wasm-port/tests/native/verify_nc_files.sh ``` The current WASM smoke validation command is: ```bash wasm-port/tests/wasm/node/verify_ini_wasm.sh ``` The current WASM interpreter-core smoke validation command is: ```bash wasm-port/tests/wasm/node/verify_interp_wasm.sh ``` The current WASM sim-config smoke validation command is: ```bash wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh ``` The current WASM sim-config inventory validation command is: ```bash wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh ``` The current WASM `nc_files` smoke validation command is: ```bash wasm-port/tests/wasm/node/verify_nc_files_wasm.sh ``` The current WASM trajectory-planner smoke validation command is: ```bash wasm-port/tests/wasm/node/verify_tp_wasm.sh ``` The current OPFS host-boundary validation command is: ```bash wasm-port/tests/opfs/node/verify_file_service.sh ``` The current browser smoke validation command is: ```bash wasm-port/tests/browser/verify_ini_panel_browser.sh ``` The current browser interpreter smoke validation command is: ```bash wasm-port/tests/browser/verify_interp_browser.sh ``` The current aggregate host/WASM/browser smoke command is: ```bash wasm-port/tests/host/verify_host_smokes.sh ``` ## Validation Layers Use these layers when deciding where a LinuxCNC asset belongs. Do not widen a later layer until the narrower layer has either passed or recorded an explicit expected boundary. | Layer | Scope | Entry command | Current result | Expected boundary | | --- | --- | --- | --- | --- | | 1 | `linuxcnc/nc_files` basic G-code smoke | `wasm-port/tests/native/verify_nc_files.sh` | `total: 107`, `pass: 101`, `expected_fail: 6`, `unexpected_fail: 0` | LinuxCNC-native entry-point/context edges only: W-axis machine context, lathe tool/cutter-comp context, upstream O-word syntax edge, and probe runtime context. | | 2 | `linuxcnc/configs/sim` native strict harness | `wasm-port/tests/native/verify_sim_configs.sh` | `total: 159`, `pass: 151`, `expected_fail: 8`, `unexpected_fail: 0` | Native `bin/rs274` cannot provide task/user-M process execution or some INI axis-mask/runtime context. The upstream `incremental_repetition_g533.ngc` demo remains an expected upstream demo edge and must not be made pass by changing G-code semantics. | | 3 | Standalone native runtime probes | `wasm-port/tests/native/verify_native_probes.sh` | Passes with `native probes complete` after source sync, no-standalone-semantics, fixture baseline, sim-config, and `nc_files` checks | Runtime adapters may cover filesystem, HAL/user-M, remap, parameter, tool, kinematics, TP, and WASM/browser boundary behavior, but CNC semantics must still come from vendored LinuxCNC source. | | 4 | WASM Node/browser representative smoke | `wasm-port/tests/host/verify_host_smokes.sh` plus targeted Node/browser commands below | Current targeted checks pass with `sim_configs_wasm_node_smoke=ok`, `nc_files_wasm_node_smoke=ok`, `browser_interp_smoke=ok`, `browser_ini_opfs_smoke=ok`, and aggregate `host_wasm_opfs_browser_smokes=ok` | JS/browser code may stage files, apply executable bits, persist OPFS text, and forward paths to C ABI calls. It must not implement G-code, remap, tool-table, parameter, planner, kinematics, or user-M semantics. | Layer 4 is made of focused smoke commands so failures can be isolated before running the aggregate host check: ```bash wasm-port/tests/wasm/node/verify_ini_wasm.sh wasm-port/tests/wasm/node/verify_interp_wasm.sh wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh wasm-port/tests/wasm/node/verify_nc_files_wasm.sh wasm-port/tests/wasm/node/verify_tp_wasm.sh wasm-port/tests/opfs/node/verify_file_service.sh wasm-port/tests/browser/verify_ini_panel_browser.sh wasm-port/tests/browser/verify_interp_browser.sh wasm-port/tests/host/verify_host_smokes.sh ``` Layer 4 INI-context staging uses `planIniFileContextStaging()` to collect INI-declared `[DISPLAY]OPEN_FILE`, `[EMCIO]TOOL_TABLE`, `[RS274NGC]PARAMETER_FILE`, `[RS274NGC]SUBROUTINE_PATH`, `[RS274NGC]USER_M_PATH`, and remap-NGC files from the vendored source manifest without browser directory enumeration. `planSimConfigStaging()` is the `configs/sim` wrapper around that generic planner. These planners are host filesystem helpers only; execution still goes through vendored LinuxCNC interpreter/remap/tool/parameter code. Layer responsibilities are intentionally narrow: | Layer | LinuxCNC-owned behavior | Host/WASM adapter allowance | Expected-failure policy | | --- | --- | --- | --- | | 1 | `nc_files` parsing and execution through upstream `rs274` | Generate only the native harness INI/tool-table context needed to classify upstream examples | Expected failures document missing machine/task context or known upstream example edges; they must not be made pass by changing G-code semantics. | | 2 | `configs/sim` file execution through upstream `rs274` with sim INI context | Locate the corresponding INI/tool table and classify main programs, macros, and remap subroutines | Expected failures document upstream standalone `rs274` limits such as task/user-M process edges and the preserved `incremental_repetition_g533.ngc` demo edge. | | 3 | Vendored LinuxCNC interpreter, remap, tool, parameter, kinematics, and planner code | Provide deterministic runtime shims for filesystem, HAL/user-M boundaries, machine status, and build/source-probe coverage | A standalone pass may cover a runtime edge that Layer 1/2 cannot provide, but it must still call vendored LinuxCNC source for CNC behavior. | | 4 | Vendored LinuxCNC C ABI behavior from generated WASM modules | Stage files, apply executable bits, persist OPFS text, generate manifest-based staging plans, and forward paths/results between JS/browser and C ABI | A WASM/browser pass proves the host boundary can reproduce the staged LinuxCNC context; it does not replace native source validation or justify JS-owned CNC semantics. | ## Layer 2 Expected Failures The current `wasm-port/tests/native/verify_sim_configs.sh` run reports `total: 159`, `pass: 151`, `expected_fail: 8`, and `unexpected_fail: 0`. The eight expected failures are listed in the table below. The tracked per-program inventory for this layer now lives in `wasm-port/docs/sim-configs-coverage-matrix.md`. That matrix maps all 159 current `summary.tsv` records to program class, native result, current Layer 3/4 coverage, and the first-pass blocked or follow-up note used for future `configs/sim` coverage work. The native harness also emits machine-readable derived artifacts without changing the `summary.tsv` schema: ```text wasm-port/build/native/source-probes.tsv wasm-port/build/native/native-source-proof-summary.tsv wasm-port/build/native/native-runtime-probe-summary.tsv wasm-port/build/native/nc-files/summary.tsv wasm-port/build/native/sim-configs/summary.tsv wasm-port/build/native/sim-configs/class-summary.tsv wasm-port/build/native/sim-configs/path-matrix.tsv wasm-port/build/native/sim-configs/skipped.tsv ``` `class-summary.tsv` aggregates class/status/expected-failure counts. `path-matrix.tsv` records each path, class, native status, expected-failure reason, INI, tool table, runtime family, and blocked kind for CI and Node inventory reconciliation. `source-probes.tsv` records the native source-probe entry points used by `verify_native_probes.sh`. `native-source-proof-summary.tsv` records LinuxCNC-owned source proof for user-M process, tool DB process, and Python remap runtime blockers without enabling execution or promotion. `native-runtime-probe-summary.tsv` records the guarded native opt-in runtime probe status and missing host requirements. `nc-files/summary.tsv` records the Layer 1 native `nc_files` baseline, and `sim-configs/skipped.tsv` records the Layer 2 native sim-config skipped or expected-skip accounting. The Node inventory layer writes its own machine-readable artifacts: ```text wasm-port/build/wasm/sim-configs-inventory/summary.tsv wasm-port/build/wasm/sim-configs-inventory/skip-summary.tsv wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv wasm-port/build/wasm/sim-configs-inventory/blocked-dependency-summary.tsv wasm-port/build/wasm/sim-configs-inventory/full-process-boundary-summary.tsv wasm-port/build/wasm/sim-configs-inventory/user-m-process-state-targets.tsv wasm-port/build/wasm/sim-configs-inventory/user-m-process-native-state-alignment.tsv wasm-port/build/wasm/sim-configs-inventory/tool-db-process-protocol-gates.tsv wasm-port/build/wasm/sim-configs-inventory/tool-db-process-native-protocol-alignment.tsv wasm-port/build/wasm/sim-configs-inventory/tool-db-process-native-runtime-probe-gate.tsv wasm-port/build/wasm/sim-configs-inventory/python-remap-boundary-summary.tsv wasm-port/build/wasm/sim-configs-inventory/python-remap-runtime-gates.tsv wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-alignment.tsv wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-readiness.tsv wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-probe-gate.tsv wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-state-plan.tsv wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-fixture-plan.tsv wasm-port/build/wasm/sim-configs-inventory/python-remap-family-summary.tsv wasm-port/build/wasm/sim-configs-inventory/boundary-phase-completion-summary.tsv wasm-port/build/wasm/sim-configs-inventory/native-proof-alignment-summary.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-native-alignment-summary.tsv wasm-port/build/wasm/sim-configs-inventory/native-runtime-probe-execution-plan.tsv wasm-port/build/wasm/sim-configs-inventory/blocked-runtime-promotion-lock.tsv wasm-port/build/wasm/sim-configs-inventory/next-boundary-worklist.tsv wasm-port/build/wasm/sim-configs-inventory/next-boundary-recommendations.tsv wasm-port/build/wasm/sim-configs-inventory/boundary-proof-gates.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-native-evidence-acceptance-gate.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-promotion-blockers.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-host-preflight.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-host-requirement-summary.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-host-unblock-plan.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-family-host-readiness.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-host-readiness-rollup.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-opt-in-probe-dispatch-plan.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-opt-in-probe-dispatch-rollup.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-opt-in-probe-skip-evidence-contract.tsv wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-opt-in-probe-skip-evidence-rollup.tsv ``` The current skip/block summary is `ASSET-ONLY=65`, `L4-PYTHON-REMAP=53`, `L4-TOOL-DB=1`, `L4-USER-M-PROCESS=1`, `NON_MAIN_CLASS=10`, and `UPSTREAM-DEMO=1`. `skip-summary.tsv` is checked against the skip reasons derived from `path-matrix.tsv`, so both the per-row inventory status and the aggregate skip counts fail on blocked-policy drift. For eligible rows, missing vendored machine context is an inventory failure, not an expected skip; blocked rows must be classified by runtime dependency before the Node inventory filter runs. `boundary-summary.tsv` records one row per native inventory path with the matrix blocked kind, SDK classifier recommendation, declared HAL/UI/HALUI/Python process dependencies, `[EMCIO]DB_PROGRAM`, user-M execution codes, and the subset of execution user-M codes that are not staged by vendored `USER_M_PATH` files. It also separates Python UI/DB process dependencies from Python remap runtime dependencies. For vendored INI rows, the SDK classifier report must be available and `L4-TOOL-DB` / `L4-USER-M-PROCESS` hard blocks must match the classifier recommendation. `recommended_blocked=UNAVAILABLE` is only allowed when the boundary row records a missing vendored INI. Non-vendored Python-remap families remain unavailable until their dependency inventory batch vendors the required INI context. `ini-boundary-summary.tsv` aggregates those path-level reports by INI, giving vendored sim-config INIs a direct `report_available=1` coverage check and recording hard-block recommendation alignment at INI granularity. The inventory also guards safe representative rows such as `axis/gladevcp/probe.ngc`, `woodpecker/on_abort.ngc`, `axis/vismach/puma/puma_cube.ngc`, and `axis/vismach/melfa-sim/example.ngc`: they must keep their declared process dependencies in `boundary-summary.tsv`, remain Node/browser representatives, match the expected HAL/UI/HALUI/Python process flags, and avoid hard-block promotion unless a real hard runtime dependency appears. Deterministic `M110`/`M111` representatives are also guarded: the inventory must see the execution-chain user-M code, a vendored user-M file, and no hard `L4-USER-M-PROCESS` recommendation. `opa_demo.ngc` includes its vendored `circles.ngc` subroutine text in the boundary analysis so the `M111` call is accounted for even though it is reached through `SUBROUTINE_PATH`. `blocked-dependency-summary.tsv` records the hard blocked rows without promoting them: 53 Python-remap rows, one tool-database row, and one external user-M process row. It reads the source `linuxcnc/configs/sim` INI files for dependency accounting only and records Python modules, remap/prolog/epilog function ownership, NGC remap subpaths, HAL/UI/HALUI process declarations, `DB_PROGRAM`, tool database protocol evidence, external user-M execution codes, user-M process script files, user-M process side-effect evidence, and the LinuxCNC source/config files that own the blocked behavior. The user-M evidence is source-derived from the `M128`/`M129` Tcl scripts and records their Tcl/HAL runtime use, kinstype guard, and `ini.[xyz]` HAL pin updates. The tool database evidence is source-derived from `taskclass.cc`, `tooldata_db.cc`, and `axis/db_demo/db.py`, including the `v2.1` handshake, `g`/`FINI` get-all, and `l`/`u`/`p` notification protocol. The final Node inventory `summary.tsv` also guards every hard-blocked row: `L4-TOOL-DB`, `L4-USER-M-PROCESS`, and `L4-PYTHON-REMAP` paths must remain `SKIP` with their matching blocked reason, not only carry a matrix-level blocked label. The detailed boundary design for the current non-Python hard blocks is tracked in `wasm-port/docs/full-process-boundary-design.md`. That document records the LinuxCNC owner sets and proof required before `axis/vismach/millturn/example.ngc` or `axis/db_demo/base.ngc` can move out of `L4-USER-M-PROCESS` or `L4-TOOL-DB`. It is not an execution artifact and does not change the current Layer 4 blocked counts. `full-process-boundary-summary.tsv` is the machine-readable companion for that design record. It has one designed-but-blocked row for `millturn` and one for `db_demo`, records the LinuxCNC runtime owner evidence from the corresponding blocked dependency row, records the required native/Node/browser proof, and keeps `execution_enabled=0` until the corresponding LinuxCNC-owned runtime boundary exists. The tracked matrix and inventory guard also require those two rows to remain non-representative in Node/browser until that proof exists. `runtime-boundary-host-preflight.tsv` is the host-facing preflight for the blocked runtime probes. It records each blocked family, the required LinuxCNC runtime commands, the opt-in environment variable, the exact native probe command, the current probe status, and keeps `execution_enabled=0` and `promotion_allowed=0`. It does not run probes or relax promotion locks. `runtime-boundary-host-requirement-summary.tsv` normalizes those preflight requirements into one row per host command or source/module prerequisite, so missing `halcmd`, `halrun`, `linuxcnc`, and `milltask` can be audited by the blocked families they affect. `runtime-boundary-host-unblock-plan.tsv` filters that table to unavailable requirements and records the affected opt-in commands and remaining missing requirements; it is a planning artifact only. `runtime-boundary-family-host-readiness.tsv` reduces the same host evidence to one row per blocked runtime family, and `runtime-boundary-host-readiness-rollup.tsv` gives the aggregate decision. On this host the rollup remains `host_blocked_for_all_opt_in_native_probes` with zero ready opt-in commands. These rows are non-executing and non-promoting. `runtime-boundary-opt-in-probe-dispatch-plan.tsv` turns each family readiness row into a per-probe dispatch action. `runtime-boundary-opt-in-probe-dispatch-rollup.tsv` then gives the aggregate dispatch switch; currently every blocked runtime probe is skipped for missing host requirements. Dispatch permission only means the guarded native probe may be manually run on a ready host, not that the row is promoted. `runtime-boundary-opt-in-probe-skip-evidence-contract.tsv` records why each non-dispatched probe is skipped and whether native pass evidence is required yet. `runtime-boundary-opt-in-probe-skip-evidence-rollup.tsv` gives the aggregate evidence decision. While probes are skipped for missing host requirements, no native pass evidence is accepted and every blocked family remains `execution_enabled=0` and `promotion_allowed=0`. `native-runtime-probe-execution-plan.tsv` records the exact opt-in command, required native proof key, current runtime readiness, expected pass status, missing requirements, and promotion prerequisites for the three guarded native runtime probes. On this host all rows remain `plan_status=blocked_missing_host_runtime`. `runtime-boundary-native-evidence-acceptance-gate.tsv` decides whether native pass evidence may be accepted for each blocked runtime family. It currently blocks evidence acceptance until host requirements are available and the native opt-in probe passes. `runtime-boundary-promotion-blockers.tsv` expands each non-ready promotion decision into concrete blocker keys such as missing host runtime, native probe not passed, Node/browser gates incomplete, promotion lock active, and manual lock update required. `next-boundary-recommendations.tsv` is the generated priority handoff for the next runtime boundary work. It ranks millturn user-M, tool DB, and Python runtime lifecycle work, while keeping `execution_enabled=0` and `promotion_allowed=0`. The Node inventory verifies the exact per-family `source_artifacts` set, duplicate-free source lists, and `primary_artifact` traceability for each recommendation, and requires every referenced artifact token to exist under the generated sim-config inventory artifact directory. The Node inventory also runs a cross-artifact guard over the blocked runtime opt-in target set. It requires recommendations, execution plan, host preflight, dispatch plan, skip/evidence contract, native evidence acceptance gate, promotion readiness, promotion blockers, and post-native-pass gates to agree on the same target, proof keys, opt-in command, missing runtime requirements, active promotion lock, and non-executing/non-promoting state. The browser smoke mirrors the promotion and opt-in gate consistency checks by cross-checking the promotion lock, readiness, blocker, post-native-pass, native evidence acceptance, pass-evidence, recommendation, host-preflight, family readiness, dispatch, and skip-evidence artifacts. This browser-side parity is non-executing and keeps every blocked runtime family locked until native, Node, browser, and manual promotion gates all agree. It also cross-checks `runtime-boundary-host-requirement-summary.tsv`, `runtime-boundary-host-unblock-plan.tsv`, `runtime-boundary-family-host-readiness.tsv`, and `runtime-boundary-host-preflight.tsv` so missing and available host requirements, affected opt-in commands, and family probe commands cannot drift between the host-readiness artifacts. It also checks that `boundary-phase-completion-summary.tsv` counts match the blocked-runtime and family-specific artifact rows the browser has already loaded, so completion criteria cannot drift from the generated gate artifacts seen by browser smoke. It also cross-checks the user-M, tool DB, and Python family-specific contract/readiness/probe artifacts against `runtime-boundary-contract-summary.tsv` so browser validation sees the same runtime-family contract alignment as the Node inventory, without running any blocked runtime process. It also checks `next-boundary-recommendations.tsv` row counts against the generated user-M probe-gate, tool DB probe-gate, and Python runtime-contract source rows, so recommendation priority handoffs cannot drift from their machine-readable source artifacts. It also checks each recommendation's `primary_artifact` and `source_artifacts` against the browser-visible generated artifact set, including duplicate detection, primary-artifact traceability, and exact per-family source artifact sets, while keeping execution and promotion disabled. The Node coverage gate also confirms the browser recommendation source-artifact check uses the same `wasmArtifactNames` returned by the artifact documentation coverage helper. It also fetches the compatibility, matrix, and full-process boundary docs in browser smoke and checks the documented artifact names/tokens for the generated WASM inventory TSVs and native TSVs. The same browser check fetches those TSV artifacts, requires a non-empty TSV header, and verifies the expected artifact/token lists are duplicate-free with fixed counts, mirroring the Node documentation coverage gate without executing native runtime probes. The native `build/native/sim-configs/skipped.tsv` artifact is allowed to be empty when the native strict sim-config baseline has no skipped rows. The same Node inventory run also checks generated artifact documentation coverage: every TSV emitted under `build/wasm/sim-configs-inventory/` must be named in `compatibility-validation.md`, `sim-configs-coverage-matrix.md`, or `full-process-boundary-design.md`. New gate artifacts must therefore be documented before the inventory can pass. The Node coverage gate also requires the generated WASM inventory artifact list to remain the exact duplicate-free 54-entry baseline and the native generated TSV token list to remain the exact duplicate-free 8-token baseline. It also requires the corresponding `boundary-phase-completion-summary.tsv` documentation-coverage counts to remain `54` and `8`, respectively. It also checks that the browser smoke source lists the same generated WASM and native artifact tokens and preserves the same fixed-count, duplicate-free, fetchability/header, documentation-missing, and completion count-parity guards before browser-side artifact coverage can pass. It also checks that browser smoke actually executes the artifact documentation coverage helper, fetches each generated WASM artifact by artifact name, fetches each native TSV by relative artifact token, calls the completion count-parity helper with the generated completion rows, still fetches and joins the exact compatibility, matrix, and full-process boundary review-document set for that coverage check before checking for missing artifact references, requires the browser missing-reference loops to iterate `wasmArtifactNames` and `nativeArtifactTokens` against that joined `documentationText`, keeps completion evidence reviewable for browser count parity, binds the documentation-coverage completion counts to the returned `wasmArtifactNames` and `nativeArtifactTokens` arrays, and preserves the native skipped-artifact empty allowance for `build/native/sim-configs/skipped.tsv`. Native generated TSVs under `build/native/` are checked the same way by their relative artifact path. This catches native baseline/source-proof/runtime-probe artifacts that are generated but not described in the compatibility, coverage, or full-process boundary documentation. It also checks native source proof consistency: the native source proof alignment rows, native runtime probe summary, and runtime probe gate alignment must cover the same blocked classes and agree that source proof is ready while execution and promotion remain disabled. `user-m-process-state-targets.tsv` expands the `millturn` M128/M129 process boundary into per-pin proof targets: two user-M codes, three axes, and four `ini.[xyz]` HAL pins per axis. Each row records the source Tcl file, remap caller, kinstype guard, INI source section/field, expected value, `proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. `user-m-process-native-state-alignment.tsv` then aligns each generated pin target with the native source probe stdout key/value pair, for example `M128_X_AXIS_X.MIN_LIMIT_ok=1`. This catches drift between generated target rows and the LinuxCNC-owned native source proof without executing Tcl/HAL or allowing promotion. `user-m-process-native-transition-alignment.tsv` performs the same source alignment for the `M428/M429` transition plan. It checks the native probe stdout for `motion.analog-out-03`, kinstype targets `0` and `1`, `G59.1`/`G59.2`, `P7`/`P8`, and the `M428 -> M128` / `M429 -> M129` calls. Those rows also remain `proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. `user-m-process-native-runtime-state-plan.tsv` is the runnable native probe contract that follows those source-alignment tables. It names the required LinuxCNC task/HAL/Tcl user-M process runtime, the required HAL/INI environment, and the exact `ini.[xyz].*` state values that a future native runtime probe must record after `M428` and `M429`. It remains a plan only with `native_runtime_status=pending_native_hal_tcl_process_probe`, `execution_enabled=0`, and `promotion_allowed=0`. `user-m-process-native-runtime-readiness.tsv` is the host capability gate for that future probe. It records availability of `tclsh`, `halrun`, `halcmd`, and `linuxcnc`, captures PATH evidence for available commands, and leaves `proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. `user-m-process-native-runtime-probe-gate.tsv` combines that readiness with the source/state proof for `M428/M128` and `M429/M129`. The native `probe_millturn_user_m_runtime.sh` entry point is wired through `build_native_probes.sh`; without the full LinuxCNC HAL/Tcl command set it reports `skipped_missing_host_runtime`, and with the runtime present it remains disabled by default. When explicitly enabled with `ENABLE_MILLTURN_USER_M_RUNTIME_PROBE=1`, it starts the vendored `millturn.ini`, runs the LinuxCNC-owned Tcl `M128`/`M129` scripts, verifies the expected `ini.[xyz].*` HAL pin state, and reports `runtime_state_probe_passed` without enabling promotion. `tool-db-process-protocol-gates.tsv` expands the `db_demo` tool-database boundary into pending protocol, callback, and state gates. It records the LinuxCNC `v2.1`, `g`, `l`, `u`, and `p` protocol requirements, the demo DB callbacks, DB mode state targets such as ignored `TOOL_TABLE`, `T10..T19`, `tno+100` pockets, and OPFS/host persistence boundaries, while keeping `proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. `tool-db-process-native-protocol-alignment.tsv` aligns each generated DB gate with the native source probe stdout proof keys, including the protocol handshake, get-all, notifications, callback registration, and nonrandom state targets. This is still dependency/proof accounting only: it does not spawn `DB_PROGRAM`, emulate the tool database protocol in JavaScript, or fall back to a `.tbl` file. `tool-db-process-native-runtime-readiness.tsv` records the host prerequisites for the guarded DB process protocol probe: `python3`, `linuxcnc`, `milltask`, `halcmd`, the configured `db_nonran.py` executable, and LinuxCNC's Python `linuxcnc.so` / `tooldb.py` modules. It captures availability evidence while keeping `proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. When explicitly enabled with `ENABLE_TOOL_DB_RUNTIME_PROBE=1`, `probe_tool_db_runtime.sh` starts the vendored `DB_PROGRAM`, drives the LinuxCNC `tooldb.py` `v2.1`/`g`/`p`/`l`/`u` protocol, verifies nonrandom startup/update/load/unload state and persistence, and reports `runtime_protocol_probe_passed` without enabling promotion. `tool-db-process-native-runtime-probe-gate.tsv` combines the DB source proof and host readiness into the execution gate for that guarded native probe. It records `runtime_ready`, missing requirements, source proof readiness, and the non-promoting gate status before any manual opt-in run is allowed. `python-remap-boundary-summary.tsv` is the machine-readable companion for the Python remap inventory batch. It has one inventory-only row for each `L4-PYTHON-REMAP` path, records Python modules, remap/prolog/epilog functions, NGC-only subpaths, HAL/UI/HALUI assumptions, LinuxCNC Python runtime owner evidence from `interp_python.cc` and `python_plugin.cc`, and keeps `execution_enabled=0` until a LinuxCNC-owned Python runtime boundary exists. `python-remap-runtime-gates.tsv` expands those rows into Python module, remap/prolog/epilog callable, NGC-only subpath, process-assumption, and runtime-owner gates, all with `proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. `python-remap-native-runtime-alignment.tsv` aligns every generated Python gate with native source proof: exact runtime owner gates use keys such as `python_runtime_pycall_dispatch`, while dependency gates use representative family inventory proof or the aggregate `python_remap_native_source_inventory_proof`. It does not initialize Python, import modules, execute callbacks, or promote browser/Node coverage. `python-remap-native-runtime-readiness.tsv` records the native runtime prerequisites for guarded probes by family: `python3`, `linuxcnc`, LinuxCNC's `interp_python.cc` / `python_plugin.cc` owner source files, and the configured Python modules. It is a readiness gate only and keeps every row `proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. `python-remap-native-runtime-probe-gate.tsv` combines the selected Python runtime fixture, source proof, and host readiness into the execution gate for the guarded native lifecycle probe. It remains non-executing and non-promoting until `linuxcnc` is available and the dispatch gate permits the manual opt-in probe. `python-remap-native-runtime-state-plan.tsv` records the next native runtime probe target set by family: LinuxCNC Python phases, configured modules, callables, NGC-only subpaths, process assumptions, readiness counts, and source-alignment artifacts. It remains a plan only and does not initialize Python, import modules, execute callbacks, or permit promotion. `python-remap-native-runtime-fixture-plan.tsv` selects the first minimal Python runtime lifecycle fixture, `axis/remap/stop-lookahead/nc_files`, because it exercises Python runtime phases and configured modules without Python callable or NGC-only subpath complexity. It is still a fixture plan only: `proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. When explicitly enabled with `ENABLE_PYTHON_REMAP_RUNTIME_PROBE=1`, `probe_python_remap_runtime.sh` follows the fixture `demo.ini` Python path and toplevel declarations, imports the vendored modules, verifies `queuebuster` callable lookup, generator return, and first `INTERP_EXECUTE_FINISH` yield, and reports `runtime_lifecycle_probe_passed` without promoting Python-remap execution. `python-remap-family-summary.tsv` aggregates the same blocked rows by runtime family, preserving row and INI counts plus family-level Python module, remap/prolog/epilog, NGC-only subpath, Python runtime owner evidence, HAL/UI/HALUI, and `execution_enabled=0` evidence. It is dependency inventory only and must not be used to promote Python-remap execution. `boundary-phase-completion-summary.tsv` records the current boundary-phase completion criteria as machine-readable checks: vendored INI boundary report coverage, hard-block dependency evidence, safe HAL/UI representative coverage, proof that blocked families remain skipped/non-representative with execution disabled, and proof that blocked runtime families carry LinuxCNC-owned user-M, tool DB, and Python runtime evidence fields. It also records native source proof alignment when the native proof summary is available, plus the aggregate native stdout alignment summary for user-M, tool DB, and Python runtime gates. The same completion summary now includes documentation-coverage criteria for generated WASM sim-config inventory TSV artifacts and native generated TSV artifacts, so artifact generation and review documentation stay in lockstep. It also exposes the blocked runtime worklist/recommendation consistency guard, the blocked runtime promotion gate consistency guard, the blocked runtime host requirement consistency guard, the blocked runtime host/dispatch/skip-evidence rollup consistency guard, the blocked runtime opt-in cross-artifact consistency guard, the native source proof/runtime probe consistency guard, and the runtime family contract/alignment consistency guard as completion criteria, so review can see those gates without reopening every individual TSV. The family contract/alignment guard checks that the user-M, tool DB, and Python-specific contract, readiness, probe-gate, and fixture/state-plan artifacts agree with `runtime-boundary-contract-summary.tsv` and `runtime-boundary-native-alignment-summary.tsv` while keeping execution and promotion disabled. The browser smoke consumes the same `boundary-phase-completion-summary.tsv` criterion list and fails on criterion drift. This is a browser-side parity check for generated gate artifacts only; it does not execute blocked native runtime probes or allow promotion. The browser smoke also checks that `runtime-boundary-contract-summary.tsv` points at the same runtime alignment artifact, row count, boundary kind, and disabled execution/promotion state reported by `runtime-boundary-native-alignment-summary.tsv`. It also cross-checks `native-proof-alignment-summary.tsv`, `native-runtime-probe-summary.tsv`, and `runtime-probe-gate-alignment.tsv` so browser validation sees the same source-proof readiness, runtime readiness, required native proof, target, and disabled execution/promotion state as the Node inventory. The browser smoke also cross-checks `native-runtime-probe-execution-plan.tsv`, `native-runtime-probe-pass-evidence-contract.tsv`, `runtime-boundary-host-preflight.tsv`, `runtime-boundary-opt-in-probe-dispatch-plan.tsv`, and `runtime-boundary-opt-in-probe-skip-evidence-contract.tsv`, keeping the current host-blocked probe status, missing requirements, opt-in command, evidence status, and disabled execution/promotion state aligned. It also checks the host requirement summary and unblock plan against family host-readiness and preflight rows, including unavailable requirement ownership, available prerequisite ownership, opt-in environment variables, and execution command traceability. It also cross-checks `runtime-boundary-host-readiness-rollup.tsv`, `runtime-boundary-opt-in-probe-dispatch-rollup.tsv`, and `runtime-boundary-opt-in-probe-skip-evidence-rollup.tsv` for family/probe counts, blocked families, missing requirements, blocked opt-in commands, host/dispatch/evidence status, and disabled execution/promotion parity. `native-proof-alignment-summary.tsv` aligns native source proof rows with the generated worklist and native proof gates for user-M, tool DB, and Python runtime blockers. It is proof-consumption accounting only and keeps execution and promotion disabled. `runtime-boundary-native-alignment-summary.tsv` summarizes the three detailed native alignment artifacts. It requires every alignment row to have native stdout evidence, `alignment_ok=1`, `proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. `blocked-runtime-promotion-lock.tsv` combines the next-boundary worklist, native/Node/browser proof gates, and runtime native alignment summary into one promotion lock per blocked runtime target. A lock row is active only while every proof layer is still pending, execution and promotion remain disabled, and the matching runtime alignment artifact is complete. `next-boundary-worklist.tsv` records the next blocked runtime-boundary design targets in priority order. It starts with the designed-but-disabled `millturn` external user-M process and `db_demo` tool database process boundaries, then lists Python runtime families from the inventory. Every row keeps `execution_enabled=0` and `promotion_allowed=0`, records the LinuxCNC owner set and runtime owner evidence, records required native, Node, and browser proof, and names the next boundary-design action before promotion. `boundary-proof-gates.tsv` expands that worklist into one pending native, Node, and browser proof gate per target. It is a promotion guard only: current rows keep `proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`; user-M gates must require HAL pin state rather than event-only proof, tool-DB gates must require protocol proof rather than a `.tbl` fallback, and Python gates must require a LinuxCNC-owned Python runtime boundary rather than JavaScript semantics. The browser interpreter smoke reads the browser-layer rows from this artifact before running safe representatives, so `millturn`, `db_demo`, and Python runtime families cannot be accidentally treated as browser/full-process coverage while their proof gates remain pending. Current `configs/sim` class taxonomy: | Class | Meaning | Current policy | | --- | --- | --- | | `main` | A complete standalone-executable sim-config program. | Eligible for native inventory; promote to Layer 3/4 when the required runtime boundary exists. | | `macro_load` | A macro or load/parse asset that is not the primary machine program entry point. | Keep in native inventory, but do not treat it as a browser main-program target by default. Add class-level load/parse representatives instead of widening browser execution blindly. | | `remap_subroutine` | A remap or subroutine asset under `remap_subs/` or similar directories. | Validate through remap parse/execute paths, not by pretending it is a standalone browser main program. | Current `configs/sim` blocked policy: | Blocked kind | Meaning | Current examples | | --- | --- | --- | | `ASSET-ONLY` | The file is a macro/remap asset or subroutine and is not a standalone browser main-program target. | `configs/sim/*/remap_subs/*.ngc` entries in the matrix. | | `L4-TOOL-DB` | Native LinuxCNC `rs274` coverage exists, but Node/browser inventory is blocked by LinuxCNC tool-database process boundaries such as `[EMCIO]DB_PROGRAM`. | `configs/sim/axis/db_demo/*`. | | `L4-USER-M-PROCESS` | Native LinuxCNC `rs274` coverage exists, but Node/browser inventory is blocked because the config depends on external `USER_M_PATH` process execution rather than the deterministic `M110`/`M111` boundary already modeled by the standalone runtime. | `configs/sim/axis/vismach/millturn/*`. | | `L4-PYTHON-REMAP` | Native LinuxCNC `rs274` coverage exists, but full Node/browser inventory is blocked until an intentional Python-remap runtime boundary is exposed for Layer 4. | `configs/sim/gmoccapy/*`, `configs/sim/axis/laser/*`, `configs/sim/axis/remap/*/nc_files/*.ngc`, `configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/*`, and `configs/sim/axis/vismach/VMC_toolchange/toolchange.ngc`. | | `UPSTREAM-DEMO` | A preserved upstream demo edge that should remain an expected failure instead of being forced through standalone semantics. | `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc`. | | Program | Layer 2 classification | Current Layer 3/4 coverage or boundary | | --- | --- | --- | | `axis/foam/foam.ngc` | `ini-axis-mask-UV`; native upstream `bin/rs274` rejects `U`/`V` words before the standalone runtime applies the INI machine axis mask. | Covered by `wasm-port/tests/native/verify_native_probes.sh`, `wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh`, and `wasm-port/tests/browser/verify_interp_browser.sh`, which run the vendored file with `axis_foam.ini` and verify `U/V` axis acceptance through LinuxCNC-backed file execution. | | `axis/vismach/5axis/bridgemill/5axisgui.ngc` | `ini-axis-mask-W`; native upstream `bin/rs274` rejects the `W` word outside the bridge-mill runtime context. | Covered by `wasm-port/tests/native/verify_native_probes.sh`, `wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh`, and `wasm-port/tests/browser/verify_interp_browser.sh`, which stage `5axis.ini`, the tool table, and remap subroutines, then execute through the vendored LinuxCNC remap/file path. | | `axis/geometry/xyzc.ngc` | `user-m-code-M110`; native upstream `bin/rs274` does not register or execute the sim-config `USER_M_PATH` handler. | Covered by `wasm-port/tests/native/verify_native_probes.sh`, `wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh`, and `wasm-port/tests/browser/verify_interp_browser.sh`; the smoke assertions require `canon_event=USER_M_COMMAND code=M110` and reject `Unknown m code used: M110`. | | `axis/external_offsets/dyn_demo.ngc` | `user-m-code-M111`; native upstream `bin/rs274` does not register or execute the sim-config `USER_M_PATH` handler. | Covered by `wasm-port/tests/native/verify_native_probes.sh`, `wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh`, and `wasm-port/tests/browser/verify_interp_browser.sh`; the smoke assertions require `canon_event=USER_M_COMMAND code=M111` and reject `Unknown m code used: M111`. | | `axis/external_offsets/eoffsets.ngc` | `user-m-code-M111`; same standalone task/user-M boundary as `dyn_demo.ngc`. | Covered by `wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh` and `wasm-port/tests/browser/verify_interp_browser.sh` with the vendored executable `M111` and `eoffset.tbl` staged from the manifest. | | `axis/external_offsets/jwp_z.ngc` | `user-m-code-M111`; same standalone task/user-M boundary as `dyn_demo.ngc`. | Covered by `wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh` and `wasm-port/tests/browser/verify_interp_browser.sh` with the vendored executable `M111` and `eoffset.tbl` staged from the manifest. | | `axis/external_offsets/opa_demo.ngc` | `user-m-code-M111`; same standalone task/user-M boundary as `dyn_demo.ngc`, plus a subroutine dependency. | Covered by `wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh` and `wasm-port/tests/browser/verify_interp_browser.sh`, which stage `M111`, `eoffset.tbl`, and the `SUBROUTINE_PATH` dependency `circles.ngc`. | | `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc` | `upstream-demo-missing-motion-gcode`; upstream standalone `rs274` reports `Cannot use axis values without a g code that uses them`. | Preserved as an upstream demo expected failure. Do not make this pass by editing the G-code, changing JS interpreter behavior, or adding standalone semantics. | ## Validation Chain The native validation script runs these checks in order: 1. `tools/verify_upstream_baseline.sh` Confirms `../linuxcnc` is at the recorded upstream commit in `tools/upstream-baseline.txt`. 2. `tools/verify_vendor_sync.sh` Confirms every manifest file is present in `vendor/linuxcnc/`, no extra vendored file exists, and every vendored file is byte-identical to upstream. 3. `tools/verify_no_standalone_cnc_semantics.sh` Confirms standalone code has not introduced project-owned `Interp::...` member definitions outside the documented Python/remap runtime-edge stubs. 4. `tools/verify_native_linuxcnc_fixture_baseline.sh` Runs a side-by-side fixture baseline through upstream `../linuxcnc/bin/rs274` and compares normalized canonical events for fixtures that do not require standalone-only runtime adapters. 5. `tools/build_native_probes.sh` Builds native source probes and standalone harnesses from vendored LinuxCNC source plus narrow runtime wrappers. 6. `tests/native/verify_sim_configs.sh` Runs LinuxCNC `configs/sim` `.ngc` programs through the upstream `../linuxcnc/bin/rs274` standalone entry point, using nearest or explicit sim INI/tool-table mappings and classifying main programs, macro-load checks, and remap subroutines separately. 7. `tests/native/verify_nc_files.sh` Runs the basic/example subset of upstream `linuxcnc/nc_files` through `../linuxcnc/bin/rs274`, with complete programs executed strictly and macro/library files wrapped only for load/parse validation. 8. `tests/native/verify_native_probes.sh` Checks probe exit codes, source-probe coverage, harness stdout, canonical fixture events, and expected error behavior. Current `nc_files` basic-suite baseline: ```text total: 107 pass: 101 fail: 6 timeout: 0 expected_fail: 6 unexpected_fail: 0 ``` The six expected failures are LinuxCNC-native entry-point/context edges: `cone.ngc` needs a W-axis 5-axis machine context; `g76.ngc` and `lathe-g76.ngc` need lathe cutter-compensation/tool context; `lathe_g70_71_demo.ngc` needs lathe profile/tool context; `nestedcall.ngc` uses an upstream O-word `callsub` syntax edge; and `tool-length-probe.ngc` needs probe runtime context. The same runner also supports exploratory full-directory inventory: ```bash wasm-port/tests/native/verify_nc_files.sh --all ``` Current full-directory `nc_files` inventory: ```text total: 247 pass: 219 fail: 28 timeout: 0 expected_fail: 28 unexpected_fail: 0 ``` The additional expected failures are probe/plasmac runtime-context files and one NURBS sample using `G2.2`, which the current upstream `bin/rs274` standalone entry point reports as `Unknown g code used`. The WASM INI smoke script builds `runtime/ui/ini-panel/linuxcnc_ini.js` and `linuxcnc_ini.wasm` from vendored LinuxCNC `inifile.cc`, then loads that module through `runtime/sdk/src/index.js` in Node and verifies INI string and boolean queries against a file written to the Emscripten filesystem. Boolean conversion is validated through vendored LinuxCNC `iniFindBool()`, and machine-session file-name lookup is validated through LinuxCNC string queries for `[RS274NGC]PARAMETER_FILE` and `[EMCIO]TOOL_TABLE`. The WASM interpreter-core smoke script builds `build/wasm/core/linuxcnc_interp.js` and `linuxcnc_interp.wasm` from the same vendored LinuxCNC interpreter source set used by the native minimal interpreter harness. It loads the module in Node through `runtime/sdk/src/index.js`, runs the first WASM interpreter fixture group through `Interp::execute()`, and compares emitted canonical events plus required LinuxCNC `_setup` state readback with the matching files in `tests/fixtures/canon/`. It also calls vendored `Interp::init()` and `Interp::synch()` through the WASM C ABI to validate the initialization canonical boundary, metric/inch machine-unit status edge, and current/selected tool slot status synchronization already covered by the native init harness. It also calls the vendored single-axis rotary indexer path through `Interp::execute()` to validate the `UNLOCK_ROTARY`/`LOCK_ROTARY` canonical runtime boundary already covered by the native indexer harness. It also calls vendored `Interp::init_named_parameters()` and `Interp::find_named_param()` through the WASM C ABI to validate the native named-parameter harness path for LinuxCNC built-in, INI-backed, HAL-backed, and missing named-parameter lookup. It also writes selected G-code fixtures and vendored `tests/interp/g10` regressions into the Emscripten filesystem through the SDK and runs them through LinuxCNC `Interp::open()`, `Interp::read()`, and `Interp::execute()` to validate the file execution path, including G10 tool-table updates, tool-length offset application timing, active G5X offset changes, G92 interaction, XY-rotation behavior, G52/G92 shared-offset transitions, and G92 startup parameter-file persistence through vendored `ini_load()`/`Interp::init()`/`restore_parameters()`, including `DISABLE_G92_PERSISTENCE` clearing parameters 5210-5219. It also writes the vendored LinuxCNC `xyzac-trt` and `xyzbc-trt` table-rotary-tilting sample machine INI, `remap_subs/*.ngc`, and `xyzac_switchkins.ngc`/`xyzbc_switchkins.ngc`, `xyzac_switchkins_test_1.ngc`, `xyzac_switchkins_test_2.ngc`, `xyzac_switchkins_test_3.ngc`, `boat-xyzac.ngc`, `boat-xyzbc.ngc`, and `impeller-7bl-xyzac.ngc` demo files into the Emscripten filesystem. It also writes the vendored LinuxCNC `xyzab-tdr` table-dual-rotary INI, tool table, `remap_subs/*.ngc`, and `xyzab-tdr-demo.ngc` into the Emscripten filesystem. It also writes the vendored LinuxCNC bridge-mill `5axis.ini`, tool table, `remap_subs/*.ngc`, and `5axisgui.ngc` into the Emscripten filesystem. These checks validate the WASM C ABI/SDK path for vendored LinuxCNC `REMAP` parsing, vendored LinuxCNC tool-table loading from the machine INI, O-word remap execution, `M68`/`M66` HAL synchronization, and file `open()`/`read()`/`execute()` completion without JavaScript M-code or kinematics semantics. The same Node smoke writes the vendored LinuxCNC `tests/remap/duplicate-o-word`, NGC-only `tests/remap/fail/args.0`, `tests/remap/fail/args.1`, `tests/remap/fail/args.2`, `tests/remap/fail/body-ngc`, `tests/remap/m30-interaction`, `tests/remap/nested-remaps-oword`, `tests/remap/posargs.0`, and `tests/remap/sequencing` INI, program, and remap subroutines into the Emscripten filesystem and validates those upstream NGC remap regressions through the generic `runRemapFile()` C ABI/SDK path, which only reads LinuxCNC INI `SUBROUTINE_PATH`, `REMAP`, and `OWORD_NARGS` entries and calls vendored `Interp::parse_remap()`, `open()`, `read()`, and `execute()`. The NGC-only failure cases that match upstream `rs274 -n 0` flow use the sibling `runRemapFileContinueOnError()` C ABI/SDK path, which records LinuxCNC error text and continues the same vendored `open()`/`read()`/`execute()` loop without implementing failure semantics in JavaScript. The same Node smoke also writes the NGC-only LinuxCNC `tests/remap/remap-io/test-ngc.ini` and `io_*.ngc` subroutines into the Emscripten filesystem, then calls `runRemapIoMdiSequence()` to feed the upstream test-driver MDI sequence into vendored `Interp::execute()`. The SDK does not implement M62-M68, M66 input, or REMAP semantics; the standalone boundary only pre-seeds deterministic external input values and captures LinuxCNC canonical events. The same WASM interpreter smoke also writes minimal `M110` and `M111` fixtures into the Emscripten filesystem, marks the `M1xx` files executable, and validates that the standalone machine-config boundary mirrors LinuxCNC task-layer `[DISPLAY]PROGRAM_PREFIX` plus `[RS274NGC]USER_M_PATH` lookup by registering `USER_DEFINED_FUNCTION` entries and recording deterministic `USER_M_COMMAND` events instead of spawning host processes. The same Node smoke writes the vendored LinuxCNC `tests/interp/do-while-break`, `tests/interp/oword-bug315`, `tests/interp/oword-bug315-p2`, `tests/interp/exists`, `tests/interp/return-value`, `tests/interp/subs-follow-main`, `tests/interp/fractional-linenumbers`, `tests/interp/cam-nisley` with its upstream `test.tbl`, `tests/interp/namedparam-bug424`, selected `tests/interp/rotation` pure interpreter cases, `tests/interp/iniparam`, `tests/interp/iniparam-failassign`, `tests/interp/sub-call-from-sub`, `tests/interp/sequence-number`, and `tests/interp/nested-sub-error`, `tests/interp/nested-sub-in-file-error`, and `tests/interp/abort-hot-comment` files into the Emscripten filesystem and validates those upstream interpreter regressions through `runFile()` or `runFileWithIni()`, which only reads LinuxCNC INI `SUBROUTINE_PATH` where needed and calls vendored LinuxCNC `Interp::open()`, `read()`, and `execute()`. The `iniparam` fixtures validate vendored LinuxCNC `_ini[...]` lookup, missing INI-parameter error text, and read-only named-parameter assignment rejection through the `INI_FILE_NAME` runtime edge. It checks LinuxCNC canonical messages, canonical motion/events, and final interpreter state without JavaScript O-word, subroutine lookup, INI-variable, or read-only-parameter semantics. The same Node smoke writes LinuxCNC-format parameter files into the Emscripten filesystem and validates vendored `Interp::restore_parameters()` and `Interp::save_parameters()`, including the saved parameter values, missing required numeric parameter defaulting, and the `.bak` backup file boundary. It also writes the negative G-code fixtures into the Emscripten filesystem and verifies their LinuxCNC-produced error text through the `Interp::open()`/`read()`/`execute()` file path. The WASM trajectory-planner smoke script builds `build/wasm/tp/linuxcnc_tp.js` and `linuxcnc_tp.wasm` from vendored LinuxCNC TP, TC, TC queue, spherical-arc, blendmath, S-curve, Ruckig-wrapper, C Ruckig support, emcpose, and posemath source files. It loads the module in Node and calls the exported TP probe C ABI to validate the same LinuxCNC linear, arc, and queued-line planner calls covered by the native `linuxcnc_tp_api_probe`. The OPFS host-boundary script validates the JavaScript file-service adapter with a Node mock of the browser File System Access handles. It covers nested directory creation, text save/load, missing file behavior, invalid relative paths, unavailable OPFS storage, and the host-side OPFS path model for INI, tool table, parameter, G-code, preview-cache, and session-snapshot storage targets. It also validates the host-side session snapshot JSON envelope and round-trip store, including unsupported format/version, session-id mismatch, non-object metadata/payload rejection, custom snapshot filenames, and invalid snapshot filename rejection, plus pure-text machine file and G-code stores, including G-code program filename rejection for traversal or nested paths, without defining CNC machine-state or file-format semantics. It now also validates the OPFS-to-WASM parameter-file bridge with a mock interpreter SDK to ensure the host boundary copies text into and out of the WASM filesystem without defining parameter semantics, and that INI-derived machine file names are still rejected by the OPFS path model when they contain traversal or nested path segments. The same Node smoke also validates that explicit session file-name options take precedence over INI-derived parameter and tool-table file names, and that missing INI file-name values fall back to the host path model defaults, keeping host override policy outside CNC semantics. The browser INI/OPFS smoke script serves `wasm-port/` over localhost and runs Chromium headless against a test page that imports the JS SDK, loads the INI WASM module, queries vendored LinuxCNC INI parsing through the SDK, including machine-session parameter/tool-table file-name strings, and performs an OPFS text-file, generic session snapshot, custom snapshot filename, invalid snapshot filename/envelope, machine file, G-code text round trip, and G-code filename path-model rejection. It also verifies that the INI panel UI exposes LinuxCNC-backed `[RS274NGC]PARAMETER_FILE` and `[EMCIO]TOOL_TABLE` query results, plus the default OPFS parameter-file and tool-table mappings used when a machine session is copied into the interpreter WASM filesystem. It also clicks the INI panel's 5-axis remap demo action and verifies that the UI copies vendored LinuxCNC `xyzac-trt` machine/remap/demo files into the interpreter WASM filesystem, calls the LinuxCNC-backed SDK remap execution path for the vendored `impeller-7bl-xyzac.ngc` demo, and displays the resulting `fiveaxis_*` status lines without JavaScript M-code or kinematics semantics. The browser interpreter smoke script serves `wasm-port/` over localhost and runs Chromium headless against a test page that loads the interpreter-core WASM module through `runtime/sdk/src/index.js`, writes no CNC behavior in JavaScript, and verifies existing canonical fixtures through the exported C ABI backed by vendored LinuxCNC `Interp::execute()` and `Interp::open()`/`read()`/`execute()` paths, including the INI-aware named-parameter file path and negative interpreter fixtures with expected error text plus absent canonical motion output. It also validates vendored `Interp::init()` and `Interp::synch()` through the same SDK/C ABI path, including initialization canonical events, metric/inch machine units, and tool slot readback, and checks the vendored rotary-indexer `G0 A...` execution path for `UNLOCK_ROTARY`/`LOCK_ROTARY` boundary events. It also validates `Interp::init_named_parameters()` and `Interp::find_named_param()` through the same browser SDK/C ABI path for built-in, INI-backed, HAL-backed, and missing named-parameter lookup. It also directly checks browser SDK parameter-file restore/save through vendored `Interp::restore_parameters()` and `Interp::save_parameters()`, including the LinuxCNC-saved text and `.bak` backup, and directly checks browser SDK non-random/random tool-table load/save through vendored `tooldata_common.cc`. The same browser smoke uses real browser OPFS storage plus the interpreter SDK to restore/save LinuxCNC parameter files, directly checks missing-file success plus out-of-order parameter-file rejection through the same LinuxCNC `restore_parameters()` C ABI, and checks the random-toolchanger `tooldata_save()` result before OPFS text writeback, to reject invalid INI-derived parameter/tool-table file names through the OPFS path model after the names are parsed by the LinuxCNC-backed INI WASM SDK. It also verifies that explicit session parameter/tool-table file-name options override INI-derived names before OPFS text is copied into the LinuxCNC-backed WASM filesystem, and that absent INI file-name values use the default OPFS parameter/tool-table paths in a real browser session. It also writes vendored LinuxCNC `xyzac-trt`/`xyzbc-trt` INI, remap subroutines, and switchkins demo files, including `xyzac_switchkins_test_1.ngc`, `xyzac_switchkins_test_2.ngc`, `xyzac_switchkins_test_3.ngc`, and the larger `boat-xyzac.ngc`, `boat-xyzbc.ngc`, and `impeller-7bl-xyzac.ngc` demos, into the browser WASM filesystem. It also writes vendored LinuxCNC `xyzab-tdr` machine files and `xyzab-tdr-demo.ngc` into the browser WASM filesystem. It also writes vendored LinuxCNC bridge-mill machine files and `5axisgui.ngc` into the browser WASM filesystem. The browser smoke verifies `runFiveAxisRemapFile()` for the table-rotary-tilting, table-dual-rotary, and bridge-mill sample machines through the exported LinuxCNC remap/tool-table/file execution path. It also verifies the vendored LinuxCNC `configs/sim/axis/foam/foam.ngc`, `axis/geometry/xyzc.ngc`, and `axis/external_offsets/dyn_demo.ngc` programs through `runSimConfigProgram()`, which writes the browser WASM filesystem files and forwards to `runFileWithIni()`. It also verifies the bridge-mill `axis/vismach/5axis/bridgemill/5axisgui.ngc` program through `runSimConfigProgram()` with `executionMode: "fiveAxisRemap"`, which forwards to `runFiveAxisRemapFile()`. These paths use the real vendored executable `M110` and `M111` files for `USER_M_PATH` registration without spawning host processes. It also verifies the vendored LinuxCNC `tests/remap/duplicate-o-word`, NGC-only `tests/remap/fail/args.0`, `tests/remap/fail/args.1`, `tests/remap/fail/args.2`, `tests/remap/fail/body-ngc`, `tests/remap/m30-interaction`, `tests/remap/nested-remaps-oword`, `tests/remap/posargs.0`, and `tests/remap/sequencing` regressions through `runRemapFile()` or `runRemapFileContinueOnError()`, using the browser WASM filesystem and vendored LinuxCNC REMAP/O-word/file execution path without JavaScript remap semantics. It also writes the NGC-only vendored LinuxCNC `tests/remap/remap-io/test-ngc.ini` and `io_*.ngc` subroutines into the browser WASM filesystem and validates `runRemapIoMdiSequence()` through vendored LinuxCNC REMAP parsing and MDI execution without JavaScript M-code or I/O semantics. It also writes vendored LinuxCNC `tests/interp/do-while-break`, `tests/interp/oword-bug315`, `tests/interp/oword-bug315-p2`, `tests/interp/exists`, `tests/interp/return-value`, `tests/interp/subs-follow-main`, `tests/interp/fractional-linenumbers`, `tests/interp/cam-nisley`, `tests/interp/namedparam-bug424`, `tests/interp/inside-corners`, `tests/interp/inverse-time-with-comp`, and selected `tests/interp/rotation` `.ngc` files plus `tests/interp/sub-call-from-sub` `test.ini`, `test.ngc`, and `subs/*.ngc` files and `tests/interp/sequence-number` `test.ini`, `test.ngc`, and `rm400.ngc` plus `tests/interp/nested-sub-error` `test.ini`, `test.ngc`, and `subs/nested.ngc` and `tests/interp/nested-sub-in-file-error` `test.ini`, `test.ngc`, and `subs/sequential.ngc`, plus `tests/interp/abort-hot-comment` `test.ini` and `test.ngc`, plus `tests/interp/m19` `test.ini` and `test.ngc`, plus `tests/interp/magic_comments/param_format_printing` `test.ngc`, plus selected pure-interpreter `tests/interp/m98m99` cases covering Fanuc-style `M98/M99`, missing-P-word, missing-subprogram, mixed Fanuc/RS274NGC sub-style, and `DISABLE_FANUC_STYLE_SUB` INI-gated errors, main-program O-word termination rules, parameter scope, loop counts including `L0`, nested numbered subprograms, subprograms after main program text, leading-zero O-word lookup, named and numbered main programs, and expression-based O-sub/M98 calls, into the browser WASM filesystem and validates those upstream interpreter regressions through `runFile()` or `runFileWithIni()`, without JavaScript O-word, parameter, line-number, spindle-speed, spindle-orient, magic-comment formatting, M98/M99, subroutine lookup, or branch semantics. The aggregate host smoke script builds the INI, interpreter-core, and trajectory-planner WASM artifacts once, then runs the Node WASM smokes, the Node OPFS mock smoke, and the Chromium browser smokes. ## Source Coverage Every `.c` and `.cc` entry in `tools/source-manifest.txt` must have a corresponding `*_source_probe` entry in `build/native/source-probes.tsv`. The validation fails if: - a manifest source file lacks a source probe; - a source probe references a file not listed in the manifest; - a manifest file is duplicated; - vendored files drift byte-for-byte from upstream LinuxCNC. ## Current Native Harnesses | Harness | Purpose | | --- | --- | | `linuxcnc_ini_probe` | Validates vendored LinuxCNC INI parsing can be used standalone. | | `linuxcnc_interp_state_probe` | Validates interpreter state constants and structs compile under the standalone boundary. | | `linuxcnc_rs274_compile_probe` | Validates the upstream `tests/interp/compile` class remains a source/compile boundary rather than being misclassified as a runtime `.ngc` interpreter fixture. | | `linuxcnc_emc_status_probe` | Validates the standalone `emcStatus` machine-units status boundary used by vendored interpreter conversion and initialization code. | | `linuxcnc_namedparam_harness` | Validates LinuxCNC named parameter behavior, `_ini[...]`, and `_hal[...]` adapter resolution. | | `linuxcnc_interp_minimal_harness` | Runs G-code fixtures through vendored LinuxCNC parser/execution/conversion code, captures canonical events, and validates feed-rate state readback across length-unit changes. | | `linuxcnc_parameter_file_harness` | Validates LinuxCNC parameter file restore/save behavior and required/read-only parameter handling. | | `linuxcnc_interp_init_harness` | Validates vendored LinuxCNC `Interp::init()` emits canonical initialization boundaries, reads metric/inch machine units, and synchronizes current/selected tool slots through standalone status adapters. | | `linuxcnc_indexer_harness` | Validates vendored LinuxCNC single-axis rotary indexer dispatch emits lock/unlock and motion boundaries through the standalone event sink. | | `linuxcnc_remap_hal_sync_harness` | Validates vendored LinuxCNC `M68`/`M66` execution can drive the standalone HAL adapter boundary used by 5-axis switchkins remap files, including `_hal[motion.switchkins-type]` readback. | | `linuxcnc_5axis_remap_execute_harness` | Validates vendored LinuxCNC `REMAP` parsing plus NGC remap execution for the 5-axis `M429 -> M428 -> M430 -> M429` switchkins path in the `xyzac-trt` and `xyzbc-trt` sample machines, the two-remap `M429 -> M428 -> M429` path in the `xyzab-tdr` sample machine, and the bridge-mill `M429 -> M428 -> M430 -> M429` path where M428 selects the default bridge-mill kinematics. It loads vendored machine tool tables through LinuxCNC `tooldata_load()`, then runs vendored `xyzac_switchkins.ngc`, `xyzbc_switchkins.ngc`, `xyzac_switchkins_test_1.ngc`, `xyzac_switchkins_test_2.ngc`, `xyzac_switchkins_test_3.ngc`, `boat-xyzac.ngc`, `boat-xyzbc.ngc`, `impeller-7bl-xyzac.ngc`, `xyzab-tdr-demo.ngc`, and `5axisgui.ngc` through the LinuxCNC file `open/read/execute` path. | | `linuxcnc_duplicate_oword_remap_harness` | Validates vendored LinuxCNC upstream `tests/remap/duplicate-o-word`, NGC-only `tests/remap/fail/args.0`, `tests/remap/fail/args.1`, `tests/remap/fail/args.2`, `tests/remap/fail/body-ngc`, `tests/remap/m30-interaction`, `tests/remap/nested-remaps-oword`, `tests/remap/posargs.0`, `tests/remap/sequencing`, and the NGC-only `tests/remap/remap-io/test-ngc.ini` branch through LinuxCNC `REMAP` parsing, O-word remap dispatch, `OWORD_NARGS`, error-text reporting, G/M remap sequencing, remapped M62-M68/M66 MDI execution, and file `open/read/execute`. The standalone harness only supplies INI/file path setup, deterministic external input values, and canonical-event capture; it can continue after LinuxCNC errors for upstream `rs274 -n 0` style tests and does not implement duplicate-label, O-word, M30, positional-argument, failure, sequencing, M62-M68, M66 input, or remap semantics. | | `linuxcnc_tp_api_probe` | Validates vendored LinuxCNC trajectory planner calls for linear, arc, and queued motion paths. | | `linuxcnc_kinematics_probe` | Validates vendored LinuxCNC `trivkins.c` plus `kins_util.c` initialize and perform identity forward/inverse mapping through the standalone HAL/RTAPI boundary. | | `linuxcnc_5axis_kinematics_probe` | Validates vendored LinuxCNC `5axiskins.c` through `switchkins.c`, including 5-axis forward/inverse round-trip behavior and switching to identity kinematics. | | `linuxcnc_xyzac_trt_kinematics_probe` | Validates vendored LinuxCNC XYZAC TRT kinematics through `switchkins.c`, including forward/inverse round-trip behavior and switching to identity kinematics. | | `linuxcnc_xyzbc_trt_kinematics_probe` | Validates vendored LinuxCNC XYZBC TRT kinematics through `switchkins.c`, including forward/inverse round-trip behavior and switching to identity kinematics. | | `linuxcnc_corexy_kinematics_probe` | Validates vendored LinuxCNC CoreXY forward/inverse behavior through the standalone HAL/RTAPI boundary. | | `linuxcnc_rotate_kinematics_probe` | Validates vendored LinuxCNC rotated-axis forward/inverse behavior. | | `linuxcnc_rose_kinematics_probe` | Validates vendored LinuxCNC rose kinematics forward/inverse behavior. | | `linuxcnc_max_kinematics_probe` | Validates vendored LinuxCNC max kinematics forward/inverse behavior. | | `linuxcnc_lineardelta_kinematics_probe` | Validates vendored LinuxCNC linear-delta inverse/forward pose round-trip behavior. | | `linuxcnc_rotarydelta_kinematics_probe` | Validates vendored LinuxCNC rotary-delta inverse/forward pose round-trip behavior. | | `linuxcnc_scorbot_kinematics_probe` | Validates vendored LinuxCNC Scorbot forward/inverse behavior and pose round-trip behavior. | | `linuxcnc_tripod_kinematics_probe` | Validates vendored LinuxCNC tripod inverse/forward behavior, including below-platform flag behavior. | | `linuxcnc_scara_kinematics_probe` | Validates vendored LinuxCNC SCARA forward/inverse behavior and switching to identity kinematics. | | `linuxcnc_puma_kinematics_probe` | Validates vendored LinuxCNC PUMA forward/inverse behavior, pose round-trip behavior, and switching to identity kinematics. | | `linuxcnc_genser_kinematics_probe` | Validates vendored LinuxCNC generic serial kinematics forward/inverse behavior and switching to identity kinematics. | | `linuxcnc_genhex_kinematics_probe` | Validates vendored LinuxCNC generic hexapod inverse/forward behavior, including the switchkins iterative-forward warmup path. | | `linuxcnc_pentakins_kinematics_probe` | Validates vendored LinuxCNC pentapod inverse/forward pose round-trip behavior. | ## Current WASM Harnesses | Harness | Purpose | | --- | --- | | `tests/wasm/node/verify_ini_wasm.sh` | Validates the browser-facing INI WASM module can be built from vendored LinuxCNC `inifile.cc`, loaded through the JS SDK in Node, and queried through the exported C ABI, including LinuxCNC-backed boolean conversion and machine-session file-name string lookup. | | `tests/wasm/node/verify_interp_wasm.sh` | Validates the interpreter-core WASM module can be built from vendored LinuxCNC interpreter/remap source, loaded through the interpreter JS SDK, run the first fixture group through `Interp::execute()` and selected file fixtures plus vendored upstream `tests/interp` regression files through `Interp::open()`/`read()`/`execute()`, match the native canonical event plus required state readback fixtures, emit `run_step` execution-status records with LinuxCNC line number, encoded source statement, return code, and interpreter axis positions for file execution, cover vendored `tests/interp/flowsnake` recursive O-word file execution, `tests/interp/g6164` path-control and naive-cam tolerance execution, `tests/interp/oword-unwind` continue-on-error stack unwind behavior through planner-staged INI context, selected `tests/interp/bad` file-error paths, and `tests/interp/g33.1` rigid-tap file execution, run vendored `xyzac-trt`/`xyzbc-trt` table-rotary-tilting and `xyzab-tdr` table-dual-rotary switchkins remap demo files through the WASM C ABI/SDK path, and run parameter-file restore/save through vendored LinuxCNC `Interp::restore_parameters()` and `Interp::save_parameters()`. | | `tests/wasm/node/verify_sim_configs_wasm.sh` | Validates representative vendored LinuxCNC `configs/sim` programs in Node WASM through `planSimConfigStaging()` plus `runSimConfigProgram()`. The generic `planIniFileContextStaging()` planner and its sim-config wrapper use INI text and `tools/source-manifest.txt` to collect the program, INI, tool table, parameter file when vendored, `SUBROUTINE_PATH` files, `USER_M_PATH` files, and remap-NGC files before forwarding to `runFileWithIni()` or `runFiveAxisRemapFile()`. This covers INI-driven `U/V/W` axis mask handling, real `USER_M_PATH` registration for executable `M110`/`M111`, all four current external-offset M111 expected-failure programs, deterministic `woodpecker/on_abort.ngc` file execution, plain INI/tool-table execution through `axis/gladevcp/probe.ngc`, `SUBROUTINE_PATH` staging for `opa_demo.ngc -> circles.ngc`, bridge-mill remap-subroutine staging, vendored LinuxCNC bridge-mill and `melfa-sim` NGC remap execution, and PUMA machine-context execution without spawning host processes. The same smoke includes synthetic staging-plan assertions for generic `TOOL_TABLE`, `PARAMETER_FILE`, multi-directory `SUBROUTINE_PATH`, `USER_M_PATH`, and `REMAP ... ngc=...` file collection. | | `tests/wasm/node/verify_sim_configs_inventory_wasm.sh` | Validates the first machine-readable Node inventory layer for `configs/sim`. It ensures native `build/native/sim-configs/summary.tsv`, generated `class-summary.tsv`, and generated `path-matrix.tsv` exist; verifies that generated `path-matrix.tsv` and tracked `docs/sim-configs-coverage-matrix.md` contain the same 159 paths as native `summary.tsv`; checks tracked matrix fields for class, native status, expected-failure reason, and blocked kind drift against generated `path-matrix.tsv`; and checks that generated `class-summary.tsv` matches class/status/expected-failure counts derived from `summary.tsv`. It then executes only entries that are currently vendored and have a defined standalone/WASM runtime path, and writes the sim-config inventory TSV artifacts. The boundary summary records one row per native inventory path with the matrix block, SDK classifier recommendation, declared HAL/UI/HALUI/Python process dependencies, `[EMCIO]DB_PROGRAM`, and execution-chain user-M codes; vendored INI rows must have an available classifier report, vendored hard blocks fail on classifier/matrix drift, safe process-declaring representatives must remain Node/browser `REP` rows with the expected process flag combinations rather than full-process promotions, and the designed full-process blocked rows must remain non-`REP` until their proof criteria are met. The generated inventory summary also requires all hard-blocked rows to remain `SKIP` with matching reasons, and `skip-summary.tsv` must match the matrix-derived skip counts. The blocked-dependency and boundary summaries record hard blocked Python-remap, tool-database, and external user-M rows from source `linuxcnc/configs/sim` INI files for dependency accounting only, including LinuxCNC source/config ownership fields, user-M script side effects, tool DB protocol evidence, Python runtime owner evidence, and completion criteria that all remain non-executing. Current gate: `executed=28`, `passed=28`, `skipped=131`, `unexpected_fail=0`; current skip/block counts are `ASSET_ONLY=65`, `L4_PYTHON_REMAP=53`, `L4_TOOL_DB=1`, `L4_USER_M_PROCESS=1`, `NON_MAIN_CLASS=10`, and `UPSTREAM_DEMO=1`. The executed set now includes the deterministic `woodpecker` plus `qtdragon` / `qtdragon_hd` / `qtvcp_screens` `on_abort.ngc` family, `axis/gladevcp/probe.ngc`, `axis/rose_engine/rcone_demo.ngc`, `axis/vismach/melfa-sim/example.ngc`, and the `axis/vismach/puma` sample programs after vendoring the required machine INI, tool-table, and remap-subroutine inputs. When an upstream INI declares a missing local tool table but the native harness resolved a valid fallback table, the Node inventory stages that native-selected table at the INI-declared path so WASM execution uses the same machine context. The skip reasons are explicit: `NON_MAIN_CLASS`, `L4-TOOL-DB`, `L4-USER-M-PROCESS`, `L4-PYTHON-REMAP`, and `UPSTREAM-DEMO`; an eligible row that lacks vendored machine context is reported as an inventory failure. This runner is an inventory source-of-truth for Node WASM and is intentionally narrower than a browser full inventory. | | `tests/wasm/node/verify_nc_files_wasm.sh` | Validates representative vendored LinuxCNC `nc_files` examples in Node WASM by copying `3D_Chips.ngc`, `arcspiral.ngc`, `hole-circle.ngc`, `factorial.ngc`, and `m6demo.ngc` into the Emscripten filesystem and forwarding to the LinuxCNC-backed `Interp::open()`/`read()`/`execute()` path. `3D_Chips.ngc` is staged with a minimal INI-declared `tool.tbl` because the upstream program contains `T1 M6`; JavaScript only stages files and checks LinuxCNC output, including `run_step` status records, and does not implement G-code, O-word, tool-change, or M-code behavior. | | `tests/wasm/node/verify_tp_wasm.sh` | Validates a standalone trajectory-planner WASM module can be built from vendored LinuxCNC TP/TC/Ruckig support source, loaded in Node, and run the same linear, arc, and queued-line planner probe paths covered by the native TP harness. | | `tests/opfs/node/verify_file_service.sh` | Validates the host-owned OPFS text-file adapter, path model, session snapshot store including custom filenames and envelope/path rejection paths, machine file store, G-code text store including filename rejection paths, OPFS-to-WASM parameter/tool-table bridges, and grouped machine-session loading without moving file persistence, parameter semantics, or tool-table semantics into the WASM core. | | `tests/browser/verify_ini_panel_browser.sh` | Validates the INI SDK, INI/interpreter WASM module loading, LinuxCNC-backed INI machine-session file-name string lookup, OPFS text-file round trip, generic session snapshot round trip plus custom filename and envelope/path rejection paths, machine file text round trip, G-code text round trip plus filename rejection paths, and the INI panel UI's machine-session load with default OPFS parameter/tool-table file mapping, G-code run, `run_step`-backed progress/line/statement/axis display, canonical-event display paths, and 5-axis remap demo action in a real browser runtime. | | `tests/browser/verify_interp_browser.sh` | Validates the interpreter-core WASM module loads through the interpreter JS SDK in a real browser runtime and runs selected positive and negative canonical fixtures plus vendored upstream `tests/interp` regression files through vendored LinuxCNC `Interp::execute()` and `Interp::open()`/`read()`/`execute()` via the exported C ABI, including direct browser SDK and OPFS-backed parameter-file restore/save, non-random/random tool-table load/save through vendored LinuxCNC source, vendored `xyzac-trt`/`xyzbc-trt` table-rotary-tilting and `xyzab-tdr` table-dual-rotary switchkins remap demo execution, representative vendored `configs/sim` `foam`, `geometry`, `external_offsets`, `axis/gladevcp/probe.ngc`, deterministic `woodpecker/on_abort.ngc`, bridge-mill, `melfa-sim`, and `puma_cube.ngc` programs through `runSimConfigProgram()`, representative vendored `nc_files` examples through `runFile()` or `runFileWithIni()` when the upstream file requires INI/tool-table context, and a synthetic browser assertion that `planIniFileContextStaging()` can collect INI, program, tool-table, parameter, multi-directory subroutine, executable user-M, and remap-NGC files using only manifest text. | | `tests/host/verify_host_smokes.sh` | Runs the current host-side Node, WASM interpreter-core, sim-config representative smoke, sim-config Node inventory, WASM trajectory-planner, OPFS, and browser smoke validation with shared WASM builds. | ## Fixture Coverage Positive G-code fixtures currently cover: - linear traverse/feed - arc semantics - modal absolute/incremental motion - position parameters - canned cycles - coordinate offsets - G53 machine-coordinate motion - feed and motion control modes - probing - threading and rigid tap - NURBS G5/G6 - spindle orient - tool semantics - tool table setup - tool-data reload boundary - interpreter state-tag boundary - percent-delimited file `FINISH` boundary - file-open `ON_RESET` boundary - comment logging canonical calls - local, INI-backed named parameters and numbered parameters - O-word subroutines - continue-on-error O-word unwind - program-end modal reset - canonical runtime edge calls Negative fixtures currently cover: - zero-feed `G1` - arc radius mismatch - zero-radius arc - G53 incremental-mode rejection - read-only named parameter writes - read-only numbered parameter writes - missing tool - missing tool length offset The negative fixture expectations are also checked against upstream `rs274 -g`: the baseline requires LinuxCNC to reject each program, to emit the expected error text, and to omit the canonical event lines marked as absent in `tests/fixtures/canon_errors/`. ## Validation Boundaries Current full-core validation is native-only. WASM/SDK validation covers the INI parser smoke harness and an initial interpreter-core canonical event smoke for `minimal_linear`, `arc_semantics`, `length_units`, `modal_incremental`, `plane_selection`, `coordinate_offsets`, `g53_machine_coordinates`, `feed_control_modes`, `position_params`, `probe_semantics`, `spindle_orient`, `comment_logging`, `numbered_params`, `tool_semantics`, `tool_table_setup`, `tool_reload`, `canned_cycles`, `cutter_comp_motion`, `threading_sync`, `nurbs_g5_semantics`, `nurbs_g6_semantics`, `state_tag_motion`, `canon_runtime_edges`, `program_end_modal_reset`, `namedparam_ini_semantics`, and `namedparam_semantics` through both Node WASM and browser INI-aware program ABI smoke coverage, plus the `g1_zero_feed`, `arc_radius_mismatch`, `arc_zero_radius`, `cutter_comp_plane_change`, `g53_incremental`, `namedparam_readonly`, `numbered_param_readonly`, `tool_not_found`, and `tool_length_offset_not_found` negative fixtures. The WASM interpreter file path additionally covers the same canonical-event fixture group, plus `namedparam_ini_semantics` and `namedparam_semantics` through the INI-aware file execution ABI, `file_open_reset`, `percent_file_finish`, `oword_subroutine`, `g6164`, and `oword_unwind`. `position_params` uses a dedicated file-path expectation under `tests/fixtures/canon_file/` because LinuxCNC file execution advances the post-execute position parameters differently than the line-by-line MDI smoke; both expectations now also pin post-execute modal, override, spindle, mist, and flood `_setup` state readback. `coordinate_offsets` also uses a dedicated file-path expectation because LinuxCNC file execution leaves the post-execute position parameters at the file-path reset state while the line-by-line MDI path exposes the active G55 offset values; both paths pin the post-execute modal, override, spindle, mist, and flood `_setup` state. `tool_semantics` also pins the post-execute position-parameter and modal, override, spindle, mist, and flood `_setup` state after T/M6/G43/G49/M61 tool behavior. `feed_control_modes` pins the post-execute feed and motion-control modal state plus the same position-parameter, override, spindle, mist, and flood `_setup` state readback after G93/G94/G95 and G61/G61.1/G64 transitions. The same Node WASM and browser file-path smokes also cover the negative fixture group and check the LinuxCNC file-execution error text plus absent canonical motion constraints where applicable. `canon_runtime_edges` also pins the vendored interpreter's post-program modal, override, spindle, mist, and flood `_setup` state readback after the canonical runtime-edge calls complete. The Node WASM and browser interpreter smokes also cover LinuxCNC parameter-file restore/save behavior through the exported C ABI, including out-of-order file rejection, missing-file success, missing required numeric parameter defaulting, required numeric parameter writeback, removal of named-parameter-only lines from saved output, and the `.bak` backup produced by vendored `save_parameters()`, including direct browser SDK readback from the Emscripten filesystem, browser OPFS readback of the backup text after the host bridge writes it to persistent storage, plus INI-derived custom and explicit host override parameter-file paths saved back to OPFS with their LinuxCNC-produced backup text. It also covers LinuxCNC tool-table load/save behavior through vendored `tooldata_common.cc`, including the non-random and random-toolchanger `tooldata_init()` branches, with the SDK only copying text into the Emscripten filesystem and calling the exported C ABI; the browser smoke directly reads back both non-random and random saved tool-table text from the Emscripten filesystem, checks the random-toolchanger `tooldata_save()` C ABI result before OPFS persistence writes the saved table text back, and verifies that INI-derived custom and explicit host override tool-table OPFS paths can be saved and read back after the table is loaded through vendored LinuxCNC. The same Node WASM and browser interpreter smokes now validate the exported `Interp::init()`/`Interp::synch()` probe for initialization canonical events, metric/inch `emcStatus` machine-unit conversion, and current/selected tool slot synchronization. They also validate the exported rotary-indexer probe for vendored LinuxCNC `UNLOCK_ROTARY`/`LOCK_ROTARY` dispatch around a single-axis `G0 A...` move, plus the exported named-parameter probe for direct LinuxCNC `init_named_parameters()` and `find_named_param()` lookup of built-in, INI-backed, HAL-backed, and missing named parameters. OPFS validation covers the JavaScript host-boundary adapter, the INI browser smoke harness, the INI panel UI's machine-session load and G-code run buttons, the raw canonical-event display fed directly by LinuxCNC interpreter WASM output, the Node parameter/tool-table bridges that copy OPFS text through the SDK into vendored LinuxCNC file APIs, the Node machine-session bridge that groups INI, parameter, and tool-table loading, the random-toolchanger flag derived from vendored LinuxCNC INI boolean parsing, INI-derived `[RS274NGC]PARAMETER_FILE` and `[EMCIO]TOOL_TABLE` file names mapped to OPFS machine files, OPFS path-model rejection of invalid INI-derived file names, explicit host session file-name overrides taking precedence over INI-derived names, default host path fallback when INI file-name values are absent, session snapshot custom filename handling plus envelope/path rejection for unsupported format/version, wrong session id, and invalid snapshot filenames, and a browser interpreter smoke that uses the same session bridge with real LinuxCNC INI WASM parsing before saving OPFS-backed parameter and tool-table text through vendored LinuxCNC file APIs, including default OPFS path fallback when INI file-name values are absent. Full browser coverage, full SDK coverage, and richer machine-state validation remain future work. ## WASM/Browser Fixture Matrix The executable fixture lists for Node WASM and browser interpreter smoke tests are centralized in `tests/fixtures/interp-fixture-matrix.mjs`. Additions to the matrix must continue to route execution through the SDK and exported C ABI backed by vendored LinuxCNC interpreter code; the matrix is only a test coverage list, not a CNC behavior implementation. Node WASM `Interp::execute()` coverage currently includes: - `minimal_linear` - `arc_semantics` - `length_units` - `modal_incremental` - `plane_selection` - `coordinate_offsets` - `g53_machine_coordinates` - `feed_control_modes` - `position_params` - `probe_semantics` - `spindle_orient` - `comment_logging` - `numbered_params` - `tool_semantics` - `tool_table_setup` - `tool_reload` - `canned_cycles` - `cutter_comp_motion` - `threading_sync` - `nurbs_g5_semantics` - `nurbs_g6_semantics` - `state_tag_motion` - `canon_runtime_edges` - `program_end_modal_reset` - `namedparam_ini_semantics` through the INI-aware program ABI - `namedparam_semantics` through the INI-aware program ABI Node WASM file-path coverage currently includes: - `minimal_linear` - `arc_semantics` - `length_units` - `modal_incremental` - `plane_selection` - `g53_machine_coordinates` - `feed_control_modes` - `probe_semantics` - `spindle_orient` - `comment_logging` - `numbered_params` - `tool_semantics` - `tool_table_setup` - `tool_reload` - `canned_cycles` - `cutter_comp_motion` - `threading_sync` - `nurbs_g5_semantics` - `nurbs_g6_semantics` - `state_tag_motion` - `canon_runtime_edges` - `program_end_modal_reset` - `file_open_reset` - `percent_file_finish` - `oword_subroutine` - `coordinate_offsets` through the dedicated `canon_file/` expectation - `position_params` through the dedicated `canon_file/` expectation - `namedparam_ini_semantics` through the INI-aware file ABI - `namedparam_semantics` through the INI-aware file ABI Node WASM file-path negative coverage currently includes every fixture under `tests/fixtures/gcode_errors/`: - `g1_zero_feed` - `arc_radius_mismatch` - `arc_zero_radius` - `cutter_comp_plane_change` - `g53_incremental` - `namedparam_readonly` - `numbered_param_readonly` - `tool_length_offset_not_found` - `tool_not_found` Browser interpreter file-path negative coverage currently includes the same negative fixture list through `Interp::open()`/`read()`/`execute()`: - `g1_zero_feed` - `arc_radius_mismatch` - `arc_zero_radius` - `cutter_comp_plane_change` - `g53_incremental` - `namedparam_readonly` - `numbered_param_readonly` - `tool_length_offset_not_found` - `tool_not_found` Browser interpreter `Interp::execute()` coverage currently includes: - `minimal_linear` - `arc_semantics` - `length_units` - `modal_incremental` - `plane_selection` - `coordinate_offsets` - `g53_machine_coordinates` - `feed_control_modes` - `position_params` - `canned_cycles` - `numbered_params` - `comment_logging` - `tool_semantics` - `tool_table_setup` - `probe_semantics` - `spindle_orient` - `cutter_comp_motion` - `threading_sync` - `nurbs_g5_semantics` - `nurbs_g6_semantics` - `state_tag_motion` - `canon_runtime_edges` - `tool_reload` - `program_end_modal_reset` - `namedparam_ini_semantics` through the INI-aware program ABI - `namedparam_semantics` through the INI-aware program ABI Browser interpreter negative coverage currently includes every fixture under `tests/fixtures/gcode_errors/`: - `g1_zero_feed` - `arc_radius_mismatch` - `arc_zero_radius` - `g53_incremental` - `cutter_comp_plane_change` - `namedparam_readonly` - `numbered_param_readonly` - `tool_length_offset_not_found` - `tool_not_found` Browser interpreter file-path coverage currently includes the same `INTERP_FILE_FIXTURES` list as the Node WASM smoke: - `minimal_linear` - `arc_semantics` - `length_units` - `modal_incremental` - `plane_selection` - `g53_machine_coordinates` - `feed_control_modes` - `probe_semantics` - `spindle_orient` - `comment_logging` - `numbered_params` - `tool_semantics` - `tool_table_setup` - `tool_reload` - `canned_cycles` - `cutter_comp_motion` - `threading_sync` - `nurbs_g5_semantics` - `nurbs_g6_semantics` - `state_tag_motion` - `canon_runtime_edges` - `program_end_modal_reset` - `file_open_reset` - `percent_file_finish` - `oword_subroutine` - `coordinate_offsets` through the dedicated `canon_file/` expectation - `position_params` through the dedicated `canon_file/` expectation - `namedparam_ini_semantics` through the INI-aware file ABI - `namedparam_semantics` through the INI-aware file ABI All current positive G-code fixtures have browser interpreter smoke coverage through either `Interp::execute()`, the file-path ABI, or the INI-aware file-path ABI. The current fixture expectations validate standalone behavior against both the vendored LinuxCNC source path and an upstream `rs274` side-by-side baseline for parser/conversion, arc geometry, offsets, feed-control and feed-state readback, comment/logging, numbered-parameter, local named-parameter plus `_ini[...]` lookup through `rs274 -i`, probing, spindle-orient, file-open reset, file-finish, tool-reload, tool select/change/length-offset, M61 current-tool-number update, canned-cycle, state-tag motion, tool-table setup, and O-word subroutine fixtures, plus vendored `tests/interp/flowsnake` recursive O-word toolpath, `tests/interp/cam-nisley` storm-door latch cam execution with upstream tool-table context and a bare-run missing-tool negative check, `tests/interp/inside-corners` cutter-compensation concave/convex/tangent geometry across XY and ZX planes, `tests/interp/inverse-time-with-comp` inverse-time feed and cutter-compensation interaction, selected upstream `tests/interp/bad` file-error paths including canned-cycle A-axis rejection, center-format arc radius mismatch rejection, and selected upstream `tests/interp/good` center-format arc tolerance acceptance, selected `tests/interp/g72-*` lathe facing canned-cycle iteration regressions, selected `tests/interp/g71-*` lathe roughing/finish canned-cycle regressions, `tests/interp/g76` lathe threading with upstream tool-table context, cutter-compensation rejection, selected standalone `tests/ccomp` cutter-compensation file execution with upstream tool tables, threading/rigid tap, vendored `tests/interp/g33.1` rigid-tap file execution, NURBS dispatch boundaries, and the comparable canonical runtime edge and program-end cleanup calls. The standalone vendored-source harness, Node WASM smoke, and browser smoke also pin `coordinate_offsets` MDI/file-path, `feed_control_modes`, `run_step` file-execution status output for line number, URI-encoded source statement, return code, and current interpreter axis positions, the `position_params` MDI/file-path, `tool_semantics`, and `canon_runtime_edges` post-program modal, override, spindle, mist, and flood `_setup` state. Native and WASM standalone checks also cover the user M-code registration boundary for INI-declared `M110`/`M111` handlers while keeping process execution outside the browser/WASM runtime. Node and browser WASM sim-config coverage now run the real vendored `axis/geometry/xyzc.ngc` and the `axis/external_offsets/dyn_demo.ngc`, `eoffsets.ngc`, `jwp_z.ngc`, and `opa_demo.ngc` programs with their executable `M110`/`M111` files, `opa_demo.ngc`'s `SUBROUTINE_PATH` dependency on `circles.ngc`, `axis/foam/foam.ngc` with its `U/V` machine configuration and shared `axis/sim.tbl` tool table staged beside the INI, and bridge-mill `5axisgui.ngc` with its `W` machine coordinates. The same upstream baseline also validates the current negative fixture error text and absent canonical-event constraints. Fixtures that depend on standalone-only runtime adapters, HAL state, upstream `rs274` output gaps such as `WAIT` or hidden NURBS control-point detail, or richer machine session state still need dedicated native LinuxCNC baselines. Remaining positive fixtures that are not in the upstream `rs274` side-by-side baseline are intentionally held out until they get a dedicated native LinuxCNC baseline: `namedparam_semantics` still depends on the standalone HAL adapter, while `namedparam_ini_semantics` now covers the local named-parameter and LinuxCNC `_ini[...]` subset against upstream `rs274 -i`. `state_tag_motion` now compares its motion events with upstream `rs274`, while `UPDATE_TAG` events remain a standalone state-tag capture boundary. `tool_semantics` now compares T/M6/G43/G49 and M61 canonical/current-pocket readback with upstream `rs274 -t -i`; `Interp::synch()` current/selected tool slot reads are covered by the native init harness. The kinematics probes currently cover LinuxCNC identity/trivial kinematics, the switchable `5axiskins` XYZBCW bridge-mill model, TRT `xyzac`/`xyzbc` table-rotary models, CoreXY, rotated-axis, rose, max, linear-delta, rotary-delta, Scorbot, tripod, SCARA, PUMA, generic serial, generic hexapod, and pentapod models. `linuxcnc_5axis_remap_asset_probe` pins the LinuxCNC sample-machine assets that define five-axis switchkins `M428`, `M429`, and `M430`: bridge-mill, dual-rotary, and table-rotary-tilting INI files, `remap_subs/*.ngc`, HAL switchkins links, tool tables, and demo programs. It verifies that these commands remain LinuxCNC `REMAP` entries backed by LinuxCNC NGC subroutines using `M68`, `M66`, and `_hal[motion.switchkins-type]`; it does not implement the remap execution path. `linuxcnc_remap_parse_harness` links vendored `interp_remap.cc` for the standalone remap descriptor path. It reads the vendored `xyzac-trt`, `xyzbc-trt`, `xyzab-tdr`, and bridge-mill INI `REMAP` entries, resolves their `remap_subs/*.ngc` files through LinuxCNC `find_ngc_file()`, and validates the resulting `_setup.m_remapped` descriptors for each machine's LinuxCNC-defined `M428`/`M429`/`M430` set. Python callbacks remain runtime boundaries. Native and WASM validation now execute the NGC remap/file paths through vendored LinuxCNC O-word dispatch and the standalone HAL adapter boundary. `linuxcnc_duplicate_oword_remap_harness` vendors LinuxCNC's upstream `tests/remap/duplicate-o-word` and `tests/remap/m30-interaction` files unchanged and runs each `test.ngc` with its `test.ini` through vendored `Interp::parse_remap()`, `open()`, `read()`, and `execute()`. Native, Node WASM, and browser interpreter validation assert the same successful LinuxCNC regression paths, including the remapped `M207`/`M208` messages and final `FINISH()` event for duplicate O-word, and the `M400 M30` remap-level interaction with `PROGRAM_END`. `linuxcnc_interp_minimal_harness` now also runs selected vendored LinuxCNC upstream `tests/interp/*/test.ngc` files through vendored `Interp::open()`, `read()`, and `execute()`, using LinuxCNC INI `SUBROUTINE_PATH` for `tests/interp/sub-call-from-sub`, `tests/interp/sequence-number`, and `tests/interp/nested-sub-error`, `tests/interp/nested-sub-in-file-error`, and `tests/interp/abort-hot-comment`, plus LinuxCNC `[RS274NGC]ORIENT_OFFSET` for `tests/interp/m19`. Native, Node WASM, and browser interpreter validation assert the LinuxCNC canonical messages, canonical events, error texts, and interpreter state for O-word loop/break/subroutine paths, dynamic O-word calls, `EXISTS[]`, subroutine return values, subroutines after main programs, fractional line numbers, named-parameter parsing, M19 spindle-orient offset and wait timeout canonical events, magic-comment parameter formatting, valid external subroutine calls from another external subroutine, external-subroutine `#<_line>` reporting, nested-subroutine-definition rejection, and blocked forward seek to a later numbered subroutine in the same external file, selected `tests/interp/rotation` absolute-position `#<_abs_x>`, `#<_abs_y>`, and `#<_abs_z>` reporting under G54, G92, XY rotation, and unit changes plus rotated-coordinate `G28` and `G53` endpoint behavior, selected `tests/interp/m98m99` Fanuc-style `M98/M99` subprogram calls, missing-P-word, missing-subprogram, mixed Fanuc/RS274NGC sub-style, and `DISABLE_FANUC_STYLE_SUB` INI-gated errors, main-program O-word termination rules, parameter-scope differences, loop counts including `L0`, nested numbered subprograms, subprograms after main program text, leading-zero O-word lookup, named/numbered main programs, and O-expression calls, plus `(ABORT,...)` hot-comment numbered, named, and INI-parameter expansion, with skipped branch/subroutine messages and post-abort program end asserted absent where applicable. The same native, Node WASM, and browser interpreter validation also stages an INI-declared variable file to verify LinuxCNC G92 startup persistence and the `DISABLE_G92_PERSISTENCE` startup clear path through vendored interpreter initialization.