diff --git a/text2.txt b/text2.txt new file mode 100644 index 0000000..e97f89c --- /dev/null +++ b/text2.txt @@ -0,0 +1,274 @@ +新下一步执行计划 + +生成时间:2026-06-09 14:20 CST + +本计划接替 `text.txt`。后续执行以本文件为准。 + +项目纪律: + +- 数控/G-code/remap/tool/parameter/planner/kinematics/user-M 语义必须来自 + LinuxCNC upstream 或 vendored LinuxCNC C/C++ source。 +- 本项目允许写的代码范围是:构建、source sync、runtime shim、filesystem + staging、OPFS、WASM/browser boundary、测试胶水、文档。 +- 不通过修改 G-code 语义、JS 解释逻辑、或 standalone `Interp::...` 实现来让 + 测试通过。 +- 需要 INI/tool table/parameter file/SUBROUTINE_PATH/USER_M_PATH/remap-NGC + 上下文的程序,必须带上下文运行,不能脱离配置单独判断。 +- browser 不能依赖目录枚举。browser/Node 共享 staging 时,优先使用 + `tools/source-manifest.txt` + INI 文本生成计划。 + +当前已完成基线: + +- 规划 i:G-code run_step 状态输出已完成第一阶段。 + 已输出当前行号、statement_uri、进度相关 step、X/Y/Z/A/B/C/U/V/W 位置。 + UI 已优先解析 run_step,fallback 到 canonical event。 + +- 规划 ii:基础 G-code smoke 已固化代表集。 + `nc_files/3D_Chips.ngc` 已按 tool-table context 运行,裸跑缺 tool 的负向边界 + 已明确。 + +- configs/sim 代表 runtime edge 已覆盖: + `axis/foam` U/V axis mask、bridge-mill W/remap path、`axis/geometry` M110、 + `external_offsets` M111 和 subroutine staging 已在 native/WASM/browser + representative smoke 中验证。 + +- 文件上下文 staging 规则已抽成通用 SDK helper: + `planIniFileContextStaging()` 负责 generic INI-context manifest-based plan; + `planSimConfigStaging()` 是 `configs/sim` wrapper; + Node 和真实 browser smoke 已覆盖 INI、OPEN_FILE、TOOL_TABLE、PARAMETER_FILE、 + multi-directory SUBROUTINE_PATH、USER_M_PATH、executable user-M、remap-NGC 和 + wasmPath 输出。 + +- 测试分层文档已补齐: + `docs/compatibility-validation.md` 已记录 4 层测试的入口、当前结果、 + LinuxCNC-owned behavior、host/WASM adapter allowance 和 expected-failure + policy。 + +当前验证口径: + +- Layer 1: `wasm-port/tests/native/verify_nc_files.sh` + 当前基线:total 107, pass 101, expected_fail 6, unexpected_fail 0。 + +- Layer 2: `wasm-port/tests/native/verify_sim_configs.sh` + 当前基线:total 159, pass 151, expected_fail 8, unexpected_fail 0。 + +- Layer 3: `wasm-port/tests/native/verify_native_probes.sh` + 当前应通过,包含 source sync、no-standalone-semantics、native fixture + baseline、sim-config 和 nc_files checks。 + +- Layer 4: `wasm-port/tests/host/verify_host_smokes.sh` + 当前应通过,包含 Node WASM、OPFS、browser interpreter 和 browser INI panel + representative smoke。 + +新执行顺序: + +1. 先稳定当前大批改动,不继续扩大测试面 + +目标: + +- 对当前累计改动做一次完整一致性验证。 +- 确认 vendor manifest、native probes、Node/browser smoke 都仍处于可提交状态。 +- 在继续新增 upstream tests 前,先把当前批次变成一个清晰、可审查的工作集。 + +执行: + +```bash +git diff --check +wasm-port/tools/verify_vendor_sync.sh +wasm-port/tests/wasm/node/verify_interp_wasm.sh +wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh +wasm-port/tests/browser/verify_interp_browser.sh +wasm-port/tests/host/verify_host_smokes.sh +wasm-port/tests/native/verify_native_probes.sh +``` + +通过条件: + +- `git diff --check` clean。 +- `vendor sync validation complete`。 +- `interp_wasm_node_smoke=ok`。 +- `sim_configs_wasm_node_smoke=ok`。 +- `browser_interp_smoke=ok`。 +- `host_wasm_opfs_browser_smokes=ok`。 +- native summaries 中仍为: + `sim-configs total 159 pass 151 expected_fail 8 unexpected_fail 0` + 和 + `nc_files total 107 pass 101 expected_fail 6 unexpected_fail 0`。 + +不做: + +- 不新增 upstream fixture。 +- 不改 LinuxCNC vendored 文件内容。 +- 不把 expected failure 改成 pass,除非 runtime edge 已经通过 vendored source + 路径证明。 + +2. 整理当前大批改动的提交/审查边界 + +目标: + +- 把当前累计改动按逻辑拆成可审查批次。 +- 如果不提交,也至少在文档里列出可拆分边界,方便后续 review。 + +建议拆分边界: + +- Batch A: run_step 状态输出和 UI/browser/Node 断言。 +- Batch B: nc_files 代表 smoke 和 `3D_Chips.ngc` tool-table context。 +- Batch C: upstream `tests/interp/*`、`tests/ccomp/*` selected fixture 扩展。 +- Batch D: G92 parameter persistence、tool table、G10/G52/G71/G72/G76 等 + interpreter regression coverage。 +- Batch E: generic INI-context staging helper 和 Node/browser synthetic coverage。 +- Batch F: 文档分层、source reuse map、compatibility validation、tracker 更新。 + +执行: + +```bash +git status --short +git diff --stat +git diff --name-only +``` + +输出要求: + +- 记录每个 batch 对应文件。 +- 标明哪些新增 `wasm-port/vendor/linuxcnc/...` 文件必须由 + `tools/source-manifest.txt` 和 `verify_vendor_sync.sh` 覆盖。 + +3. 收敛 configs/sim 剩余 expected failure,不改语义 + +目标: + +- 继续分析 Layer 2 中 8 个 expected_fail。 +- 明确哪些只是 upstream `rs274` 缺 task/user-M/runtime context; + 哪些已经由 Layer 3/4 runtime representative smoke 覆盖; + 哪些仍需要新的 runtime adapter 或 blocked entry。 + +重点对象: + +- `axis/foam/foam.ngc` + 已有 U/V axis mask runtime coverage。确认 Layer 2 expected_fail 是否只属于 + native upstream standalone context 限制。 + +- `axis/vismach/5axis/bridgemill/5axisgui.ngc` + 已有 bridge-mill W/remap representative coverage。确认 expected_fail 是否只 + 属于 native full sim/task/HAL boundary。 + +- `axis/geometry/xyzc.ngc` + 已有 M110 USER_M_PATH deterministic boundary。确认 native expected_fail 与 + runtime coverage 对齐。 + +- `axis/external_offsets/*.ngc` + 已有 M111 deterministic boundary 和 `opa_demo.ngc -> circles.ngc` + SUBROUTINE_PATH staging。确认剩余 expected_fail 的具体原因。 + +- `incremental_repetition_g533.ngc` + 保留 upstream demo expected failure。禁止通过修改 G-code 语义或 runner + 语义让它 pass。 + +执行: + +```bash +wasm-port/tests/native/verify_sim_configs.sh +cat wasm-port/build/native/sim-configs/summary.tsv +``` + +产出: + +- 更新 `docs/compatibility-validation.md` 或 + `docs/linuxcnc-test-porting-tracker.md`,逐条记录 8 个 expected_fail 的当前 + 层级归因。 +- 如果某项已由 Layer 3/4 覆盖,写明对应验证命令和 smoke assertion。 +- 如果某项未覆盖,加入明确 blocked dependency 或下一步 runtime boundary。 + +4. 将 generic INI-context staging helper 用到更多手写 staging 点 + +目标: + +- 减少 Node/browser 测试中手写 `TOOL_TABLE`、`PARAMETER_FILE`、 + `SUBROUTINE_PATH`、`USER_M_PATH` 和 remap files 的重复。 +- 只迁移“已经 vendored 且 manifest 完整”的测试,不扩大功能面。 + +候选: + +- `tests/wasm/node/verify_interp_wasm.mjs` 中带 `test.ini`、`test.tbl`、 + `startup.var`、`subs/*.ngc` 的 upstream regression staging。 +- `tests/browser/interp_smoke.html` 中与 Node 同构的 upstream regression + staging。 +- 不急于迁移 five-axis 专用 staging,除非能保持 `executionMode: + "fiveAxisRemap"` 现有路径清晰。 + +执行原则: + +- 先抽小 helper:`loadPlannedVendorFiles(plan)` 或测试局部 helper。 +- 保持 `planIniFileContextStaging()` 只返回 plan,不读文件、不 fetch。 +- Node 侧从 filesystem 读 `vendor/linuxcnc/${sourceRel}`。 +- Browser 侧 fetch `../../vendor/linuxcnc/${sourceRel}`。 +- 每次迁移后跑: + +```bash +wasm-port/tests/wasm/node/verify_interp_wasm.sh +wasm-port/tests/browser/verify_interp_browser.sh +wasm-port/tests/host/verify_host_smokes.sh +``` + +5. 继续 upstream `tests/interp/*` intake,但必须小批量 + +前置条件: + +- 第 1 步完整验证通过。 +- 第 2 步当前工作集边界清楚。 +- 第 3 步 expected failure 归因没有新疑点。 + +候选优先级: + +- 纯 interpreter file execution。 +- 不需要 Python remap。 +- 不需要 full task/motion/HAL process。 +- 需要 tool table/parameter/subroutine context 的测试,必须通过 INI-context + staging 运行。 +- 有 upstream expected output 或可稳定断言 canonical event/error text。 + +候选方向: + +- `tests/interp/oword-unwind` + 可能适合 continue-on-error runner;先 native probe 验证,再 Node/browser。 + +- `tests/interp/g6164` + 先确认是否纯 interpreter、是否需要额外 machine/runtime context。 + +- `tests/interp/compile` + 先判断它是 compile/source test 还是 runtime interpreter test;不要误归类。 + +- `tests/interp/mdi-*`、`oword-mdi-*` + 默认视为 MDI/UI/full-process 候选,先加入 blocked table,除非能证明存在 + NGC-only subpath。 + +- `tests/interp/pymove`、`python-self` + 默认 blocked:Python O-word/remap boundary 未实现。 + +每个 intake 必须执行 checklist: + +- 记录 upstream path。 +- byte-for-byte vendor 原始文件。 +- 更新 `tools/source-manifest.txt` 和 vendor sync。 +- 确认 LinuxCNC source ownership。 +- 先 native harness/probe,再 Node WASM,再 browser。 +- 更新 `docs/source-reuse-map.md`、 + `docs/compatibility-validation.md`、 + `docs/linuxcnc-test-porting-tracker.md`。 +- 如 blocked,加入 blocked-test table 并写清 dependency。 + +6. 不做事项 + +- 不继续扩大 `configs/sim` 全量 WASM/browser 执行面,除非某个 expected failure + 已经有明确 runtime boundary 价值。 +- 不引入 JS G-code parser 或 JS remap/tool/parameter semantics。 +- 不编辑 `linuxcnc/` upstream 工作树。 +- 不修改 `wasm-port/vendor/linuxcnc/` vendored 文件内容;只能 byte-for-byte copy + upstream 文件。 +- 不绕过 `tools/verify_no_standalone_cnc_semantics.sh`。 + +推荐下一次立即执行: + +1. 运行第 1 步完整一致性验证。 +2. 如果通过,执行第 2 步,整理当前工作集 batch 边界。 +3. 然后再进入第 3 步,逐条归因 configs/sim 8 个 expected_fail。 diff --git a/text3.txt b/text3.txt new file mode 100644 index 0000000..ec781ef --- /dev/null +++ b/text3.txt @@ -0,0 +1,386 @@ +configs/sim 全面测试下一步实施计划 + +生成时间:2026-06-09 15:00 CST + +本计划接替 `text2.txt`。后续 `configs/sim` 相关工作以本文件为准。 + +目标定义: + +- 这里的“全部完成全面测试”不等于“让 `linuxcnc/configs/sim` 下所有 `.ngc` + 在 standalone `bin/rs274` 下全部 PASS”。 +- 正确目标是: + 1. 对 `configs/sim` 下所有 `.ngc` 建立完整 inventory; + 2. 每个文件都被归入明确类别; + 3. 每个类别都有正确入口点和验证层; + 4. 能在 standalone native/WASM/browser 中运行的,必须补齐覆盖; + 5. 不能在 standalone 路径中真实复现的,必须记录为 blocked,并写清依赖; + 6. 不通过修改 G-code 语义、JS 解释逻辑、或 project-owned standalone + interpreter 语义让测试“看起来通过”。 + +项目纪律: + +- CNC 语义来源只能是 LinuxCNC upstream 或 vendored LinuxCNC source。 +- `configs/sim` 程序必须在完整上下文下判断:INI、tool table、parameter file、 + `SUBROUTINE_PATH`、`USER_M_PATH`、remap-NGC、Python remap、task/runtime + 边界都要按 LinuxCNC 真实归属处理。 +- browser 不能依赖目录枚举;Node/browser staging 继续优先使用 + `tools/source-manifest.txt` + INI 文本生成计划。 +- 不为了“全面测试”而把 full-process / HAL / UI / linuxcncrsh / Python binding + 误降级为 standalone interpreter file execution。 + +当前真实基线: + +- Layer 2: `wasm-port/tests/native/verify_sim_configs.sh` + 当前基线:`total 159, pass 151, expected_fail 8, unexpected_fail 0`。 +- Layer 3: `wasm-port/tests/native/verify_native_probes.sh` + 当前通过,已经覆盖代表性 runtime edge: + `axis/foam` U/V、bridge-mill W/remap、`axis/geometry` M110、 + `axis/external_offsets` M111、`opa_demo.ngc -> circles.ngc`。 +- Layer 4: + `wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh`、 + `wasm-port/tests/browser/verify_interp_browser.sh`、 + `wasm-port/tests/host/verify_host_smokes.sh` + 当前通过,但只覆盖 representative subset,不是全量 `configs/sim`。 + +当前已知剩余 expected failure: + +- `axis/foam/foam.ngc` + native upstream standalone `rs274` 缺 U/V axis reader,上层 runtime 已覆盖。 +- `axis/vismach/5axis/bridgemill/5axisgui.ngc` + native upstream standalone `rs274` 缺 W axis reader,上层 runtime 已覆盖。 +- `axis/geometry/xyzc.ngc` + native upstream standalone `rs274` 缺 `USER_M_PATH` M110 注册,上层 runtime 已覆盖。 +- `axis/external_offsets/dyn_demo.ngc` +- `axis/external_offsets/eoffsets.ngc` +- `axis/external_offsets/jwp_z.ngc` +- `axis/external_offsets/opa_demo.ngc` + native upstream standalone `rs274` 缺 `USER_M_PATH` M111 注册,上层 runtime 已覆盖; + 其中 `opa_demo.ngc` 还依赖 `SUBROUTINE_PATH` `circles.ngc`,上层 runtime 已覆盖。 +- `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc` + 保持 upstream demo expected failure;禁止通过修改 G-code 或 JS 解释逻辑让它 PASS。 + +全面测试还缺哪些工作: + +1. 完整建立 `configs/sim` 程序级覆盖矩阵 + +当前问题: + +- 我们有 harness summary,但还没有一份“每个 `.ngc` 的归属矩阵”: + 哪些是 `main`、哪些是 `macro_load`、哪些是 `remap_subroutine`、 + 哪些只是 LinuxCNC native baseline、哪些已经进入 Layer 3、哪些已经进入 Layer 4、 + 哪些仍 blocked。 + +需要产出: + +- 一份 tracked matrix,建议新增: + +```text +wasm-port/docs/sim-configs-coverage-matrix.md +``` + +矩阵至少包含列: + +- `path` +- `class` +- `native_rs274_status` +- `expected_failure_reason` +- `layer3_runtime_probe` +- `layer4_node` +- `layer4_browser` +- `blocked_dependency` +- `notes` + +通过条件: + +- `wasm-port/build/native/sim-configs/summary.tsv` 中所有 159 条记录都能映射到 matrix。 +- matrix 中不能有“未分类”行。 + +2. 明确“全部”里的 blocked 边界,而不是继续误扩面 + +当前问题: + +- `configs/sim` 下面并不是所有 `.ngc` 都应该被强行推进到 browser full execution。 +- 还缺一份 `configs/sim` 专属 blocked policy,用来区分: + - pure interpreter / remap / INI-context 可移植程序; + - task/user-M/runtime edge 程序; + - Python remap/full-process/HAL/UI 依赖程序; + - demo edge / upstream malformed demo。 + +需要明确加入 blocked 的类: + +- 任何本质依赖 linuxcncrsh、GUI driver、HAL process、实时 motion 状态反馈、 + 外部 userspace component、或 Python binding API 的 sim-config path。 +- `mdi-*`、UI action、或只能通过 full task process 触发的配置流。 +- 不能通过 NGC-only subpath 提纯的 Python/full-process config family。 + +执行: + +- 从 `verify_sim_configs.sh` summary 和 `configs/sim` 路径结构出发, + 逐目录补 blocked classification。 +- 先补 family-level blocked,再细化到 program-level。 + +产出: + +- 更新 `docs/linuxcnc-test-porting-tracker.md` blocked table; +- 更新 `docs/compatibility-validation.md` 的 `configs/sim` 边界说明; +- 在新 matrix 中写出每个 blocked 程序或目录的 dependency。 + +3. 把 representative coverage 扩展成 class coverage,而不是盲目追求全量 browser + +当前问题: + +- Layer 4 现在只覆盖 representative subset: + `foam`、`geometry`、`external_offsets`、bridge-mill。 +- 这还不足以支撑“全面测试完成”的说法,因为 `configs/sim` 还包含多种 machine class: + - plain INI/tool-table/main program; + - Python remap main program; + - remap subroutine only; + - five-axis switchkins / TWP / TDR / TRT; + - macro-only config families; + - on_abort / macro load / tool-change style files。 + +实施原则: + +- 不是把 159 个程序都复制进 browser smoke。 +- 是每种独立 runtime class 至少补一个 native + Node + browser representative, + 并且 class 到 program 的归因在 matrix 中完整记录。 + +最低还要补齐的 representative class: + +- TWP `table-rotary_spindle-rotary-nutating`: + 当前 native baseline 已有 14/15 passing inventory,但 Layer 4 还没有代表性 TWP + runtime smoke。 +- gmoccapy Python remap family: + native inventory 已通过,但 Layer 4 还没有任何 gmoccapy representative。 +- axis/laser Python remap family: + native inventory 已通过,但 Layer 4 还没有任何 laser representative。 +- generic `macro_load` family: + 当前 Layer 4 基本聚焦 main programs,缺少“宏文件只验证 load/parse,不伪造 main” + 的 shared assertion。 +- `on_abort` / deterministic user-action macro family: + 当前 native inventory大量 PASS,但 Node/browser 尚未有独立 representative class。 + +通过条件: + +- 每个 runtime class 在 `docs/sim-configs-coverage-matrix.md` 中都能对应至少一个 + Layer 3/Layer 4 representative。 +- 不要求 159 个程序全部进入 browser smoke; + 但要求每个 class 都有代表 sample,且每个非代表 sample 都有“为什么不需要单独进 + browser”的记录。 + +4. 补 `configs/sim` 专属全量 Node inventory runner + +当前问题: + +- Node 侧现在只有 representative smoke,没有一个“只跑能在 standalone/WASM + 路径中合理成立的 `configs/sim` 全量 inventory”。 + +需要新增: + +```text +wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs +wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh +``` + +职责: + +- 读取 native `summary.tsv` 或同等来源; +- 只挑选: + - native PASS 条目; + - 以及 Layer 2 expected_fail 但 Layer 3/4 已知有 runtime adapter coverage 的条目; +- 跳过已标记 blocked 的 full-process/HAL/UI-only family; +- 对 Node WASM 做 inventory run; +- 输出 Node 侧 summary.tsv。 + +重要限制: + +- 不把 browser 作为 first target; +- 不新增 JS CNC 语义; +- 不把 Python/full-process family 强行塞进 Emscripten,除非已存在 LinuxCNC-owned + runtime path。 + +通过条件: + +- Node inventory summary 可重跑、可对比、可纳入 CI; +- unexpected failure 为 0; +- expected skip / blocked 有明确计数。 + +5. 再决定 browser inventory,而不是直接上全量 browser + +当前问题: + +- browser 环境成本高,且不能依赖目录枚举。 +- 如果先做 browser 全量 inventory,会把大量问题混在 host boundary、 + asset staging、Emscripten runtime、Playwright orchestration 里,定位价值低。 + +实施顺序: + +- 先完成 Node inventory; +- 从 Node inventory 中挑出最有价值的 browser representative 扩展; +- browser 保持 focused class smoke,不追求一次性全量 159。 + +可以进入 browser 扩展候选的 class: + +- TWP representative; +- gmoccapy Python remap representative; +- axis/laser representative; +- one deterministic macro-only family; +- one toolchange / on_abort family。 + +通过条件: + +- browser 侧 class coverage 明确,不再只是 `foam/geometry/external_offsets/bridgemill`; +- 仍然保持稳定、可复现、非目录枚举。 + +6. 把 `verify_sim_configs.sh` 从 inventory 提升为 coverage source-of-truth + +当前问题: + +- native `summary.tsv` 已经是事实来源,但还缺少稳定的 machine-readable 统计, + 用来支撑 docs、Node inventory 和后续 CI 对账。 + +需要增强: + +- 保持 `summary.tsv` 不变; +- 增加稳定派生 artifact,建议: + +```text +wasm-port/build/native/sim-configs/class-summary.tsv +wasm-port/build/native/sim-configs/path-matrix.tsv +``` + +最少字段: + +- `path` +- `class` +- `status` +- `expected_failure` +- `ini` +- `tbl` +- `runtime_family` +- `blocked` + +注意: + +- 如果不想提交 generated artifact,就由脚本生成并由 docs 读取规则描述; +- 但字段模型要先定下来。 + +7. 清理 `configs/sim` 文档的“完成”定义 + +当前问题: + +- 现有 `docs/sim-configs-completion-plan.md` 更多描述了“把当前大块 runtime edge + 打通”的完成,不是“全面测试完成”的完成。 + +需要文档调整: + +- 新增一节:`Definition of Done for Full configs/sim coverage` +- 明确: + - inventory complete + - blocked table complete + - native source-of-truth complete + - Node inventory complete + - browser class coverage complete + - every expected failure justified + - no accidental standalone semantic ownership + +8. 最后再谈“还能不能把 Layer 2 的 8 个 expected_fail 变少” + +原则: + +- `foam` / `bridgemill` / `M110` / `M111` 这些 expected_fail 不是当前首要问题; + 它们已经由 Layer 3/4 runtime path 证明。 +- 只有当能够通过 vendored LinuxCNC source path 合法地把 native strict baseline + 改造成更贴近 runtime 的入口点时,才讨论减少 expected_fail。 +- 在那之前,不改 `verify_sim_configs.sh` 的语义口径,不把 expected_fail 硬改成 PASS。 + +优先级排序: + +1. coverage matrix +2. blocked table +3. Node inventory +4. browser class expansion +5. docs done-definition +6. 再评估 Layer 2 baseline 是否需要新入口点 + +推荐执行顺序: + +1. 先建立 coverage matrix + +执行: + +```bash +wasm-port/tests/native/verify_sim_configs.sh +cat wasm-port/build/native/sim-configs/summary.tsv +``` + +产出: + +- 新增 `wasm-port/docs/sim-configs-coverage-matrix.md` +- 159 条记录全部分类 + +2. 再补 blocked table 和 class taxonomy + +执行: + +- 逐目录梳理 `linuxcnc/configs/sim` +- 对照 `verify_sim_configs.sh` summary +- 把 full-process/HAL/UI-only family 写进 tracker blocked table + +产出: + +- 更新 `docs/linuxcnc-test-porting-tracker.md` +- 更新 `docs/compatibility-validation.md` + +3. 实施 Node inventory runner + +执行: + +```text +wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs +wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh +``` + +通过条件: + +- Node inventory 只跑可移植条目 +- unexpected failure = 0 + +4. 扩 browser class coverage + +执行: + +- 先补 TWP representative +- 再补 gmoccapy representative +- 再补 axis/laser representative +- 最后补 macro-only / on_abort representative + +通过条件: + +- `verify_interp_browser.sh` 和 `verify_host_smokes.sh` 仍稳定通过 +- browser 不引入目录枚举 + +5. 更新完成定义和漂移控制 + +执行: + +- 更新 `docs/sim-configs-completion-plan.md` +- 更新 `docs/compatibility-validation.md` +- 更新 `docs/source-reuse-map.md` + +完成判定: + +- `configs/sim` 每个 `.ngc` 都有明确分类; +- 每个类别都有合适层级的验证入口; +- blocked dependency 清单完整; +- Node inventory 可重跑; +- browser class coverage 覆盖所有重要 runtime family; +- Layer 2 的 8 个 expected_fail 都有稳定归因; +- 没有通过 project-owned CNC 语义让测试看起来通过。 + +不做事项: + +- 不把 159 个程序全部塞进 browser smoke; +- 不把 full-process/HAL/UI/linuxcncrsh 依赖程序误降级为 standalone file execution; +- 不修改 `linuxcnc/configs/sim` upstream 文件; +- 不通过 JS 解释逻辑、临时字符串匹配、或 standalone `Interp::...` 新语义实现来换取 PASS。 diff --git a/text4.txt b/text4.txt new file mode 100644 index 0000000..d380af2 --- /dev/null +++ b/text4.txt @@ -0,0 +1,248 @@ +HAL/UI/full-process standalone/browser boundary design and next plan + +Generated: 2026-06-10 CST + +This plan follows `text3.txt`. The `configs/sim` inventory/matrix work is now +complete for the current definition. This file defines the next boundary before +any previously blocked HAL/UI/full-process family is promoted into standalone, +Node, or browser execution. + +Goal + +- Preserve LinuxCNC as the CNC semantic source of truth. +- Make HAL/UI/full-process dependencies machine-readable before attempting + execution. +- Promote only the subpaths that can run through vendored LinuxCNC source plus + explicit standalone runtime adapters. +- Keep task, HAL process launch, UI driver process launch, linuxcncrsh, Python + remap, and tool-database process behavior blocked until each has a deliberate + LinuxCNC-owned runtime boundary. + +Non-goals + +- Do not implement HAL, task, linuxcncrsh, GUI, Python remap, or tool-database + semantics in JavaScript. +- Do not make blocked `configs/sim` programs pass by editing upstream G-code, + changing SDK behavior, or adding project-owned interpreter semantics. +- Do not treat native LinuxCNC GUI code as implementation code for the browser + UI. + +Current implementation added by this batch + +1. SDK runtime-boundary classifier + + Added: + + ```text + wasm-port/runtime/sdk/src/sim-config-staging.js + analyzeIniRuntimeBoundaries() + ``` + + Exported through: + + ```text + wasm-port/runtime/sdk/src/index.js + ``` + + The classifier reads INI text, manifest text, source-root metadata, and + optional execution text. It reports: + + - declared `HAL` process inputs: `HALFILE`, `HALCMD`, `POSTGUI_HALFILE`, + `HALUI`; + - declared UI process inputs: `DISPLAY`, `PYVCP`, `GLADEVCP`, + `EMBED_TAB_COMMAND`; + - `HALUI` MDI command dependencies; + - `[EMCIO]DB_PROGRAM` tool-database process dependencies; + - Python references in UI, DB, `[PYTHON]`, or Python remap declarations; + - `[RS274NGC]USER_M_PATH` plus whether the current execution text calls + unstaged external `M100..M199` process codes. + + It returns a policy recommendation for hard Layer 4 blocks: + + - `L4-TOOL-DB` when `[EMCIO]DB_PROGRAM` is present; + - `L4-USER-M-PROCESS` when the current execution chain calls unstaged + external user-M process codes; + - `L4-PYTHON-REMAP` for Python remap runtime declarations; + - `-` when the dependency is only a declared process dependency already + represented by a narrower standalone adapter or class representative. + + This is policy/accounting only. It does not execute or emulate HAL, task, + UI, Python, user-M, or tool-database behavior. + +2. Node coverage for the classifier + + Updated: + + ```text + wasm-port/tests/wasm/node/verify_sim_configs_wasm.mjs + ``` + + Covered cases: + + - synthetic INI with vendored `M123` user-M file remains unblocked; + - `axis/db_demo/db_nonran.ini` reports `L4-TOOL-DB`; + - `axis/vismach/millturn/millturn.ini` plus its remap execution chain + reports `L4-USER-M-PROCESS` because `M428/M429` call unstaged `M128/M129`; + - `axis/vismach/puma/puma_cube.ini` declares HAL/UI/HALUI process + dependencies but remains unblocked for the current representative program + because the promoted execution path does not call unstaged external + user-M process codes; + - `axis/gladevcp/gladevcp_panel.ini` declares UI/Python UI process + dependencies but remains unblocked for the current `probe.ngc` + representative. + +3. Inventory policy guard + + Updated: + + ```text + wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs + ``` + + The Node inventory now checks vendored INI rows against + `analyzeIniRuntimeBoundaries()` before execution/skipping: + + - `L4-TOOL-DB` rows must declare `DB_PROGRAM`; + - `L4-USER-M-PROCESS` rows must be backed by an execution chain that calls + unstaged external user-M process codes; + - generated/tracked blocked policy drift fails the inventory. + +Boundary model + +Layer A: declaration classification + +- Input: INI text, manifest text, optional execution text. +- Output: dependency list and recommended blocked kind. +- Owner: SDK host-boundary code. +- Validation: Node unit/smoke assertions and Node inventory policy checks. + +Layer B: standalone adapter execution + +- Allowed only when a narrow runtime edge already exists and CNC behavior still + comes from vendored LinuxCNC source. +- Current examples: + - HAL named-parameter lookup and switchkins M68/M66 synchronization through + the standalone HAL adapter; + - deterministic `USER_M_COMMAND` canonical events for already vendored + M110/M111-style user-M registration; + - five-axis remap execution through vendored LinuxCNC remap/O-word paths; + - OPFS/file/parameter/tool-table persistence as host storage boundaries. + +Layer C: browser/UI representation + +- Browser UI may present standalone simulation state and user controls. +- Browser UI must not execute native LinuxCNC GUI code. +- Browser UI must call SDK/WASM boundaries that are already validated in Node + or native probes. +- Full LinuxCNC GUI actions remain blocked unless expressed as a deliberate + standalone command boundary with LinuxCNC-owned behavior underneath. + +Layer D: full-process blocked boundary + +Keep blocked until explicitly designed: + +- LinuxCNC task process lifecycle; +- HAL process/module loading and realtime scheduling; +- HALUI/linuxcncrsh command queues; +- external userspace components; +- native GUI driver processes; +- Python remap/prolog/epilog runtime; +- tool database process startup and protocol/state behavior. + +Immediate next implementation batches + +Batch 1: make boundary reports durable + +- Add a generated machine-readable boundary artifact: + + ```text + wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv + ``` + +- Minimum fields: + + ```text + path + ini + blocked + recommended_blocked + dependencies + user_m_execution_codes + user_m_vendored_count + db_program + hal_process + ui_process + halui_mdi_process + python_process + ``` + +- The existing Node inventory should fail if `blocked` and + `recommended_blocked` conflict for hard blocks. + +Batch 2: promote only safe HAL/UI representatives + +- Keep `axis/gladevcp/probe.ngc`, `woodpecker/on_abort.ngc`, + `axis/vismach/puma/puma_cube.ngc`, and `axis/vismach/melfa-sim/example.ngc` + as representative file-execution paths. +- Add browser assertions that these programs remain file/remap execution + representatives and do not claim full UI/HAL process coverage. +- Do not promote `axis/vismach/millturn/example.ngc` until the user-M process + boundary is designed, because the remap chain calls M128/M129. + +Batch 3: design external user-M process boundary + +- Start with `axis/vismach/millturn` because it is the smallest current hard + blocked row with vendored INI and program context. +- Required design questions: + - Which LinuxCNC source owns M128/M129 behavior in the native config? + - Is the behavior expressible as a LinuxCNC-owned deterministic adapter + boundary, or does it require spawning external process scripts? + - What canonical/state output proves behavior without adding JS CNC + semantics? +- Do not mark `millturn` unblocked until native, Node, and browser checks can + prove the boundary. + +Batch 4: design tool DB boundary + +- Start with `axis/db_demo/db_nonran.ini`. +- Required design questions: + - Which LinuxCNC source owns `DB_PROGRAM` startup/protocol semantics? + - Can a standalone tool database adapter call vendored LinuxCNC tooldata + source without reimplementing database behavior? + - What fixture demonstrates tool lookup/update behavior across native and + WASM? +- Keep `axis/db_demo/base.ngc` as `L4-TOOL-DB` until this exists. + +Batch 5: Python remap/full-process family plan + +- Do not vendor or execute `gmoccapy`, `axis/laser`, or TWP nutating Layer 4 + paths until Python remap runtime ownership is designed. +- First artifact should be a dependency inventory, not execution: + - Python modules referenced by INI/remap; + - prolog/epilog functions; + - HAL/task/UI assumptions; + - NGC-only subpaths, if any, that can be separated safely. + +Validation gates + +Run after each batch: + +```bash +wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh +wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh +wasm-port/tests/browser/verify_interp_browser.sh +wasm-port/tests/host/verify_host_smokes.sh +wasm-port/tools/verify_vendor_sync.sh +wasm-port/tools/verify_no_standalone_cnc_semantics.sh +``` + +Completion criteria for this boundary phase + +- Every vendored sim-config INI used by Node inventory has a machine-readable + runtime-boundary report. +- Hard blocked rows have a dependency-backed reason rather than path-only + classification. +- Safe representatives can declare HAL/UI process dependencies without being + mislabeled as full-process coverage. +- No blocked family is promoted until a LinuxCNC-owned runtime boundary exists + and is validated native, Node, and browser where appropriate. diff --git a/wasm-port/docs/compatibility-validation.md b/wasm-port/docs/compatibility-validation.md index 6152154..67ec2ce 100644 --- a/wasm-port/docs/compatibility-validation.md +++ b/wasm-port/docs/compatibility-validation.md @@ -36,6 +36,12 @@ The current WASM sim-config smoke validation command is: 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 @@ -92,6 +98,7 @@ running the aggregate host check: 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 @@ -122,7 +129,278 @@ Layer responsibilities are intentionally narrow: 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: +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/sim-configs/class-summary.tsv +wasm-port/build/native/sim-configs/path-matrix.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. + +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/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-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/blocked-runtime-promotion-lock.tsv +wasm-port/build/wasm/sim-configs-inventory/next-boundary-worklist.tsv +wasm-port/build/wasm/sim-configs-inventory/boundary-proof-gates.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. +`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. +`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-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. +`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 | | --- | --- | --- | @@ -499,14 +777,15 @@ The validation fails if: | 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` 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, `SUBROUTINE_PATH` staging for `opa_demo.ngc -> circles.ngc`, bridge-mill remap-subroutine staging, and vendored LinuxCNC bridge-mill NGC remap 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_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` switchkins remap demo execution, representative vendored `configs/sim` `foam`, `geometry`, `external_offsets`, and bridge-mill 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, WASM trajectory-planner, OPFS, and browser smoke validation with shared WASM builds. | +| `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 diff --git a/wasm-port/docs/full-process-boundary-design.md b/wasm-port/docs/full-process-boundary-design.md new file mode 100644 index 0000000..979ecca --- /dev/null +++ b/wasm-port/docs/full-process-boundary-design.md @@ -0,0 +1,513 @@ +# Full-Process Runtime Boundary Design + +Generated: 2026-06-10 CST + +This document records the first design pass for `configs/sim` rows that are +already classified by the Node inventory, but must remain blocked until a +LinuxCNC-owned runtime boundary exists. It is a design and accounting artifact, +not an execution path. + +## Scope + +- `axis/vismach/millturn/example.ngc`, currently `L4-USER-M-PROCESS`. +- `axis/db_demo/base.ngc`, currently `L4-TOOL-DB`. +- Python-remap and broader full-process families remain inventoried in + `build/wasm/sim-configs-inventory/blocked-dependency-summary.tsv`; they are + not promoted here. + +## Non-Goals + +- Do not implement HAL, task, HALUI, Tcl, Python, tool-database, or external + process semantics in JavaScript. +- Do not make blocked rows pass by editing upstream G-code, Tcl, Python, INI, + or tool-table files. +- Do not treat native GUI code or config helper scripts as browser UI + implementation code. +- Do not mark a row unblocked until native, Node, and browser validation prove + the boundary where that layer is applicable. + +## External User-M Process Boundary + +### Current Block + +`axis/vismach/millturn/example.ngc` is blocked because +`millturn.ini` declares: + +- `[RS274NGC]USER_M_PATH = ./mcodes`; +- `REMAP = M428 ... ngc=428remap`; +- `REMAP = M429 ... ngc=429remap`; +- `[HAL]HALUI = halui`, `HALFILE`, `HALCMD`, and `POSTGUI_HALFILE`; +- `[HALUI]MDI_COMMAND = M128` and `M129`; +- `[DISPLAY]PYVCP = millturn.xml`. + +The promoted execution chain reaches `remap_subs/428remap.ngc` and +`remap_subs/429remap.ngc`. Those LinuxCNC NGC remaps execute `M68`/`M66` +switchkins synchronization and then call external user-M process codes +`M128` or `M129`. + +### LinuxCNC Owner Set + +- `configs/sim/axis/vismach/millturn/millturn.ini` owns the machine + declarations and search paths. +- `configs/sim/axis/vismach/millturn/remap_subs/428remap.ngc` and + `429remap.ngc` own the NGC remap call sequence around `M128` and `M129`. +- `configs/sim/axis/vismach/millturn/mcodes/M128` and + `configs/sim/axis/vismach/millturn/mcodes/M129` own the config side effects. +- `src/emc/task/emctask.cc` owns `USER_M_PATH` search, executable detection, + `USER_DEFINED_FUNCTION_ADD()`, and queuing `EMC_SYSTEM_CMD`. +- `src/emc/task/emctaskmain.cc` owns `emcSystemCmd()` process spawning and + completion tracking for queued system commands. +- `src/emc/usr_intf/halui.cc` owns HALUI MDI command queue behavior. +- The HAL runtime owns `hal getp`/`hal setp` state, including the `ini.*` + soft-limit pins used by the scripts. + +### Native Behavior To Preserve + +`M128` is a Tcl process script that: + +- requires the LinuxCNC and HAL Tcl packages; +- calls `emc_init -quick`; +- calls `parse_ini $::env(INI_FILE_NAME)`; +- checks `hal getp kinstype.is-0`; +- writes mill limits from `[AXIS_X]`, `[AXIS_Y]`, and `[AXIS_Z]` into + `ini.x.*`, `ini.y.*`, and `ini.z.*` HAL pins. + +`M129` follows the same process path, but checks `kinstype.is-1` and writes the +`MIN_LIMIT_TURN` / `MAX_LIMIT_TURN` values for X, Y, and Z. Both scripts also +restore `MAX_VELOCITY` and `MAX_ACCELERATION`. + +The NGC remap files own the surrounding interpreter-visible work: + +- set `motion.analog-out-03` through `M68`; +- force synchronization with `M66`; +- set G5x offsets with `G10 L2 P7` or `G10 L2 P8`; +- activate `G59.1` or `G59.2`; +- verify `_hal[motion.switchkins-type]` after the switch. + +### Boundary Decision + +This is not the same boundary as the existing deterministic `M110`/`M111` +registration adapter. `M110` and `M111` can currently be represented as +deterministic `USER_M_COMMAND` canonical events because the promoted tests only +need the interpreter to accept and queue the user-M command. `M128` and `M129` +must also prove HAL pin state updates that affect soft limits after a +kinematics switch. + +The row therefore remains `L4-USER-M-PROCESS`. + +### Current Machine-Readable Artifact + +`user-m-process-boundary-summary.tsv` records the current designed-but-blocked +state target set for this boundary. It maps `M128` to +`remap_subs/428remap.ngc` and `M129` to `remap_subs/429remap.ngc`, records the +`kinstype.is-0` and `kinstype.is-1` guards, and expands the source-traceable +`ini.[xyz].min_limit`, `ini.[xyz].max_limit`, `ini.[xyz].min_velocity`, and +`ini.[xyz].max_acceleration` target pins from `millturn.ini`. +`user-m-process-state-targets.tsv` is the normalized companion table for that +same evidence. It has one pending proof row per `M128`/`M129` target pin, +including the config script source file, remap caller, mill/turn state mode, +guard pin, source INI section/field, and expected value. The current table has +24 target rows plus a header and keeps `proof_status=pending`, +`execution_enabled=0`, and `promotion_allowed=0`. +`user-m-process-transition-plan.tsv` records the next non-executing contract +for this boundary. It binds `M428` to `M128` and `M429` to `M129`, records the +`motion.analog-out-03` switchkins output, target kinstype values `0` and `1`, +the active `G59.1`/`G59.2` work offsets, `P7`/`P8` offset pockets, guard pins, +and the 12 expected `ini.[xyz].*` state outputs for each user-M code. This is +still a pending transition contract only; it does not execute Tcl, start HAL, +or permit standalone/browser promotion. +`user-m-process-native-state-alignment.tsv` aligns those 24 generated target +rows with the native source probe stdout keys, such as +`M128_X_AXIS_X.MIN_LIMIT_ok` and `M129_Z_AXIS_Z.MAX_LIMIT_TURN_ok`. This table +proves the generated pin targets still match the native LinuxCNC source/state +probe output, but it also remains `proof_status=pending`, +`execution_enabled=0`, and `promotion_allowed=0`. +`user-m-process-native-transition-alignment.tsv` aligns the two generated +transition-plan rows with native source probe stdout for `M428` and `M429`. +It verifies the source-owned `motion.analog-out-03` switchkins output, target +kinstype values `0` and `1`, active `G59.1`/`G59.2` offsets, `P7`/`P8` +offset pockets, and `M428 -> M128` / `M429 -> M129` process calls. This is +still source-transition alignment only; it does not execute the Tcl user-M +processes, start HAL, or allow promotion. +`user-m-process-native-runtime-state-plan.tsv` is the next native runnable +probe contract. It records the required LinuxCNC task/HAL/Tcl user-M runtime, +the required environment (`INI_FILE_NAME`, `motion.switchkins-type`, +`kinstype.is-0`, `kinstype.is-1`, and `ini.[xyz].*` pins), the two transition +steps, and the exact expected `ini.[xyz].*` values after each user-M process. +It requires the source transition/state alignment artifacts to be complete, but +keeps `native_runtime_status=pending_native_hal_tcl_process_probe`, +`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. +`user-m-process-native-runtime-readiness.tsv` records whether the host has the +runtime commands needed to attempt that native probe. It currently checks +`tclsh`, `halrun`, `halcmd`, and `linuxcnc`, records PATH evidence where a +command exists, and keeps the boundary blocked with `proof_status=pending`, +`execution_enabled=0`, and `promotion_allowed=0` even if the commands become +available. +`user-m-process-native-runtime-probe-gate.tsv` is the generated execution gate +for the future runtime probe. It combines source proof readiness with host +runtime readiness for `M428/M128` and `M429/M129`, records missing runtime +commands, and keeps `proof_status=pending`, `execution_enabled=0`, and +`promotion_allowed=0`. +`tests/native/probe_millturn_user_m_runtime.sh` is wired into +`build_native_probes.sh` as `linuxcnc_millturn_user_m_runtime_probe`. On hosts +without `halrun`, `halcmd`, or `linuxcnc`, it exits successfully but reports +`millturn_user_m_runtime_probe_status=skipped_missing_host_runtime`; on a host +with the full LinuxCNC runtime it remains disabled by default. If explicitly +enabled with `ENABLE_MILLTURN_USER_M_RUNTIME_PROBE=1`, it starts the vendored +`millturn.ini`, runs the LinuxCNC-owned Tcl `M128`/`M129` scripts, and verifies +the resulting `ini.[xyz].*` HAL state targets before reporting +`runtime_state_probe_passed`. + +The artifact keeps `execution_enabled=0` and `promotion_allowed=0`. It is not +a standalone Tcl/HAL executor and does not make `millturn` a Node/browser +representative. + +`linuxcnc_millturn_user_m_boundary_probe` is the current native guard for this +evidence. It reads the LinuxCNC source `millturn.ini`, `mcodes/M128`, +`mcodes/M129`, and the `428remap`/`429remap` callers, then verifies the +source-derived guard pins, `M428`/`M429` switchkins transition fields, and +`ini.[xyz].*` target values recorded in the machine-readable tables. This is a +source/state-target and source-transition proof only: it does not execute Tcl, +start HAL, spawn the external user-M process, or permit promotion. + +### Candidate Boundary + +A valid future boundary would have to be LinuxCNC-owned and state based: + +1. Reuse LinuxCNC task user-M search and registration behavior for discovering + `M128` and `M129`. +2. Reuse a LinuxCNC-owned HAL/INI state boundary for the `ini.x.*`, + `ini.y.*`, `ini.z.*`, `kinstype.is-*`, and `motion.switchkins-type` pins. +3. Execute or faithfully host the config-owned side-effect source without + translating it into JavaScript CNC semantics. If the Tcl scripts cannot be + executed in the target layer, the boundary must be narrowed to a documented + LinuxCNC-owned state transition with source-traceable inputs and outputs. +4. Keep browser execution blocked unless the same state transition can be + proven without spawning arbitrary host processes. + +### Required Proof Before Promotion + +Native proof: + +- The existing `linuxcnc_millturn_user_m_boundary_probe` source/state guard + must continue to prove that the pending M128/M129 state targets come from + LinuxCNC config files rather than project-owned behavior. +- A LinuxCNC or standalone-native probe runs the `M428 -> M129 -> M429 -> M128` + relevant switch path and records the `ini.[xyz].min_limit`, + `ini.[xyz].max_limit`, `ini.[xyz].min_velocity`, and + `ini.[xyz].max_acceleration` pin values before and after each user-M call. +- The same probe records the kinstype guard result and the active G5x offset. + +Node WASM proof: + +- The SDK stages the same INI, remap, and script assets for dependency + accounting. +- The WASM runtime proves the same state output through a LinuxCNC-owned + boundary. A `USER_M_COMMAND` event alone is not sufficient. + +Browser proof: + +- The browser smoke calls the already validated SDK/WASM boundary. +- The test labels the row as a millturn process-boundary representative only + after the state proof exists. It must not claim full LinuxCNC HAL/task/UI + process coverage. + +## Tool Database Boundary + +### Current Block + +`axis/db_demo/base.ngc` is blocked because `db_nonran.ini` declares: + +```text +[EMCIO] +RANDOM_TOOLCHANGER = 0 +DB_PROGRAM = ./db_nonran.py +``` + +The INI explicitly notes that `TOOL_TABLE` is not used with `DB_PROGRAM`. +Standalone interpreter file execution would therefore bypass the tool database +startup, command/reply protocol, and persistent database state. + +### LinuxCNC Owner Set + +- `configs/sim/axis/db_demo/db_nonran.ini` owns the DB program declaration. +- `configs/sim/axis/db_demo/db.py` owns the demo database behavior. +- `src/emc/task/taskclass.cc` owns reading `[EMCIO]DB_PROGRAM`, enabling DB + mode, calling `tooldata_db_init()`, loading tooldata, and notifying DB state + changes during tool load/unload paths. +- `src/emc/tooldata/tooldata_db.cc` owns child process startup, pipe setup, + version handshake, `g` get-all requests, and `l`/`u`/`p` notifications. +- `src/emc/tooldata/tooldata_common.cc` owns common tooldata storage and DB + refresh behavior. + +### Native Behavior To Preserve + +`tooldata_db_init()` splits `DB_PROGRAM` into argv, verifies that the program is +executable, forks it, connects stdin/stdout pipes, and waits for the version +reply `v2.1`. `tooldata_db_getall()` sends `g`, resets local tooldata, reads +tool lines until `FINI`, and calls `tooldata_read_entry()` for each line. + +`tooldata_db_notify()` sends: + +- `l ...` for `SPINDLE_LOAD`; +- `u ...` for `SPINDLE_UNLOAD`; +- `p ...` for `TOOL_OFFSET`. + +The demo `db.py` uses LinuxCNC's `tooldb` module with callbacks for: + +- `user_get_tool`; +- `user_put_tool`; +- `user_load_spindle_nonran_tc` or `user_load_spindle_ran_tc`; +- `user_unload_spindle_nonran_tc` or `user_unload_spindle_ran_tc`. + +It maintains a persistent flat-file database, updates tool usage minutes, and +can call `linuxcnc.command().load_tool_table` to synchronize changes back to +LinuxCNC. Those details are DB process behavior, not interpreter file +execution behavior. + +### Boundary Decision + +This row remains `L4-TOOL-DB`. A standalone adapter that merely loads a +fallback `.tbl` file would be wrong for this config because DB mode explicitly +replaces the tool table file path. + +### Current Machine-Readable Artifact + +`tool-db-process-boundary-summary.tsv` records the current designed-but-blocked +protocol and state target set for this boundary. It records `DB_PROGRAM = +./db_nonran.py`, the LinuxCNC tooldata protocol messages `v2.1`, `g`, `l`, `u`, +and `p`, the demo DB callbacks `user_get_tool`, `user_put_tool`, +`user_load_spindle_nonran_tc`, and `user_unload_spindle_nonran_tc`, and the +nonrandom database state targets such as `T10..T19`, `/tmp/db_nonran_file`, +`tno+100` startup pockets, and pocket-0 spindle load/unload behavior. +`tool-db-process-protocol-gates.tsv` is the normalized companion table for +that evidence. It splits the blocked DB boundary into pending protocol-message, +DB-program-callback, and state-target gates, including the `v2.1` startup +reply, `g` get-all through `FINI`, `l`/`u`/`p` notifications, demo callback +registration, ignored `TOOL_TABLE`, startup tools, nonrandom pocket mapping, +and persistence/sync targets. The current table keeps `proof_status=pending`, +`execution_enabled=0`, and `promotion_allowed=0`. +`tool-db-process-transaction-plan.tsv` records the next non-executing contract +for this boundary. It orders the pending DB protocol into startup handshake, +initial get-all, spindle load notify, tool offset notify, and spindle unload +notify steps. Each step binds one LinuxCNC protocol message to the expected +`db.py` callback, required native/Node/browser proof, and source-traceable +state targets. This is still a transaction contract only; it does not start +`DB_PROGRAM`, run Python, mutate `/tmp/db_nonran_file`, fall back to a tool +table, or permit standalone/browser promotion. +`tool-db-process-native-protocol-alignment.tsv` aligns those generated gates +with the native source probe stdout keys, such as `tool_db_v2_1_handshake`, +`tool_db_getall_g_until_fini`, `tool_db_notify_l_u_p_protocol`, and +`tool_db_program_nonran_state_targets`. This table proves the generated gates +still match LinuxCNC-owned task/tooldata/config evidence, but it also remains +`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. +`tool-db-process-native-runtime-readiness.tsv` records whether the host has +the runtime pieces needed to attempt a DB process protocol probe. It checks +`python3`, `linuxcnc`, `milltask`, `halcmd`, the configured +`axis/db_demo/db_nonran.py` program, and the LinuxCNC Python `linuxcnc.so` and +`tooldb.py` modules. It records PATH/source evidence where available and keeps +the DB boundary blocked with `proof_status=pending`, `execution_enabled=0`, +and `promotion_allowed=0`. +`tests/native/probe_tool_db_runtime.sh` is wired into `build_native_probes.sh` +as `linuxcnc_tool_db_runtime_probe`. On hosts without the required DB runtime +commands it exits successfully with `tool_db_runtime_probe_status = +skipped_missing_host_runtime`; on a ready host it remains disabled by default. +If explicitly enabled with `ENABLE_TOOL_DB_RUNTIME_PROBE=1`, it starts the +vendored `DB_PROGRAM`, drives the LinuxCNC `tooldb.py` `v2.1`/`g`/`p`/`l`/`u` +protocol over stdin/stdout, verifies nonrandom `T10..T19` startup state, tool +update, spindle load/unload, and flat-file persistence, then reports +`runtime_protocol_probe_passed`. + +The artifact keeps `execution_enabled=0` and `promotion_allowed=0`. It is not +a standalone tool database executor, does not replace `DB_PROGRAM` with a +fallback `.tbl`, and does not make `axis/db_demo/base.ngc` a Node/browser +representative. + +`linuxcnc_tool_db_boundary_probe` is the current native guard for this +evidence. It reads the LinuxCNC source `db_nonran.ini`, `db.py`, +`src/emc/task/taskclass.cc`, and `src/emc/tooldata/tooldata_db.cc`, then +verifies the DB mode owner path, child-process protocol, `v2.1` startup +handshake, `g`/`FINI` get-all path, `l`/`u`/`p` notifications, demo DB +callbacks, and nonrandom state targets. This is a source/protocol-target proof +only: it does not start `DB_PROGRAM`, run the Python tooldb loop, mutate the +flat-file database, or permit promotion. + +### Candidate Boundary + +A valid future boundary should be a narrow tool-database host adapter: + +1. Reuse `tooldata_db.cc` and `tooldata_common.cc` for DB mode behavior. +2. Isolate the process-spawn edge behind a host abstraction so native can spawn + the configured DB program, while WASM/browser use an explicitly designed + equivalent only if it preserves the LinuxCNC protocol. +3. Preserve the `v2.1`, `g`, `l`, `u`, and `p` command/reply protocol rather + than parsing or inventing tool semantics in JavaScript. +4. Treat `db.py` as a config-owned process dependency. If it is not executable + in a target layer, that layer remains blocked. + +### Required Proof Before Promotion + +Native proof: + +- The existing `linuxcnc_tool_db_boundary_probe` source/protocol guard must + continue to prove that the pending DB gates come from LinuxCNC task/tooldata + and demo DB sources rather than project-owned behavior. +- A probe starts `db_nonran.py` through the LinuxCNC DB path and verifies the + `v2.1` handshake. +- A get-all request returns the expected nonrandom startup tools. +- A load/unload or update path changes DB state through `l`, `u`, or `p` and + is reflected by a subsequent get-all. + +Node WASM proof: + +- The same protocol is visible through the SDK boundary. +- Tool lookup/update behavior matches the native proof without staging a fake + `.tbl` replacement. + +Browser proof: + +- Browser validation calls the Node-proven SDK/WASM boundary. +- OPFS may store DB files only as host persistence. It must not implement DB + command semantics. + +## Python-Remap Inventory Boundary + +Python-remap rows remain inventory-only. The current +`blocked-dependency-summary.tsv` records Python modules, remap/prolog/epilog +functions, NGC-only subpaths, and HAL/UI/HALUI declarations. +`python-remap-boundary-summary.tsv` preserves the same evidence per blocked +path and records LinuxCNC Python runtime owner evidence from +`src/emc/rs274ngc/interp_python.cc` and +`src/emc/pythonplugin/python_plugin.cc`. `python-remap-family-summary.tsv` +aggregates it by runtime family so mixed Python/NGC-only subpaths remain +visible without promoting execution. No Python-remap row should be promoted +until a separate LinuxCNC-owned Python runtime boundary exists and has native +plus Node/browser proof appropriate to the target layer. +`python-remap-runtime-gates.tsv` expands each blocked path into Python module, +remap/prolog/epilog callable, NGC-only subpath, process-assumption, and +runtime-owner gates. `python-remap-native-runtime-alignment.tsv` aligns those +generated gates with the current native source probe stdout. Runtime owner +gates map to exact LinuxCNC runtime proof keys such as +`python_runtime_pycall_dispatch` and `python_plugin_callable_invoke`; dependency +inventory gates map to representative family inventory proof or the aggregate +`python_remap_native_source_inventory_proof`. Both tables remain +`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. +`python-remap-runtime-contract.tsv` records the next non-executing family-level +contract. It keeps one row per blocked Python-remap family, records the +LinuxCNC-owned Python runtime phases (`initialize_python`, +`apply_ini_python_path`, `execute_toplevel`, callable lookup/invoke, +remap-phase dispatch, generator finish, execute-string/file, and reload), +aggregates Python modules/callables/NGC-only subpaths, carries HAL/UI/HALUI +process assumptions, and binds each family to native, Node, and browser proof +requirements. It is a runtime contract only: it does not initialize Python, +import modules, execute callbacks, or permit promotion. +`python-remap-native-runtime-readiness.tsv` records the current host/source +readiness for future native Python-remap runtime probes. It checks `python3`, +`linuxcnc`, the LinuxCNC interpreter/plugin owner source files, and each +configured Python module by blocked runtime family. The artifact remains a +gate only: every row stays `proof_status=pending`, `execution_enabled=0`, and +`promotion_allowed=0`. +`python-remap-native-runtime-state-plan.tsv` records the non-executing runtime +state plan for those future probes. It binds each blocked Python-remap family +to the required LinuxCNC Python phases, configured modules, callables, +NGC-only subpaths, process assumptions, readiness counts, source-alignment +artifacts, and future native proof targets. It does not initialize Python, +import modules, execute callbacks, or permit promotion. +`python-remap-native-runtime-fixture-plan.tsv` selects the first native runtime +fixture target, `axis/remap/stop-lookahead/nc_files`. That family is the +smallest current Python runtime lifecycle candidate because it needs the +LinuxCNC Python initialization/path/toplevel/runtime phases and configured +modules but avoids Python callable and NGC-only subpath complexity. The +fixture plan is still non-executing: it records the proof target only and +keeps `proof_status=pending`, `execution_enabled=0`, and +`promotion_allowed=0`. +`tests/native/probe_python_remap_runtime.sh` is wired into +`build_native_probes.sh` as `linuxcnc_python_remap_runtime_probe`. It records +the stop-lookahead fixture identity, configured Python modules, required +LinuxCNC Python runtime phases, host command readiness, and source/module +availability. On hosts without `linuxcnc`, it exits successfully but reports +`python_remap_runtime_probe_status=skipped_missing_host_runtime`; on hosts with +the runtime available it remains disabled by default. If explicitly enabled +with `ENABLE_PYTHON_REMAP_RUNTIME_PROBE=1`, it follows the `demo.ini` +`[PYTHON]` path/toplevel declarations, imports the vendored stop-lookahead +modules, verifies `queuebuster` callable lookup, confirms the callable returns +a generator, and checks that the first yield is the LinuxCNC +`INTERP_EXECUTE_FINISH` value from `interp_return.hh` before reporting +`runtime_lifecycle_probe_passed`. + +`linuxcnc_python_remap_boundary_probe` is the current native guard for this +inventory. It reads the LinuxCNC Python runtime owners and representative +config families (`axis/laser`, `axis/remap/cycle`, TWP nutating, and +`gmoccapy` stdglue), then verifies the runtime dispatch/phase/callable owner +evidence plus representative Python modules, remap callables, prolog/epilog +callables, and Python path declarations. This is source inventory only: it +does not initialize Python, import modules, execute remap callbacks, or permit +promotion. + +## Next Boundary Worklist + +`next-boundary-worklist.tsv` is the machine-readable handoff for the next +runtime-boundary design phase. It is a planning artifact only: every row keeps +`execution_enabled=0` and `promotion_allowed=0`, records the LinuxCNC owner set, +records runtime owner evidence, records required native, Node, and browser +proof, and names the next boundary-design action before promotion. + +`boundary-proof-gates.tsv` is the machine-readable proof checklist derived from +that worklist. It expands every target into native, Node, and browser proof +rows and keeps each row at `proof_status=pending`, `execution_enabled=0`, and +`promotion_allowed=0`. It must fail validation if a future edit tries to +promote a target without first replacing the pending gate with LinuxCNC-owned +proof for that layer. For the current blockers, event-only `USER_M_COMMAND` +coverage is insufficient for `millturn`, `.tbl` fallback coverage is +insufficient for `db_demo`, and JavaScript-owned behavior is insufficient for +Python runtime families. + +`native-proof-alignment-summary.tsv` records whether the native source proof +summary, when present, is consumed by generated worklist and native proof-gate +rows. It currently aligns the `millturn` user-M source-state proof, `db_demo` +tool database protocol source proof, and Python runtime source-inventory proof +without enabling execution or promotion. +`runtime-boundary-native-alignment-summary.tsv` is the aggregate guard for the +detailed native alignment artifacts. It requires every user-M, tool DB, and +Python alignment row to have native stdout evidence, `alignment_ok=1`, +`proof_status=pending`, `execution_enabled=0`, and `promotion_allowed=0`. +`build/native/native-runtime-probe-summary.tsv` is the native companion for the +disabled runtime probe entry points. It summarizes the current runtime +readiness for `millturn` user-M, `db_demo` tool DB, and the Python +stop-lookahead fixture, records the missing host runtime requirements, points +back to each probe stdout log, and keeps every row at `execution_enabled=0` and +`promotion_allowed=0`. +`runtime-boundary-contract-summary.tsv` is the aggregate guard for the +non-executing runtime contracts. It ties the `millturn` user-M transition +contract, `db_demo` tool DB transaction contract, and Python-remap family +runtime contract to their native-alignment artifacts, and requires every +contract row to remain pending with execution and promotion disabled. +`blocked-runtime-promotion-lock.tsv` is the final machine-readable lock for +this phase. It combines the worklist, native/Node/browser proof gates, and +runtime alignment summary so every blocked target has `lock_active=1` until a +LinuxCNC-owned runtime boundary replaces the pending gates. + +The first two priorities are the current designed-but-disabled full-process +blocks: + +1. `external_user_m_process` for `axis/vismach/millturn/example.ngc`; +2. `tool_database_process` for `axis/db_demo/base.ngc`. + +Python runtime family rows follow as inventory-only targets. They must remain +behind a LinuxCNC-owned Python runtime boundary and must not be used to vendor +or execute `gmoccapy`, `axis/laser`, TWP nutating, or other Python-remap +families by path alone. + +## Current Validation + +These commands must continue to pass after any change to this document or to +the inventory code: + +```bash +wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh +wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh +wasm-port/tests/browser/verify_interp_browser.sh +wasm-port/tests/host/verify_host_smokes.sh +wasm-port/tools/verify_vendor_sync.sh +wasm-port/tools/verify_no_standalone_cnc_semantics.sh +``` diff --git a/wasm-port/docs/linuxcnc-test-porting-tracker.md b/wasm-port/docs/linuxcnc-test-porting-tracker.md index 068de3c..8b501ee 100644 --- a/wasm-port/docs/linuxcnc-test-porting-tracker.md +++ b/wasm-port/docs/linuxcnc-test-porting-tracker.md @@ -48,13 +48,14 @@ wasm-port/tests/host/verify_host_smokes.sh | Reject standalone CNC semantics | Done | `tools/verify_no_standalone_cnc_semantics.sh` guards project-owned `Interp::...` definitions outside documented runtime-edge stubs. | | Maintain source reuse map | Done | Current sim-config, remap, interpreter, kinematics, TP, user-M, tool, named-parameter, and OPFS runtime boundaries are recorded in `docs/source-reuse-map.md`; keep updating it whenever LinuxCNC source, test assets, or runtime boundaries are added. | | Maintain compatibility validation notes | Done | Current native, Node WASM, browser, OPFS, and host aggregate checks are recorded in `docs/compatibility-validation.md`; keep updating it whenever a validation command or fixture class is added. | +| Maintain sim-config coverage matrix | Done | `docs/sim-configs-coverage-matrix.md` now maps all current `verify_sim_configs.sh` records to program class, native result, current Layer 3/4 coverage, and blocked/class-coverage notes. The native harness emits `class-summary.tsv` and `path-matrix.tsv`, and the Node inventory runner checks generated/tracked path sets plus tracked class/native-status/expected-failure/blocked fields against native outputs before execution. Future changes should update the matrix only with a matching regenerated native inventory. | | Document validation layers | Done | `docs/compatibility-validation.md` now records Layer 1 `nc_files` basic smoke, Layer 2 `configs/sim` native strict harness, Layer 3 standalone native runtime probes, and Layer 4 WASM Node/browser representative smokes with entry commands, current results, expected boundaries, and the no-LinuxCNC-semantics rule. | | Build LinuxCNC test inventory | In progress | `linuxcnc/tests/remap` has been inventoried by dependency class; the first broader `linuxcnc/tests` pass now records full-process, HAL/realtime, linuxcncrsh, Python-binding, and external-component families in the blocked table. | | Prefer pure interpreter tests first | In progress | Continue with tests that can run through `Interp::open()`, `read()`, and `execute()` without realtime hardware or GUI. | | Add upstream-output comparison | In progress | Use upstream `../linuxcnc/bin/rs274` or original `test.sh` output where practical, then compare against native/WASM/browser output. | | Promote tests through three layers | In progress | Add each selected test first to native harnesses, then WASM Node, then browser smoke where meaningful. | | Record blocked tests | In progress | First broader family-level blocked batch is recorded below; continue expanding it as each `linuxcnc/tests` family is inspected. | -| Add aggregate smoke coverage | Done | `tests/host/verify_host_smokes.sh` now runs stable Node WASM, sim-config WASM, `nc_files` WASM, OPFS, and browser smoke checks with shared builds. Current run passed with `host_wasm_opfs_browser_smokes=ok`. | +| Add aggregate smoke coverage | Done | `tests/host/verify_host_smokes.sh` now runs stable Node WASM, sim-config representative WASM, sim-config Node inventory, `nc_files` WASM, OPFS, and browser smoke checks with shared builds. Current run passed with `host_wasm_opfs_browser_smokes=ok`. | | Add `linuxcnc/nc_files` basic examples | Done | `tests/native/verify_nc_files.sh` now runs the basic/example subset of upstream `linuxcnc/nc_files` through LinuxCNC `bin/rs274`; current native baseline is 107 total, 101 pass, 6 expected context/entry-point edges, 0 unexpected failures. Exploratory `--all` inventory is 247 total, 219 pass, 28 expected context/entry-point edges, 0 unexpected failures. A representative vendored subset now passes Node WASM and browser execution through LinuxCNC-backed `Interp::open()`/`read()`/`execute()`, with `3D_Chips.ngc` using an INI-declared tool-table context for its upstream `T1 M6` line. | ## Current Review Boundaries @@ -132,6 +133,10 @@ directories under `wasm-port/vendor/linuxcnc/tests/interp/` including | `configs/sim/axis/foam/foam.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/foam`; validates LinuxCNC INI-driven `U/V` axis mask handling through `axis_foam.ini` and vendored file execution paths. | | `configs/sim/axis/geometry/xyzc.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/geometry`; validates LinuxCNC `USER_M_PATH` registration with the real executable `M110` while process execution remains a deterministic standalone `USER_M_COMMAND` boundary. | | `configs/sim/axis/external_offsets/*.ngc` M111 demos | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/external_offsets`; validates `dyn_demo.ngc`, `eoffsets.ngc`, `jwp_z.ngc`, and `opa_demo.ngc` with their corresponding INI files, real executable `M111`, shared `eoffset.tbl`, and `opa_demo.ngc`'s `circles.ngc` subroutine while process execution remains a deterministic standalone boundary. | +| `configs/sim/axis/gladevcp/probe.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/gladevcp`; validates plain INI/tool-table main-program staging through `gladevcp_panel.ini` without treating the GTK panel process as browser runtime. | +| `configs/sim/axis/vismach/melfa-sim/example.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/vismach/melfa-sim`; validates a robot/Genser-style remap machine representative through real INI, tool table, and M428/M429/M430 remap subroutines while GUI/HAL process launch remains outside the standalone boundary. | +| `configs/sim/axis/vismach/puma/puma_cube.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/axis/vismach/puma`; validates a PUMA machine-context representative through real INI, tool table, and remap subroutine staging while external GUI/HAL process launch remains outside the standalone boundary. | +| `configs/sim/woodpecker/on_abort.ngc` | Done | Native, WASM Node, browser | Vendored under `wasm-port/vendor/linuxcnc/configs/sim/woodpecker`; validates deterministic `on_abort` file execution through the real machine INI and tool table without expanding browser coverage to unrelated full-process UI flows. | | More `tests/remap/*` interpreter-only cases | Planned | Native first | Select cases that do not require Python behavior beyond documented runtime-edge stubs unless the required LinuxCNC source path is ported. | | More `tests/interp/*` interpreter-only cases | Planned | Native first | Select upstream interpreter cases that can run through vendored file execution without Python, HAL, realtime motion, or GUI. | | `tests/rs274ngc/*` candidates | Planned | Native first | Use upstream `rs274` as the baseline where output is comparable. | @@ -192,6 +197,15 @@ Use this checklist when adding each LinuxCNC upstream test: | `tests/trajectory-planner/circular-arcs` | Blocked | Full LinuxCNC sim configs with task, HAL/Tcl files, GUI/display settings, and motion execution logs. | Keep using standalone TP API probes for planner code; full circular-arc machine tests require task/HAL/motion boundaries. | | `tests/lowlevel/emcmot-error-mpsc` | Blocked | RIP-only build against LinuxCNC motion sources and low-level motion error driver. | Revisit only if low-level motion process test drivers are intentionally ported. | | `tests/uspace/spawnv-root` | Blocked | Sudo-installed userspace HAL component and `spawnv` root behavior. | Keep upstream-only unless HAL component install/runtime support is added. | +| `configs/sim/*/remap_subs/*.ngc` browser main-program inventory | Blocked | These files are remap/subroutine assets, not standalone browser main-program targets. | Keep validating them through native remap parse/execute paths and explicit five-axis/runtime probes instead of widening browser `runSimConfigProgram()` blindly. | +| `configs/sim/axis/db_demo/base.ngc` Layer 4 inventory | Blocked | `[EMCIO]DB_PROGRAM = ./db_nonran.py` requires LinuxCNC task/tooldata DB process startup, command/reply protocol, and database state behavior, not standalone interpreter file execution. | Keep as `L4-TOOL-DB` until a LinuxCNC-owned tool database runtime boundary exists and proves lookup/update behavior across native and WASM. `blocked-dependency-summary.tsv` records `taskclass.cc`, `tooldata_db.cc`, `tooldata_common.cc`, and `configs/sim/axis/db_demo/db.py` as the owner set plus source-derived `tool_db_protocol_evidence` for the `v2.1` handshake, `g`/`FINI` get-all, and `l`/`u`/`p` notification protocol. | +| `configs/sim/axis/vismach/millturn/example.ngc` Layer 4 inventory | Blocked | The remap execution chain calls external `USER_M_PATH` process codes `M128` and `M129`, with HAL/HALUI/UI process declarations in `millturn.ini`. | Keep as `L4-USER-M-PROCESS`; do not promote until the M128/M129 LinuxCNC-owned state boundary proves the kinstype guard and `ini.[xyz].*` HAL pin updates. `blocked-dependency-summary.tsv` records the `mcodes/M128` and `mcodes/M129` Tcl scripts plus source-derived `user_m_process_effects` for Tcl/HAL runtime use, kinstype guards, and `ini.[xyz]` HAL pin side effects. | +| `configs/sim/gmoccapy/*` Layer 4 full inventory | Blocked | Python remap runtime boundary is present in native LinuxCNC `rs274`, but not yet intentionally exposed for Node/browser full inventory. | Keep native inventory coverage as source-of-truth; add one representative Node/browser class sample only after the Python remap boundary is deliberately designed. Python module and prolog/epilog ownership is inventoried in `blocked-dependency-summary.tsv`; LinuxCNC runtime ownership is recorded as `python_runtime_evidence` in the Python boundary/family summaries. | +| `configs/sim/axis/laser/*` Layer 4 full inventory | Blocked | Python remap runtime boundary is present in native LinuxCNC `rs274`, but not yet intentionally exposed for Node/browser full inventory. | Keep native inventory coverage as source-of-truth; add one representative Node/browser class sample only after the Python remap boundary is deliberately designed. Python module and remap ownership is inventoried in `blocked-dependency-summary.tsv`; LinuxCNC runtime ownership is recorded as `python_runtime_evidence` in the Python boundary/family summaries. | +| `configs/sim/axis/remap/*/nc_files/*.ngc` Layer 4 full inventory | Blocked | Native LinuxCNC `rs274` coverage exists, but these demo main programs depend on Python remaps, Python prolog/epilog callbacks, or Python-backed queue/tool-change handlers. | Keep native inventory coverage as source-of-truth; do not reduce Python remap demos to missing vendored files or browser standalone execution until the Python remap boundary is deliberately designed. Dependency ownership is inventoried in `blocked-dependency-summary.tsv`; LinuxCNC runtime ownership is recorded as `python_runtime_evidence` in the Python boundary/family summaries. | +| `configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/*` Layer 4 full inventory | Blocked | Native LinuxCNC `rs274` coverage exists, but the demo family depends on Python remap entry points such as `g682`, `g69_core`, and `g53x_core` that are not yet intentionally exposed for Node/browser inventory. | Keep native inventory coverage as source-of-truth; revisit Layer 4 only after the Python remap boundary is deliberately designed rather than faked in JS. Python and NGC remap dependencies are inventoried in `blocked-dependency-summary.tsv`; LinuxCNC runtime ownership is recorded as `python_runtime_evidence` in the Python boundary/family summaries. | +| `configs/sim/axis/vismach/VMC_toolchange/toolchange.ngc` Layer 4 full inventory | Blocked | Native LinuxCNC `rs274` coverage exists, but the program is the remapped tool-change body for a Python prolog/epilog and full tool-change/HAL process flow. | Keep native inventory coverage as source-of-truth and validate tool-change mechanics through existing standalone interpreter/tooldata probes until task/HAL/tool-change runtime boundaries exist. | +| `configs/sim/axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc` | Blocked | Preserved upstream demo edge: line uses bare `X/Y/Z` after `G53.6` without an explicit motion G-code in the upstream standalone baseline. | Keep as expected failure in Layer 2 and do not modify G-code or project-owned interpreter semantics to force a pass. | ## Next Work Batch diff --git a/wasm-port/docs/sim-configs-completion-plan.md b/wasm-port/docs/sim-configs-completion-plan.md index 6e9c4d5..dac3aa3 100644 --- a/wasm-port/docs/sim-configs-completion-plan.md +++ b/wasm-port/docs/sim-configs-completion-plan.md @@ -16,6 +16,8 @@ Result file: ```text 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 ``` Baseline: @@ -50,19 +52,52 @@ Remaining failures are explicit LinuxCNC-native baseline edges: ## Target -The first target is not a browser UI feature. It is a repeatable native and -WASM simulation harness that can load and execute all `linuxcnc/configs/sim` -programs that are meaningful in a standalone non-hardware simulation context. +The first target is not a browser UI feature and not a requirement that every +`linuxcnc/configs/sim` `.ngc` program pass through standalone `bin/rs274`. +It is a repeatable native and WASM inventory that classifies every +`configs/sim` program, runs the entries that are meaningful in standalone +native/WASM/browser contexts, and records blocked dependencies for the entries +that require full LinuxCNC task, HAL, UI, Python-remap, or external process +runtime. Acceptance criteria: -- The native sim-config harness reports all executable sim programs as `PASS`. +- The native sim-config harness reports `unexpected_fail: 0` and writes + `summary.tsv`, `class-summary.tsv`, and `path-matrix.tsv`. - Macro/remap files are validated by the correct entry point: direct execution only for real programs, load/parse or remap-call validation for subroutines. -- WASM tests cover the same representative classes after the native harness is - green. -- Any remaining unsupported files are explicitly classified as native GUI or - hardware-only and excluded by rule, not by accident. +- Node WASM inventory executes only entries with a defined standalone/WASM + runtime path and reports `unexpected_fail: 0`. +- Browser coverage remains focused on representative runtime classes rather + than blind full-directory execution. +- Any remaining unsupported files are explicitly classified by dependency, not + by accident. + +## Definition Of Done For Full configs/sim Coverage + +Full coverage for this project means: + +- Inventory complete: every `summary.tsv` `.ngc` entry appears in + `docs/sim-configs-coverage-matrix.md` and generated `path-matrix.tsv`. +- Classification complete: every entry has `main`, `macro_load`, or + `remap_subroutine` class. +- Blocked table complete: full-process, HAL, UI, linuxcncrsh, external + userspace component, Python binding/remap, tool-database, and process user-M + dependencies are recorded explicitly. +- Native source-of-truth complete: `verify_sim_configs.sh` remains the Layer 2 + source for per-path status and expected-failure reason. +- Node inventory complete: `verify_sim_configs_inventory_wasm.sh` checks the + native/generated/tracked path sets, runs eligible vendored programs, and + emits stable WASM inventory and skip/block summaries. + Any eligible row with missing vendored machine context is an inventory + failure, not an expected skip. +- Browser class coverage complete: each promoted browser class has a + representative sample and no browser test relies on directory enumeration. +- Expected failures justified: the current eight Layer 2 expected failures are + tied to runtime boundaries or the preserved upstream demo edge. +- No accidental standalone semantic ownership: tests must not pass by changing + G-code semantics, JS interpreter behavior, or project-owned + `Interp::...` implementations. ## Phase 1: Make The Harness A First-Class Test @@ -80,7 +115,8 @@ validation entry point. - scan only `linuxcnc/configs/sim`; - identify `.ngc`, nearest `.ini`, nearest `.tbl`; - run from the INI directory; - - write `summary.tsv`, stdout, stderr, and interpreter output under + - write `summary.tsv`, `class-summary.tsv`, `path-matrix.tsv`, stdout, + stderr, and interpreter output under `wasm-port/build/native/sim-configs/`; - classify programs as `main`, `macro_load`, `remap_subroutine`, or `unsupported_runtime_edge`; @@ -252,71 +288,61 @@ wasm-port/tests/native/verify_native_probes.sh wasm-port/tests/wasm/node/verify_interp_wasm.sh ``` -## Phase 4: Bring Up Python Remap Runtime Edges +## Phase 4: Classify Python Remap Runtime Edges -Status: complete for the native sim-config harness. Current checks: +Status: complete for the native sim-config harness and blocked for Layer 4 +full inventory. Current native checks: ```text gmoccapy: total 38, pass 38, fail 0 axis/laser: total 3, pass 3, fail 0 +axis/remap main demos: total 6, pass 6, fail 0 +VMC_toolchange: total 1, pass 1, fail 0 ``` -Root cause: +Boundary: -The configs use LinuxCNC Python remap modules. Earlier harness runs failed while -initializing `python/toplevel.py`; current native runs now resolve and execute -these configs under the LinuxCNC `rs274` baseline. +The configs use LinuxCNC Python remap modules. Native LinuxCNC `rs274` can +resolve and execute these configs under the current baseline, but Node/browser +Layer 4 full inventory is intentionally blocked until a Python-remap runtime +boundary is deliberately designed. Do not make these pass in browser by +translating Python remap behavior into JavaScript or by adding project-owned +CNC semantics. -Implementation steps: +Recorded dependency: -1. Preserve upstream behavior where possible: +- `configs/sim/gmoccapy/python/toplevel.py` +- `configs/sim/gmoccapy/python/remap.py` +- `configs/sim/gmoccapy/python/stdglue.py` +- `configs/sim/axis/laser/python/toplevel.py` +- `configs/sim/axis/laser/python/remap.py` +- `configs/sim/axis/remap/*/python/*.py` for Python remap, prolog, epilog, + queue, and tool-change callbacks. +- `configs/sim/axis/vismach/VMC_toolchange/remap.py` and `toplevel.py` for + Python tool-change prolog/epilog handling. - - inspect vendored LinuxCNC Python plugin interfaces; - - identify exact APIs used by: - - `configs/sim/gmoccapy/python/toplevel.py` - - `configs/sim/gmoccapy/python/remap.py` - - `configs/sim/gmoccapy/python/stdglue.py` - - `configs/sim/axis/laser/python/toplevel.py` - - `configs/sim/axis/laser/python/remap.py` +Current policy: -2. Split the implementation into two layers: - - - native harness support using the host Python runtime, if available; - - WASM support using a documented adapter boundary or a Python-free - equivalent only for runtime edges, not G-code semantics. - -3. Add runtime state adapters required by Python remap: - - - selected tool and pocket; - - tool table access; - - interpreter status object fields used by stdglue; - - message/error reporting; - - canonical tool-change side effects needed by `M6`, `M61`, and laser - remaps. - -4. Make Python module path resolution match LinuxCNC: - - - INI directory is the base directory; - - `PYTHONPATH` includes config `python/` directories; - - remap modules load relative to the sim config. - -5. Add narrowly-scoped tests before running all 38 gmoccapy programs. Done: - - - one gmoccapy tool-change macro; - - one gmoccapy lathe macro; - - one gmoccapy 5-axis example; - - one laser raster/vector program. +- Keep native inventory as source-of-truth. +- Mark `gmoccapy/*`, `axis/laser/*`, `axis/remap/*/nc_files/*.ngc`, and + `axis/vismach/VMC_toolchange/toolchange.ngc` rows as `L4-PYTHON-REMAP` in + `docs/sim-configs-coverage-matrix.md`. +- Revisit Layer 4 only after the runtime boundary is designed from LinuxCNC + source ownership, not as a browser smoke expansion. Completion check: ```bash wasm-port/tests/native/verify_sim_configs.sh --only gmoccapy wasm-port/tests/native/verify_sim_configs.sh --only axis/laser +wasm-port/tests/native/verify_sim_configs.sh --only axis/remap +wasm-port/tests/native/verify_sim_configs.sh --only VMC_toolchange ``` -## Phase 5: Support TWP Remaps Including G69 +## Phase 5: Classify TWP Remaps Including G69 -Status: mapping complete. The harness now maps +Status: native mapping complete and Layer 4 blocked on Python-remap runtime +ownership. The harness now maps `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/*` through the explicit `xyzacb-trsrn_twp/xyzacb-trsrn.ini` machine config instead of falling back to `axis/axis.ini`. That loads the TWP `G69` remap declarations correctly, @@ -329,7 +355,7 @@ Current failures: `x50y50z150` after `G53.6`; same-directory demos use explicit `G0` motion words at this point. -Root cause: +Boundary: The demo programs rely on table/spindle rotary TWP remaps. The original test mapping fell back to `axis/axis.ini` for these demo files because the actual @@ -341,26 +367,15 @@ axis/vismach/5axis/table-rotary_spindle-rotary-nutating/ xyzbca-trsrn_twp/xyzbca-trsrn.ini ``` -Implementation steps: +Current policy: -1. Improve sim-config mapping. Done: - - - if a `.ngc` is under a `demos/` sibling of machine-specific INI - directories, map it to the appropriate TWP INI instead of walking upward - to `axis/axis.ini`; - - encode this as explicit metadata in the harness, not a fragile heuristic. - -2. Ensure `SUBROUTINE_PATH` includes `../remap_subs:../demos` as declared by - the TWP INIs. - -3. Verify remap subroutines: - - - `g69remap.ngc` - - `g531remap.ngc` - - `g533remap.ngc` - - `g536remap.ngc` - -4. Add a native test for each failing demo. +- Keep native mapping and expected-failure classification in + `verify_sim_configs.sh`. +- Keep `incremental_repetition_g533.ngc` as `UPSTREAM-DEMO`; do not edit the + upstream G-code or add standalone semantics to force a pass. +- Keep TWP demo Layer 4 rows as `L4-PYTHON-REMAP` until Python remap entry + points such as `g682`, `g69_core`, and `g53x_core` have an intentional + runtime boundary. Latest result: @@ -380,13 +395,14 @@ Completion check: wasm-port/tests/native/verify_sim_configs.sh --only table-rotary_spindle-rotary-nutating ``` -## Phase 6: Promote Native Coverage To WASM +## Phase 6: Promote Eligible Native Coverage To WASM -Status: complete for representative Node and browser WASM coverage. Dedicated -Node and browser smokes now pass a representative vendored `configs/sim` subset -through the SDK `runSimConfigProgram()` host boundary, which copies files into -the Emscripten filesystem and forwards execution to existing LinuxCNC-backed C -ABI paths. They cover: +Status: complete for the current representative Node/browser class coverage +and the Node inventory layer. Dedicated Node and browser smokes now pass a +representative vendored `configs/sim` subset through the SDK +`runSimConfigProgram()` host boundary, which copies files into the Emscripten +filesystem and forwards execution to existing LinuxCNC-backed C ABI paths. They +cover: - `axis/foam/foam.ngc` with `axis_foam.ini`, verifying INI-driven `U/V` axis mask handling in WASM. @@ -400,87 +416,214 @@ ABI paths. They cover: shared `eoffset.tbl`, and `opa_demo.ngc`'s `circles.ngc` subroutine, verifying the same user-M and `SUBROUTINE_PATH` boundaries against upstream sim programs. + The Node inventory guard keeps these deterministic `M110`/`M111` rows + unblocked, requires a vendored user-M file, and includes the `opa_demo.ngc` + `circles.ngc` subroutine text in boundary analysis so the reached `M111` + call is accounted for instead of being mistaken for an external user-M + process gap. +- `axis/gladevcp/probe.ngc` as a plain INI/tool-table main-program sample. +- `axis/external_offsets/circles.ngc` as the macro-load class representative, + wrapped only with an added `M2` for load/parse style execution. +- `axis/vismach/5axis/table-dual-rotary/demos/xyzab-tdr-demo.ngc` and + `axis/vismach/5axis/table-rotary-tilting/demos/*` through the existing + five-axis remap execution C ABI. +- `axis/vismach/melfa-sim/example.ngc` and `axis/vismach/puma/puma_cube.ngc` + as additional remap/kinematics machine representatives. +- `woodpecker/on_abort.ngc` as the deterministic on-abort/user-action macro + class representative. +- Node inventory for the eligible vendored program set: + `executed=28`, `passed=28`, `skipped=131`, `unexpected_fail=0`. +- Node inventory skip/block summary: + `ASSET-ONLY=65`, `L4-PYTHON-REMAP=53`, `L4-TOOL-DB=1`, + `L4-USER-M-PROCESS=1`, `NON_MAIN_CLASS=10`, `UPSTREAM-DEMO=1`. +- Node blocked-dependency inventory for the hard blocked row set: + `L4-PYTHON-REMAP=53`, `L4-TOOL-DB=1`, `L4-USER-M-PROCESS=1`. + The inventory reads source `linuxcnc/configs/sim` INI files for dependency + accounting only and writes + `build/wasm/sim-configs-inventory/blocked-dependency-summary.tsv` without + vendoring or executing those blocked families. The blocked summary includes + source-derived `user_m_process_effects` for `millturn`, + `tool_db_protocol_evidence` for `db_demo`, and Python module/remap/prolog/ + epilog dependency ownership for Python-remap families. Python-remap rows are + also projected into + `build/wasm/sim-configs-inventory/python-remap-boundary-summary.tsv`, which + keeps all 53 `L4-PYTHON-REMAP` rows inventory-only with + `python_runtime_evidence` and `execution_enabled=0`. + +Boundary decisions for the current hard blocks: + +- `axis/vismach/millturn/example.ngc` remains `L4-USER-M-PROCESS`. The + source INI declares HAL, HALUI MDI, and UI process dependencies, and the + remap chain enters `remap_subs/428remap.ngc` and `429remap.ngc`, which call + external user-M process codes `M128` and `M129`. Those process scripts live + at `configs/sim/axis/vismach/millturn/mcodes/M128` and `M129`; they use Tcl + LinuxCNC/HAL packages, `emc_init`, `parse_ini`, `hal getp`, and `hal setp` + to change INI axis limit HAL pins after the kinematics switch. The current + LinuxCNC owner is therefore task user-M process dispatch plus HALUI/MDI and + the config-owned Tcl process scripts, not the standalone interpreter. Do not + promote this row until the boundary design in + `docs/full-process-boundary-design.md` has a deterministic state proof for + these HAL pin updates across native, Node, and browser. The Node inventory + guard requires this row to stay non-`REP` in Node and browser while it remains + `L4-USER-M-PROCESS`, and the generated inventory summary must keep it as + `SKIP` with that reason. +- `axis/db_demo/base.ngc` remains `L4-TOOL-DB`. The source INI declares + `[EMCIO]DB_PROGRAM = ./db_nonran.py`, so standalone interpreter execution + would miss LinuxCNC tool-database process startup and protocol/state + behavior. The LinuxCNC owner is `src/emc/task/taskclass.cc` for DB_PROGRAM + activation, `src/emc/tooldata/tooldata_db.cc` for DB process startup and + command/reply protocol, `src/emc/tooldata/tooldata_common.cc` for DB-backed + tooldata behavior, and the config program `configs/sim/axis/db_demo/db.py`. + Do not promote until the boundary design in + `docs/full-process-boundary-design.md` has a LinuxCNC-owned tool database + boundary that proves lookup/update behavior across native and WASM. The Node + inventory guard requires this row to stay non-`REP` in Node and browser while + it remains `L4-TOOL-DB`, and the generated inventory summary must keep it as + `SKIP` with that reason. +- Python-remap/full-process families remain `L4-PYTHON-REMAP`. The blocked + dependency inventory records Python modules, remap/prolog/epilog function + ownership, NGC remap subpaths, and HAL/UI/HALUI declarations for gmoccapy, + axis/laser, axis/remap demos, TWP nutating demos, and VMC tool-change + rows. The Python-specific boundary summary records the same row set as + inventory-only and requires a LinuxCNC-owned Python runtime boundary before + any promotion. Every `L4-PYTHON-REMAP` row must also remain `SKIP` with + `L4-PYTHON-REMAP` in the generated inventory summary. This is an inventory + artifact, not a Layer 4 execution path. Completion checks: ```bash wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh +wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh wasm-port/tests/browser/verify_interp_browser.sh ``` -Remaining work: +Current Layer 4 non-goals: -1. Extend `runtime/core/linuxcnc_wrap/linuxcnc_interp_wasm.cpp` with the same - machine-config entry point used by native tests. Done for the existing - `runFileWithIni()` file-execution path. +- Do not run all 159 programs in browser. +- Do not promote Python remap/full-process/HAL/UI-only families into + Emscripten without LinuxCNC-owned runtime support. +- Do not add JS-owned G-code, remap, tool, kinematics, parameter, or planner + semantics. -2. Extend `runtime/sdk/src/linuxcnc-interp.js` with a host-boundary method such - as: +Browser inventory decision record: - ```js - runSimConfigProgram({ iniPath, programPath, files }) - ``` - - Done. The method only writes caller-provided text files into the - Emscripten filesystem, applies executable bits for user M-code files, and - forwards execution to the existing LinuxCNC-backed C ABI path. It does not - implement CNC semantics in JavaScript. - -3. Copy required sim config files into the Emscripten FS: - - - INI; - - tool table; - - parameter file; - - `.ngc` program; - - `SUBROUTINE_PATH` files; - - `USER_M_PATH` handler files or registered adapter handlers. - - Done for the representative Node and browser subsets. - -4. Add Node WASM coverage. Done: - - ```text - wasm-port/tests/wasm/node/verify_sim_configs_wasm.mjs - wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh - ``` - -5. Add representative browser coverage. Done in - `wasm-port/tests/browser/interp_smoke.html` through the existing browser - interpreter smoke and the same `runSimConfigProgram()` SDK boundary as Node. +- Promoted after Node inventory: plain INI/tool-table execution + (`axis/gladevcp/probe.ngc`), deterministic macro/load execution + (`axis/external_offsets/circles.ngc`), deterministic on-abort/user-action + execution (`woodpecker/on_abort.ngc`), TDR/TRT five-axis remap execution, + bridge-mill W-axis remap execution, `melfa-sim`, and PUMA. + The Node inventory guard requires process-declaring representatives such as + `axis/gladevcp/probe.ngc`, `woodpecker/on_abort.ngc`, + `axis/vismach/melfa-sim/example.ngc`, and + `axis/vismach/puma/puma_cube.ngc` to keep their dependency rows in + `boundary-summary.tsv`, match the expected HAL/UI/HALUI/Python process flag + combinations, remain Node/browser `REP` rows, and avoid hard-block promotion + unless the classifier finds a real hard runtime dependency. +- Kept as blocked: TWP `table-rotary_spindle-rotary-nutating`, `gmoccapy`, + `axis/laser`, `axis/remap/*/nc_files`, and VMC tool-change Python remap + families. These are not missing browser staging work; they depend on + Python-remap, prolog/epilog, or full runtime process boundaries that have not + been intentionally exposed in Layer 4. +- Kept out of browser full inventory: remap subroutine assets and macro-only + non-representatives. They remain covered by native inventory, native remap + parse/execute probes, Node inventory where eligible, or a class + representative in browser. ## Phase 7: Documentation And Drift Control -Status: complete for the current representative sim-config WASM/browser -coverage. The documentation and manifest now record the native, Node WASM, -browser, source reuse, and vendor-sync state for the selected sim-config -programs. +Status: complete for the current full `configs/sim` coverage definition. The +documentation and manifest now record native inventory, generated class/path +artifacts, blocked policy, Node inventory, browser class coverage, source +reuse, and vendor-sync state. -1. Update `docs/compatibility-validation.md` with the sim-config matrix. Done. +1. Update `docs/compatibility-validation.md` with the sim-config matrix, + blocked policy, and validation commands. Done. -2. Update `docs/source-reuse-map.md` for newly vendored source files. Done. +2. Add `docs/sim-configs-coverage-matrix.md` as the tracked review surface for + all 159 current native inventory rows. Done. -3. Update `tools/source-manifest.txt` and `tools/verify_vendor_sync.sh` if new +3. Update `docs/source-reuse-map.md` for newly vendored source files. Done. + +4. Update `tools/source-manifest.txt` and `tools/verify_vendor_sync.sh` if new LinuxCNC files are copied into `wasm-port/vendor/linuxcnc`. Done for the - representative `axis/foam`, `axis/geometry`, and `axis/external_offsets` - sim-config files, including the remaining external-offset M111 programs and - `circles.ngc`; no `verify_vendor_sync.sh` logic change was needed. + current representative and inventory-backed sim-config files; no + `verify_vendor_sync.sh` logic change was needed. -4. Preserve the latest result summary as a machine-readable artifact, but do +5. Preserve the latest result summary as a machine-readable artifact, but do not commit generated logs unless they are intentionally used as fixtures. - Done: generated logs remain under build/test output directories, while the - tracked documentation records only the current summary values and validation - commands. + Done: `summary.tsv` remains the source row set, and `class-summary.tsv` plus + `path-matrix.tsv` are generated artifacts under `build/native/sim-configs/`. + Node inventory also writes `build/wasm/sim-configs-inventory/summary.tsv` + `build/wasm/sim-configs-inventory/skip-summary.tsv`, and + `build/wasm/sim-configs-inventory/boundary-summary.tsv` plus + `build/wasm/sim-configs-inventory/ini-boundary-summary.tsv` for Layer 4 + execution, skip/block accounting, and runtime-boundary dependency reporting. + The same inventory now writes the full blocked-boundary handoff artifacts: + `blocked-dependency-summary.tsv`, `full-process-boundary-summary.tsv`, + `user-m-process-boundary-summary.tsv`, `user-m-process-state-targets.tsv`, + `tool-db-process-boundary-summary.tsv`, + `tool-db-process-protocol-gates.tsv`, + `python-remap-boundary-summary.tsv`, `python-remap-family-summary.tsv`, + `boundary-phase-completion-summary.tsv`, + `native-proof-alignment-summary.tsv`, `next-boundary-worklist.tsv`, and + `boundary-proof-gates.tsv`. These remain accounting/proof-gate artifacts; + they do not enable blocked execution or promotion. + The inventory guard checks `skip-summary.tsv` against skip reasons derived + from `path-matrix.tsv`, so aggregate skip counts drift when any blocked or + class policy changes without updating the tracked matrix and inventory. + The inventory guard requires every vendored INI row to have an available + SDK runtime-boundary classifier report; `UNAVAILABLE` is reserved for rows + whose boundary summary records a missing vendored INI. + Hard blocked rows are additionally recorded in + `build/wasm/sim-configs-inventory/blocked-dependency-summary.tsv` without + promotion into standalone/WASM execution. That artifact includes source + owner fields and runtime proof fields such as `user_m_process_files`, + `user_m_process_effects`, `tool_db_protocol_evidence`, and `linuxcnc_owner`, + so `millturn` and `db_demo` remain blocked for dependency-backed reasons + rather than path-only classification. The follow-up boundary design and + required proof for those two blocked rows are tracked in + `docs/full-process-boundary-design.md`. Node inventory also writes + `build/wasm/sim-configs-inventory/full-process-boundary-summary.tsv` for + the designed-but-blocked non-Python full-process rows, including their + `runtime_owner_evidence`, and + `build/wasm/sim-configs-inventory/python-remap-boundary-summary.tsv` for + the Python remap inventory-only row set. The Python boundary and family + summaries include `python_runtime_evidence`. All blocked boundary artifacts + require `execution_enabled=0`. -## Recommended Work Order +## Layer 2 Expected-Failure Policy -1. Harness first: make `verify_sim_configs.sh` reproducible. -2. Axis config next: unblock `U/V/W` failures. -3. TWP mapping: complete; remaining TWP demo failures are Python/HAL remap - runtime edges. -4. User M-code dispatch: small runtime-edge feature, unblocks five files. -5. Python remap runtime: largest block; do it after the harness and smaller - runtime edges are stable. -6. WASM promotion after native parity. +The current Layer 2 baseline remains: + +```text +total: 159 +pass: 151 +fail: 8 +timeout: 0 +expected_fail: 8 +unexpected_fail: 0 +``` + +Do not reduce the eight expected failures by changing upstream G-code, JS +interpreter behavior, or project-owned standalone interpreter semantics. Reducing +this count is only valid if a new LinuxCNC-owned native/runtime entry point can +legitimately supply the missing task/user-M/axis/TWP context while preserving the +strict native baseline as a separately documented source of truth. + +## Recommended Next Work + +1. Keep `verify_sim_configs.sh`, `path-matrix.tsv`, and + `docs/sim-configs-coverage-matrix.md` in sync whenever the source manifest or + vendored sim-config set changes. +2. Add new Node/browser representatives only when they cover a new runtime class + with a LinuxCNC-owned execution path. +3. Treat Python remap, full-process HAL/UI, tool database, and external + userspace process families as blocked until their runtime boundary is + intentionally designed and the proof criteria in + `docs/full-process-boundary-design.md` are met where applicable. +4. Re-evaluate Layer 2 expected failures only after a new legitimate + LinuxCNC-owned entry point exists. ## Non-Goals diff --git a/wasm-port/docs/sim-configs-coverage-matrix.md b/wasm-port/docs/sim-configs-coverage-matrix.md new file mode 100644 index 0000000..24d4dc6 --- /dev/null +++ b/wasm-port/docs/sim-configs-coverage-matrix.md @@ -0,0 +1,421 @@ +# Sim Configs Coverage Matrix + +This matrix maps every current `wasm-port/tests/native/verify_sim_configs.sh` entry +to its native classification and current Layer 3/4 coverage status. It is the +tracked review surface for `linuxcnc/configs/sim` inventory; the native harness +also emits machine-readable artifacts for automation. + +Current baseline: + +- Source file: `wasm-port/build/native/sim-configs/summary.tsv` +- Generated class summary: `wasm-port/build/native/sim-configs/class-summary.tsv` +- Generated path matrix: `wasm-port/build/native/sim-configs/path-matrix.tsv` +- Total records: `159` +- Native result: `pass 151`, `expected_fail 8`, `unexpected_fail 0` +- Current Layer 4 representative subset: `axis/foam`, `axis/geometry`, + `axis/external_offsets`, `axis/gladevcp`, `woodpecker/on_abort.ngc`, + bridge-mill `5axisgui.ngc`, TDR/TRT five-axis switchkins demos, + `melfa-sim`, and `puma_cube.ngc` +- `wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs` checks that + this tracked matrix and generated `path-matrix.tsv` contain the same 159 paths + as native `summary.tsv` before running Node inventory. +- Node inventory artifact: `wasm-port/build/wasm/sim-configs-inventory/summary.tsv` +- Node skip/block artifact: `wasm-port/build/wasm/sim-configs-inventory/skip-summary.tsv` +- Node runtime-boundary artifact: `wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv` +- Node INI runtime-boundary artifact: + `wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv` +- Node blocked-dependency artifact: + `wasm-port/build/wasm/sim-configs-inventory/blocked-dependency-summary.tsv` +- Node full-process boundary design artifact: + `wasm-port/build/wasm/sim-configs-inventory/full-process-boundary-summary.tsv` +- Node user-M process boundary design artifact: + `wasm-port/build/wasm/sim-configs-inventory/user-m-process-boundary-summary.tsv` +- Node user-M process transition contract artifact: + `wasm-port/build/wasm/sim-configs-inventory/user-m-process-transition-plan.tsv` +- Node tool DB process boundary design artifact: + `wasm-port/build/wasm/sim-configs-inventory/tool-db-process-boundary-summary.tsv` +- Node tool DB process transaction contract artifact: + `wasm-port/build/wasm/sim-configs-inventory/tool-db-process-transaction-plan.tsv` +- Node Python-remap boundary inventory artifact: + `wasm-port/build/wasm/sim-configs-inventory/python-remap-boundary-summary.tsv` +- Node Python-remap family inventory artifact: + `wasm-port/build/wasm/sim-configs-inventory/python-remap-family-summary.tsv` +- Node Python-remap runtime contract artifact: + `wasm-port/build/wasm/sim-configs-inventory/python-remap-runtime-contract.tsv` +- Node Python-remap native runtime readiness artifact: + `wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-readiness.tsv` +- Node Python-remap native runtime state-plan artifact: + `wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-state-plan.tsv` +- Node Python-remap native runtime fixture-plan artifact: + `wasm-port/build/wasm/sim-configs-inventory/python-remap-native-runtime-fixture-plan.tsv` +- Node runtime-boundary contract summary artifact: + `wasm-port/build/wasm/sim-configs-inventory/runtime-boundary-contract-summary.tsv` +- Node boundary-phase completion artifact: + `wasm-port/build/wasm/sim-configs-inventory/boundary-phase-completion-summary.tsv` +- Node next-boundary worklist artifact: + `wasm-port/build/wasm/sim-configs-inventory/next-boundary-worklist.tsv` +- Current Node inventory: `executed 28`, `passed 28`, `skipped 131`, + `unexpected_fail 0` +- Current Node skip/block counts: `ASSET-ONLY 65`, `L4-PYTHON-REMAP 53`, + `L4-TOOL-DB 1`, `L4-USER-M-PROCESS 1`, `NON_MAIN_CLASS 10`, + `UPSTREAM-DEMO 1` + +Legend: + +- `Layer 3`: `SIM-*` means dedicated native runtime probe coverage; `5AX-EXEC` means + native five-axis remap execution coverage; `-` means no dedicated runtime probe yet. +- `Layer 4 Node/Browser`: `REP` means the current representative smoke covers this + exact program; `INV` means the Node inventory runner covers the exact program; + `N/A` means the row is a subroutine asset and should not be judged as a standalone + browser main program; `-` means the row is not individually promoted at that layer + and must be interpreted with the row's blocked or class-coverage note. +- `Blocked`: current hard blocked dependency or non-target classification for future + inventory work. `ASSET-ONLY` means the row is not a browser/main-program target. + `L4-PYTHON-REMAP` means native `rs274` coverage exists but Node/browser full inventory + is blocked on an intentional Python-remap runtime boundary decision. `UPSTREAM-DEMO` + means the file is a preserved upstream expected-failure edge. +- `boundary-summary.tsv`: one row per native inventory path. It records the + matrix blocked kind, the SDK classifier's recommended hard block when an INI + is vendored, declared HAL/UI/HALUI/Python process dependencies, tool database + declarations, user-M process codes seen in the execution text, and which of + those user-M codes are not staged by vendored `USER_M_PATH` files. Python is + split into total process dependency, UI/DB process dependency, and Python + remap runtime dependency so safe UI representatives such as `gladevcp` are + not mislabeled as Python-remap coverage. Rows whose INI has not been + vendored yet use `recommended_blocked=UNAVAILABLE` and keep their tracked + matrix policy as the source of truth until the relevant boundary inventory + batch vendors the missing context. +- `ini-boundary-summary.tsv`: one row per unique INI referenced by the native + inventory. It aggregates path-level boundary reports so vendored INIs have a + direct machine-readable `report_available=1` check and hard block + recommendations can be audited at INI granularity. +- `blocked-dependency-summary.tsv`: one row per hard blocked + `L4-PYTHON-REMAP`, `L4-TOOL-DB`, and `L4-USER-M-PROCESS` path. It reads the + source `linuxcnc/configs/sim` INI files without vendoring or executing those + families, records Python modules, remap/prolog/epilog function ownership, + NGC remap subpaths, HAL/UI/HALUI process declarations, `DB_PROGRAM`, and + tool database protocol evidence, plus external user-M execution codes, their + process script files, and process side-effect evidence. The `linuxcnc_owner` + field records the LinuxCNC source/config files that own the blocked behavior, + and keeps those rows blocked until a LinuxCNC-owned runtime boundary is + designed. +- `full-process-boundary-summary.tsv`: one row for each designed-but-still-blocked + non-Python full-process boundary. It currently covers `axis/db_demo/base.ngc` + and `axis/vismach/millturn/example.ngc`, records LinuxCNC runtime owner + evidence, records required native/Node/browser proof, and requires + `execution_enabled=0`. +- `user-m-process-boundary-summary.tsv`: one row for each designed-but-still-blocked + external user-M process boundary. It currently records the `millturn` + `M128`/`M129` process files, remap call chain, kinstype guards, and + source-traceable `ini.[xyz].*` HAL pin state targets, while requiring + `execution_enabled=0` and `promotion_allowed=0`. +- `user-m-process-transition-plan.tsv`: the pending non-executing transition + contract for the `millturn` user-M boundary. It binds `M428` to `M128` and + `M429` to `M129`, records switchkins output/target, active G5x work offset, + guard pin, state mode, and expected `ini.[xyz].*` outputs, and still requires + `execution_enabled=0` and `promotion_allowed=0`. +- `user-m-process-native-transition-alignment.tsv`: the native source + alignment for the two `millturn` transition rows. It proves the generated + `M428/M429` transition contract still matches the native probe stdout for + switchkins output/target, G5x, offset pocket, and `M428 -> M128` / + `M429 -> M129` calls, while remaining pending and non-executing. +- `user-m-process-native-runtime-state-plan.tsv`: the pending native runnable + state-probe contract for `millturn`. It records the required LinuxCNC + task/HAL/Tcl user-M runtime, the HAL/INI environment, and exact + `ini.[xyz].*` values that a future runtime probe must observe after the + transitions, while keeping `execution_enabled=0` and `promotion_allowed=0`. +- `user-m-process-native-runtime-readiness.tsv`: the host capability gate for + that future native probe. It records whether `tclsh`, `halrun`, `halcmd`, + and `linuxcnc` are available on PATH and keeps the boundary pending and + non-promotable regardless of host readiness. +- `user-m-process-native-runtime-probe-gate.tsv`: the generated execution gate + for that future native probe. It records per-transition runtime readiness, + missing host commands, source-proof readiness, and the pending gate status. + The native `probe_millturn_user_m_runtime.sh` entry point reports + `skipped_missing_host_runtime` on hosts without the full LinuxCNC HAL/Tcl + runtime, `ready_disabled_by_default` when the host is ready but the guarded + runtime probe is not explicitly enabled, or `runtime_state_probe_passed` when + `ENABLE_MILLTURN_USER_M_RUNTIME_PROBE=1` proves the LinuxCNC-owned + `M128`/`M129` Tcl scripts update the expected `ini.[xyz].*` HAL pins. + command set and does not enable execution or promotion. +- `tool-db-process-boundary-summary.tsv`: one row for each designed-but-still-blocked + tool database process boundary. It currently records `db_nonran.py`, + LinuxCNC tooldata protocol messages, DB program callbacks, nonrandom tool + database state targets, and runtime owner evidence, while requiring + `execution_enabled=0` and `promotion_allowed=0`. +- `tool-db-process-transaction-plan.tsv`: the pending non-executing transaction + contract for the `db_demo` tool database boundary. It orders startup + handshake, get-all, spindle load notify, tool offset notify, and spindle + unload notify steps, binds each protocol message to the expected `db.py` + callback and state targets, and still requires `execution_enabled=0` and + `promotion_allowed=0`. +- `tool-db-process-native-runtime-readiness.tsv`: the host capability gate for + the guarded native DB process protocol probe. It records whether `python3`, + `linuxcnc`, `milltask`, `halcmd`, the configured `db_nonran.py`, and + LinuxCNC's `linuxcnc.so` / `tooldb.py` Python modules are available, while + keeping the DB boundary pending and non-promotable. The native + `probe_tool_db_runtime.sh` entry point reports `skipped_missing_host_runtime` + when the host runtime is unavailable, `ready_disabled_by_default` when it is + available but not explicitly enabled, or `runtime_protocol_probe_passed` when + `ENABLE_TOOL_DB_RUNTIME_PROBE=1` proves the LinuxCNC-owned `DB_PROGRAM` + `v2.1`/`g`/`p`/`l`/`u` protocol, nonrandom state updates, and flat-file + persistence. +- `python-remap-boundary-summary.tsv`: one row for each `L4-PYTHON-REMAP` + path. It records Python modules, remap/prolog/epilog functions, NGC-only + subpaths, HAL/UI/HALUI assumptions, the LinuxCNC Python owner set, LinuxCNC + Python runtime owner evidence, and requires `execution_enabled=0`. +- `python-remap-family-summary.tsv`: one row per blocked Python-remap runtime + family. It aggregates row and INI counts plus Python module, + remap/prolog/epilog, NGC-only subpath, Python runtime owner evidence, + HAL/UI/HALUI, and `execution_enabled=0` evidence without vendoring or + executing those families. +- `python-remap-runtime-contract.tsv`: one row per blocked Python-remap runtime + family. It records LinuxCNC-owned Python runtime phases, Python modules, + remap/prolog/epilog callables, NGC-only subpaths, HAL/UI/HALUI assumptions, + native/Node/browser proof requirements, and keeps `proof_status=pending`, + `execution_enabled=0`, and `promotion_allowed=0`. +- `python-remap-native-runtime-readiness.tsv`: the host/source capability gate + for guarded native Python-remap runtime probes. It records `python3`, + `linuxcnc`, LinuxCNC's Python interpreter/plugin owner source files, and the + configured Python modules for each blocked family, while keeping every row + pending, non-executing, and non-promotable. +- `python-remap-native-runtime-state-plan.tsv`: one row per blocked + Python-remap family. It records the runtime phases, modules, callables, + NGC-only subpaths, process assumptions, readiness counts, source-alignment + inputs, and exact future native state-probe targets while keeping every row + pending, non-executing, and non-promotable. +- `python-remap-native-runtime-fixture-plan.tsv`: the first non-executing + Python runtime fixture plan. It selects + `axis/remap/stop-lookahead/nc_files` as the minimal lifecycle fixture because + it has Python modules and runtime phases without Python callable or NGC-only + subpath complexity, and keeps execution/promotion disabled. The native + `probe_python_remap_runtime.sh` entry point reports + `skipped_missing_host_runtime` without the host runtime, + `ready_disabled_by_default` when the host is ready but the probe is not + explicitly enabled, or `runtime_lifecycle_probe_passed` when + `ENABLE_PYTHON_REMAP_RUNTIME_PROBE=1` proves the `demo.ini` + path/toplevel import, `queuebuster` callable lookup, generator return, and + first `INTERP_EXECUTE_FINISH` yield. +- `runtime-boundary-contract-summary.tsv`: one row per blocked runtime boundary + class. It unifies the user-M transition contract, tool DB transaction + contract, and Python runtime contract with their native-alignment artifact, + and requires every contract row to remain pending with execution and + promotion disabled. +- `boundary-phase-completion-summary.tsv`: one row per boundary-phase + completion criterion. It requires vendored INI boundary reports, dependency + evidence for hard blocks, safe HAL/UI representative coverage, blocked + families remaining skipped/non-representative with execution disabled, and + LinuxCNC-owned runtime proof fields for user-M, tool DB, and Python runtime + blockers. When native source proof is available, it also requires that proof + to be consumed by generated worklist/native proof-gate rows without enabling + execution or promotion. +- `native-proof-alignment-summary.tsv`: one row per native source proof class. + It aligns the native source proof summary with generated worklist/native + proof-gate consumers for user-M, tool DB, and Python runtime blockers. +- `next-boundary-worklist.tsv`: one row per next blocked runtime-boundary + design target. It keeps execution and promotion disabled, records the + LinuxCNC owner set and runtime owner evidence, records native, Node, and + browser proof requirements, and names the next boundary-design action before + any blocked family can be promoted. + +## Summary + +| Class | Count | +| --- | --- | +| `main` | `48` | +| `macro_load` | `46` | +| `remap_subroutine` | `65` | + +## Family Summary + +| Family | Count | +| --- | --- | +| `axis/db_demo` | `1` | +| `axis/external_offsets` | `6` | +| `axis/foam` | `1` | +| `axis/geometry` | `1` | +| `axis/gladevcp` | `1` | +| `axis/laser` | `3` | +| `axis/lathe-fanucy` | `1` | +| `axis/remap` | `29` | +| `axis/rose_engine` | `2` | +| `axis/vismach` | `57` | +| `gmoccapy/lathe_configs` | `8` | +| `gmoccapy/macros` | `25` | +| `gmoccapy/non_trivial_kinematics` | `5` | +| `gscreen/industrial_lathe_wear` | `1` | +| `gscreen/silverdragon` | `4` | +| `qtaxis/non-trivial` | `3` | +| `qtdragon/qtdragon_multi_joint` | `1` | +| `qtdragon/qtdragon_xyz` | `1` | +| `qtdragon/qtdragon_xyz45` | `1` | +| `qtdragon_hd/qtdragon_hd_xyz` | `1` | +| `qtdragon_hd/qtdragon_hd_z_compensation` | `1` | +| `qtvcp_screens/industrial_lathe_wear` | `1` | +| `qtvcp_screens/non-trivial` | `3` | +| `qtvcp_screens/qtdragon` | `1` | +| `woodpecker` | `1` | + +## Program Matrix + +| Path | Family | Class | Native | Expected Failure | Layer 3 | Layer 4 Node | Layer 4 Browser | Blocked | Notes | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| `axis/db_demo/base.ngc` | `axis/db_demo` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-TOOL-DB` | native pass, but Node/browser inventory is blocked by the LinuxCNC tool-database process boundary declared by `[EMCIO]DB_PROGRAM` | +| `axis/external_offsets/circles.ngc` | `axis/external_offsets` | `macro_load` | `PASS` | `-` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 4 macro-only class representative now covered through wrapped execution with native staging inputs | +| `axis/external_offsets/dyn_demo.ngc` | `axis/external_offsets` | `main` | `FAIL` | `user-m-code-M111` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 2 expected-fail; M111 runtime edge covered | +| `axis/external_offsets/eoffsets.ngc` | `axis/external_offsets` | `main` | `FAIL` | `user-m-code-M111` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 2 expected-fail; M111 runtime edge covered | +| `axis/external_offsets/jwp_z.ngc` | `axis/external_offsets` | `main` | `FAIL` | `user-m-code-M111` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 2 expected-fail; M111 runtime edge covered | +| `axis/external_offsets/opa_demo.ngc` | `axis/external_offsets` | `main` | `FAIL` | `user-m-code-M111` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 2 expected-fail; M111 runtime edge covered | +| `axis/external_offsets/queuebuster.ngc` | `axis/external_offsets` | `macro_load` | `PASS` | `-` | `SIM-EOFF` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` | +| `axis/foam/foam.ngc` | `axis/foam` | `main` | `FAIL` | `ini-axis-mask-UV` | `SIM-FOAM` | `REP` | `REP` | `-` | Layer 2 expected-fail; Layer 3/4 runtime edge covered | +| `axis/geometry/xyzc.ngc` | `axis/geometry` | `main` | `FAIL` | `user-m-code-M110` | `SIM-XYZC` | `REP` | `REP` | `-` | Layer 2 expected-fail; M110 runtime edge covered | +| `axis/gladevcp/probe.ngc` | `axis/gladevcp` | `main` | `PASS` | `-` | `-` | `REP` | `REP` | `-` | plain INI/tool-table main-program class representative covered in Node and browser through vendored staging inputs | +| `axis/laser/raster_test.ngc` | `axis/laser` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `axis/laser/vector_test.ngc` | `axis/laser` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `axis/laser/vector_test2.ngc` | `axis/laser` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `axis/lathe-fanucy/toolchange.ngc` | `axis/lathe-fanucy` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later | +| `axis/remap/cycle/nc_files/examples.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python remap/prolog/epilog runtime boundaries; remap subroutine assets remain `ASSET-ONLY` | +| `axis/remap/cycle/nc_subroutines/g843.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/extend-builtins/nc_files/examples.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python prolog/epilog remap runtime boundaries; remap subroutine assets remain `ASSET-ONLY` | +| `axis/remap/extend-builtins/nc_subroutines/change.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/extend-builtins/nc_subroutines/extend_m0.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/extend-builtins/nc_subroutines/extend_m1.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/extend-builtins/nc_subroutines/extend_m60.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/extend-builtins/nc_subroutines/extend_m7.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/extend-builtins/nc_subroutines/extend_m8.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/extend-builtins/nc_subroutines/extend_m9.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/extend-builtins/nc_subroutines/prepare.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/extend-builtins/nc_subroutines/setfeed.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/extend-builtins/nc_subroutines/setspeed.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/extend-builtins/nc_subroutines/settool.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/getting-started/nc_files/examples.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python remap handlers such as `G88.1`; remap subroutine assets remain `ASSET-ONLY` | +| `axis/remap/getting-started/nc_subroutines/change_min.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/getting-started/nc_subroutines/m400.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/getting-started/nc_subroutines/m410.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/getting-started/nc_subroutines/prepare_min.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/manual-toolchange-with-tool-length-switch/nc_files/tcdemo.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python tool-change prolog/epilog runtime boundaries; remap subroutine assets remain `ASSET-ONLY` | +| `axis/remap/manual-toolchange-with-tool-length-switch/nc_subroutines/manual_change.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/manual-toolchange-with-tool-length-switch/nc_subroutines/on_abort.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/manual-toolchange-with-tool-length-switch/nc_subroutines/restore.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/rack-toolchange/nc_files/tcdemo.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python tool-change prolog/epilog runtime boundaries; remap subroutine assets remain `ASSET-ONLY` | +| `axis/remap/rack-toolchange/nc_subroutines/on_abort.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/rack-toolchange/nc_subroutines/rack_change.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/rack-toolchange/nc_subroutines/tool_getput_move.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/rack-toolchange/nc_subroutines/tool_holder_clear_move.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/remap/stop-lookahead/nc_files/examples.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python `queuebuster` remap runtime boundaries; remap subroutine assets remain `ASSET-ONLY` | +| `axis/rose_engine/rcone.ngc` | `axis/rose_engine` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later | +| `axis/rose_engine/rcone_demo.ngc` | `axis/rose_engine` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | Node inventory coverage uses the native harness-selected `axis/sim.tbl` fallback staged at the INI-declared tool-table path; browser class coverage is represented by other plain INI/tool-table samples | +| `axis/vismach/5axis/bridgemill/5axisgui.ngc` | `axis/vismach` | `main` | `FAIL` | `ini-axis-mask-W` | `SIM-BRIDGE,5AX-EXEC` | `REP` | `REP` | `-` | Layer 2 expected-fail; W-axis and remap runtime edge covered | +| `axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/bridgemill/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/bridgemill/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-dual-rotary/demos/xyzab-tdr-demo.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TDR five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging | +| `axis/vismach/5axis/table-dual-rotary/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-dual-rotary/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzac.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging | +| `axis/vismach/5axis/table-rotary-tilting/demos/boat-xyzbc.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging | +| `axis/vismach/5axis/table-rotary-tilting/demos/impeller-7bl-xyzac.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging | +| `axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging | +| `axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging | +| `axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_2.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging | +| `axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_3.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging | +| `axis/vismach/5axis/table-rotary-tilting/demos/xyzbc_switchkins.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `5AX-EXEC` | `REP` | `REP` | `-` | TRT five-axis remap class covered in Node and browser through vendored INI, tool-table, remap-subroutine, and demo staging | +| `axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary-tilting/remap_subs/centering.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary-tilting/remap_subs/helix_ac.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary-tilting/remap_subs/helix_bc.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary-tilting/remap_subs/xyzac_switchkins_sub.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary-tilting/remap_subs/xyzbc_switchkins_sub.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/circular_pocket.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass, but Layer 4 full inventory is blocked on Python remap entry points such as g682, g69_core, and g53x_core | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass, but Layer 4 full inventory is blocked on Python remap entry points such as g682, g69_core, and g53x_core | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_back_and_forth.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass, but Layer 4 full inventory is blocked on Python remap entry points such as g682, g69_core, and g53x_core | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/incremental_repetition_g533.ngc` | `axis/vismach` | `main` | `FAIL` | `upstream-demo-missing-motion-gcode` | `-` | `-` | `-` | `UPSTREAM-DEMO` | preserve upstream demo failure; do not force PASS | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/simple_example.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass, but Layer 4 full inventory is blocked on Python remap entry points such as g682, g69_core, and g53x_core | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/demos/square.ngc` | `axis/vismach` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass, but Layer 4 full inventory is blocked on Python remap entry points such as g682, g69_core, and g53x_core | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/g531remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/g533remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/g536remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/g69remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/on_abort_no_twp_reset.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/5axis/table-rotary_spindle-rotary-nutating/remap_subs/on_abort_with_twp_reset.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/VMC_toolchange/toolchange.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python tool-change prolog/epilog and full tool-change runtime boundaries | +| `axis/vismach/hexapod-sim/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/hexapod-sim/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/hexapod-sim/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/melfa-sim/example.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `REP` | `REP` | `-` | robot/Genser-style remap machine class representative covered in Node and browser through vendored INI, tool-table, and remap-subroutine staging | +| `axis/vismach/melfa-sim/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/melfa-sim/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/melfa-sim/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/millturn/example.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-USER-M-PROCESS` | native pass, but Node/browser inventory is blocked by external `USER_M_PATH` process M-codes `M128` and `M129` rather than the deterministic `M110`/`M111` boundary already modeled by the standalone runtime | +| `axis/vismach/millturn/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/millturn/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/puma/puma_cube.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `REP` | `REP` | `-` | PUMA kinematics/remap machine class representative covered in Node and browser through vendored INI, tool-table, and remap-subroutine staging | +| `axis/vismach/puma/puma_seam_weld.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | Node inventory covered with the same vendored puma machine context; browser class coverage is represented by `puma_cube.ngc` | +| `axis/vismach/puma/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/puma/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/puma/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/scara/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/scara/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `axis/vismach/scara/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `gmoccapy/lathe_configs/boring.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/lathe_configs/chamfer.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/lathe_configs/drilling.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/lathe_configs/facing.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/lathe_configs/grooving.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/lathe_configs/radius.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/lathe_configs/threading.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/lathe_configs/turning.ngc` | `gmoccapy/lathe_configs` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/change.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/change_g43.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/go_to_position.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/halo_world.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/i_am_lost.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/increment.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/jog_around.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_0.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_1.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_10.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_11.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_12.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_13.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_14.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_15.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_2.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_3.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_4.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_5.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_6.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_7.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_8.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/macro_9.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/on_abort.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/macros/settool_g43.ngc` | `gmoccapy/macros` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/boat-xyzac.ngc` | `gmoccapy/non_trivial_kinematics` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/boat-xyzbc.ngc` | `gmoccapy/non_trivial_kinematics` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/impeller-7bl-xyzac.ngc` | `gmoccapy/non_trivial_kinematics` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/test-xyzac.ngc` | `gmoccapy/non_trivial_kinematics` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gmoccapy/non_trivial_kinematics/table-rotary-tilting/examples/test-xyzbc.ngc` | `gmoccapy/non_trivial_kinematics` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native pass; Layer 4 is blocked until the Python-remap runtime boundary is deliberately designed | +| `gscreen/industrial_lathe_wear/toolchange.ngc` | `gscreen/industrial_lathe_wear` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later | +| `gscreen/silverdragon/macros/auto_zref.ngc` | `gscreen/silverdragon` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later | +| `gscreen/silverdragon/macros/laserzero.ngc` | `gscreen/silverdragon` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later | +| `gscreen/silverdragon/macros/tool_sensor.ngc` | `gscreen/silverdragon` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later | +| `gscreen/silverdragon/macros/touch_plate.ngc` | `gscreen/silverdragon` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later | +| `qtaxis/non-trivial/scara/remap_subs/428remap.ngc` | `qtaxis/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `qtaxis/non-trivial/scara/remap_subs/429remap.ngc` | `qtaxis/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `qtaxis/non-trivial/scara/remap_subs/430remap.ngc` | `qtaxis/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `qtdragon/qtdragon_multi_joint/on_abort.ngc` | `qtdragon/qtdragon_multi_joint` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample | +| `qtdragon/qtdragon_xyz/on_abort.ngc` | `qtdragon/qtdragon_xyz` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample | +| `qtdragon/qtdragon_xyz45/on_abort.ngc` | `qtdragon/qtdragon_xyz45` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample | +| `qtdragon_hd/qtdragon_hd_xyz/on_abort.ngc` | `qtdragon_hd/qtdragon_hd_xyz` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample | +| `qtdragon_hd/qtdragon_hd_z_compensation/on_abort.ngc` | `qtdragon_hd/qtdragon_hd_z_compensation` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample | +| `qtvcp_screens/industrial_lathe_wear/toolchange.ngc` | `qtvcp_screens/industrial_lathe_wear` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later | +| `qtvcp_screens/non-trivial/scara/remap_subs/428remap.ngc` | `qtvcp_screens/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `qtvcp_screens/non-trivial/scara/remap_subs/429remap.ngc` | `qtvcp_screens/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `qtvcp_screens/non-trivial/scara/remap_subs/430remap.ngc` | `qtvcp_screens/non-trivial` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | +| `qtvcp_screens/qtdragon/on_abort.ngc` | `qtvcp_screens/qtdragon` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | vendored INI/tool-table now allow Node inventory coverage; browser representative still delegated to the shared `woodpecker/on_abort.ngc` class sample | +| `woodpecker/on_abort.ngc` | `woodpecker` | `main` | `PASS` | `-` | `-` | `REP` | `REP` | `-` | Layer 4 deterministic on_abort class representative now covered | diff --git a/wasm-port/docs/source-reuse-map.md b/wasm-port/docs/source-reuse-map.md index 38ca74c..445cfda 100644 --- a/wasm-port/docs/source-reuse-map.md +++ b/wasm-port/docs/source-reuse-map.md @@ -41,7 +41,8 @@ Current validation is intentionally mechanical: | Switchable 5-axis bridge kinematics | `src/emc/kinematics/5axiskins.c`, `switchkins.c`, `switchkins.h`, `userkfuncs.c`, plus `src/rtapi/rtapi_ctype.h` | Copy unchanged | HAL pin allocation, HAL component lifecycle, and RTAPI module metadata are standalone runtime edges; switchable 5-axis forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_5axis_kinematics_probe` | | TRT table-rotary kinematics | `src/emc/kinematics/trtfuncs.c`, `xyzac-trt-kins.c`, `xyzbc-trt-kins.c` | Copy unchanged | HAL pin allocation and switchkins lifecycle stay runtime boundaries; XYZAC/XYZBC TRT forward/inverse behavior remains LinuxCNC source | Vendor byte sync, per-file source probes, `linuxcnc_xyzac_trt_kinematics_probe`, `linuxcnc_xyzbc_trt_kinematics_probe` | | Five-axis switchkins machine configs and M428/M429/M430 remaps | `configs/sim/axis/vismach/5axis/bridgemill/*`, `table-dual-rotary/*`, and `table-rotary-tilting/*` selected INI, HAL, tool-table, XML, demo, and `remap_subs/*.ngc` files plus `src/emc/rs274ngc/interp_remap.cc` | Copy unchanged | `M428`, `M429`, and `M430` remain LinuxCNC `REMAP` entries that call LinuxCNC NGC subroutines using `M68`, `M66`, `_hal[motion.switchkins-type]`, and the INI/HAL `motion.analog-out-03 => motion.switchkins-type` link; standalone remap descriptor parsing routes through vendored `Interp::parse_remap()` and `find_ngc_file()`, and NGC remap/file execution routes through vendored LinuxCNC O-word and `open()`/`read()`/`execute()` paths while HAL synchronization stays a runtime adapter boundary | Vendor byte sync, `linuxcnc_5axis_remap_asset_probe`, `linuxcnc_remap_parse_harness`, `linuxcnc_remap_hal_sync_harness`, `linuxcnc_5axis_remap_execute_harness`, `tests/wasm/node/verify_interp_wasm.sh`, `tests/wasm/node/verify_sim_configs_wasm.sh`, `tests/browser/verify_interp_browser.sh`, `tests/browser/verify_ini_panel_browser.sh` | -| Representative sim-config machine programs | `configs/sim/axis/foam/*`, `configs/sim/axis/geometry/M110`, `xyzc.ini`, `xyzc.ngc`, `configs/sim/axis/external_offsets/M111`, `dyn_demo.ngc`, `dynamic_offsets.ini`, `eoffsets.ngc`, `eoffsets.ini`, `jwp_z.ngc`, `jwp_z.ini`, `opa_demo.ngc`, `opa.ini`, `circles.ngc`, `eoffset.tbl`, and `configs/sim/axis/sim.tbl` | Copy unchanged | The `foam`, `xyzc`, and external-offset sample programs remain LinuxCNC sim-config assets. The standalone boundary only copies INI, tool table, G-code, executable user-M files, `SUBROUTINE_PATH` files, and remap-NGC files into the native or WASM filesystem, then calls vendored LinuxCNC INI parsing and `Interp::open()`/`read()`/`execute()` through the existing machine-config adapter. The native sim-config harness now prefers `[DISPLAY]OPEN_FILE` when several INI files live beside a program, so each program is judged with its corresponding machine context. The JS SDK `planIniFileContextStaging()` is a generic manifest-based file-plan helper, `planSimConfigStaging()` is its `configs/sim` wrapper, and `runSimConfigProgram()` only writes caller-provided text files to the Emscripten filesystem, applies executable bits, and forwards to LinuxCNC-backed C ABI entry points. `M110`/`M111` process execution stays a runtime boundary represented by deterministic `USER_M_COMMAND` canonical events | Vendor byte sync, `tests/native/verify_sim_configs.sh`, `tests/wasm/node/verify_sim_configs_wasm.sh`, `tests/browser/verify_interp_browser.sh` | +| Representative sim-config machine programs | `configs/sim/axis/foam/*`, `configs/sim/axis/geometry/M110`, `xyzc.ini`, `xyzc.ngc`, `configs/sim/axis/external_offsets/M111`, `dyn_demo.ngc`, `dynamic_offsets.ini`, `eoffsets.ngc`, `eoffsets.ini`, `jwp_z.ngc`, `jwp_z.ini`, `opa_demo.ngc`, `opa.ini`, `circles.ngc`, `eoffset.tbl`, `configs/sim/axis/sim.tbl`, `configs/sim/axis/gladevcp/gladevcp_panel.ini`, `probe.ngc`, `sim.tbl`, `configs/sim/axis/vismach/melfa-sim/*`, selected `configs/sim/axis/vismach/puma/*`, and `configs/sim/woodpecker/on_abort.ngc`, `tool.tbl`, `woodpecker.ini` | Copy unchanged | The `foam`, `xyzc`, external-offset, plain `gladevcp/probe.ngc`, `melfa-sim`, PUMA, and deterministic `woodpecker/on_abort.ngc` sample programs remain LinuxCNC sim-config assets. The standalone boundary only copies INI, tool table, G-code, executable user-M files, `SUBROUTINE_PATH` files, and remap-NGC files into the native or WASM filesystem, then calls vendored LinuxCNC INI parsing and `Interp::open()`/`read()`/`execute()` or the existing five-axis remap execution C ABI through the machine-config adapter. The native sim-config harness now prefers `[DISPLAY]OPEN_FILE` when several INI files live beside a program, so each program is judged with its corresponding machine context. The JS SDK `planIniFileContextStaging()` is a generic manifest-based file-plan helper, `planSimConfigStaging()` is its `configs/sim` wrapper, and `runSimConfigProgram()` only writes caller-provided text files to the Emscripten filesystem, applies executable bits, and forwards to LinuxCNC-backed C ABI entry points. `M110`/`M111` process execution stays a runtime boundary represented by deterministic `USER_M_COMMAND` canonical events, while GUI driver, HAL process launch, and external userspace process startup remain outside standalone Node/browser execution. The TWP `table-rotary_spindle-rotary-nutating` demo family remains outside this representative row because its Layer 4 promotion still depends on a deliberate Python-remap runtime boundary, not on additional JS-owned staging logic. | Vendor byte sync, `tests/native/verify_sim_configs.sh`, `tests/wasm/node/verify_sim_configs_wasm.sh`, `tests/wasm/node/verify_sim_configs_inventory_wasm.sh`, `tests/browser/verify_interp_browser.sh`, `tests/host/verify_host_smokes.sh` | +| Sim-config inventory and blocked-boundary assets | Selected `configs/sim/axis/db_demo/*`, `axis/rose_engine/*`, `axis/vismach/millturn/*`, `configs/sim/qtdragon/*`, `configs/sim/qtdragon_hd/*`, and `configs/sim/qtvcp_screens/qtdragon/*` files | Copy unchanged | These assets are vendored for the machine-readable `configs/sim` Node inventory and blocked-boundary accounting. Eligible `on_abort` and plain INI/tool-table rows run through the same LinuxCNC-backed `runSimConfigProgram()` staging path as other sim-config samples. Rows such as `axis/db_demo/base.ngc` and `axis/vismach/millturn/example.ngc` remain explicit Layer 4 blocked entries because their native LinuxCNC configs depend on tool-database or external user-M process boundaries; Node/browser inventory records those dependencies instead of reducing them to standalone file execution. | Vendor byte sync, `tests/native/verify_sim_configs.sh`, `tests/wasm/node/verify_sim_configs_inventory_wasm.sh`, `tests/host/verify_host_smokes.sh` | | Representative `nc_files` examples | `nc_files/3D_Chips.ngc`, `nc_files/arcspiral.ngc`, `nc_files/factorial.ngc`, `nc_files/hole-circle.ngc`, `nc_files/m6demo.ngc` | Copy unchanged | These upstream `linuxcnc/nc_files` examples are copied byte-for-byte into the WASM vendor tree after the native `nc_files` harness classifies the broader directory. Node and browser tests only stage the original `.ngc` text and, for `3D_Chips.ngc`, the minimal INI-declared tool table context required by its upstream `T1 M6` line in the Emscripten filesystem, then call the LinuxCNC-backed `Interp::open()`, `read()`, and `execute()` path through the existing SDK; no G-code, O-word, tool-change, or M-code behavior is implemented in JavaScript | Vendor byte sync, `tests/native/verify_nc_files.sh`, `tests/wasm/node/verify_nc_files_wasm.sh`, `tests/browser/verify_interp_browser.sh`, `tests/host/verify_host_smokes.sh` | | LinuxCNC remap regression fixtures | `tests/remap/duplicate-o-word/*`, `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/*`, selected NGC-only `tests/remap/remap-io/test-ngc.ini` plus `io_*.ngc`, and `src/emc/rs274ngc/interp_remap.cc` plus `interp_o_word.cc` | Copy unchanged | The upstream duplicate O-word, NGC-only remap failure, M30/remap-level interaction, nested O-word remap, positional-argument remap, G/M remap sequencing, and remap-IO NGC subroutine regressions remain LinuxCNC REMAP/O-word/file or MDI execution tests. The standalone boundary only copies the upstream test files into native or WASM filesystems, reads LinuxCNC INI `SUBROUTINE_PATH`, `REMAP`, and `OWORD_NARGS` entries, and calls vendored `Interp::parse_remap()`, `open()`, `read()`, and `execute()` or feeds the upstream remap-IO MDI sequence into vendored `Interp::execute()`; the continue-on-error runner path only mirrors LinuxCNC `rs274 -n 0` test execution and does not implement duplicate-label, O-word, nested remap, M30, positional-argument, failure, sequencing, M62-M68, M66 input, or remap semantics | Vendor byte sync, `linuxcnc_duplicate_oword_remap_harness`, `tests/wasm/node/verify_interp_wasm.sh`, `tests/browser/verify_interp_browser.sh` | | LinuxCNC interpreter regression fixtures | `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/flowsnake/*`, selected `tests/interp/good/*.ngc` center-format arc tolerance fixtures, `tests/interp/g6164/*`, `tests/interp/inside-corners/*`, `tests/interp/inverse-time-with-comp/*`, selected `tests/ccomp/*` standalone cutter-compensation fixtures, selected `tests/interp/bad/*.ngc` file-error fixtures, `tests/interp/g33.1/*`, selected `tests/interp/g71-*/*` and `tests/interp/g72-*/*` lathe canned-cycle fixtures, `tests/interp/g76/*`, `tests/interp/g10/*`, `tests/interp/g52/g52-g92-interaction/*`, selected `tests/interp/rotation/*` pure interpreter cases, `tests/interp/iniparam/*`, `tests/interp/iniparam-failassign/*`, `tests/interp/m19/*`, `tests/interp/magic_comments/param_format_printing/*`, selected `tests/interp/m98m99/*` pure interpreter cases, `tests/interp/sub-call-from-sub/*`, `tests/interp/sequence-number/*`, `tests/interp/nested-sub-error/*`, `tests/interp/nested-sub-in-file-error/*`, `tests/interp/oword-unwind/*`, `tests/interp/abort-hot-comment/*`, plus vendored interpreter/O-word sources including `interp_o_word.cc`, `interp_read.cc`, `interp_execute.cc`, `interp_find.cc`, `interp_namedparams.cc`, and `rs274ngc_pre.cc` | Copy unchanged | The upstream do/while/break, O-word bug315, `EXISTS[]`, subroutine return-value, subs-after-main, fractional line-number, storm-door latch cam toolpath with upstream tool-table context, named-parameter, recursive O-word flowsnake toolpath, selected center-format arc tolerance acceptance/rejection cases, `G61`/`G64` path-control and naive-cam tolerance behavior, cutter-compensation concave/convex/tangent geometry, inverse-time feed and cutter-compensation interaction, selected standalone cutter-compensation file execution with upstream tool tables, selected file-execution error cases including canned-cycle A-axis rejection, center-format arc radius mismatch rejection, cutter-compensation arc-exit/gouging rejection, and malformed `EXISTS[]`, rigid-tap `G33.1`, G71/G72 lathe canned-cycle iteration behavior, G76 lathe threading with upstream tool-table context, `G10 L1/L10/L11/L2/L20` tool-table/offset/G5X/G92/rotation regressions, G52/G92 shared-offset interaction, selected rotation/G53/G28 absolute-position and endpoint, INI named-parameter lookup/read-only protection, M19 spindle-orient offset/timeout handling, magic-comment parameter formatting, selected Fanuc `M98/M99` call, loop, missing-P-word, missing-subprogram, mixed Fanuc/RS274NGC sub-style, `DISABLE_FANUC_STYLE_SUB`, main-program O-word termination, and O-expression regressions, external-subroutine-call, external-subroutine line-number, nested-subroutine-definition rejection, blocked forward-seek-to-later-numbered-sub, O-word stack unwind after a subroutine error, `(ABORT,...)` hot-comment parameter-expansion regressions, and INI-declared G92 parameter-file startup persistence remain LinuxCNC interpreter file-execution or initialization tests. The standalone boundary only vendors the original upstream assets, copies `*.ngc`, `test.ini`, `test.tbl`, `subs/*.ngc`, referenced external subroutine `.ngc` files, and staged variable files into native or WASM filesystems where applicable, sets the LinuxCNC `INI_FILE_NAME` runtime edge for `_ini[...]`, applies LinuxCNC INI machine settings such as `[RS274NGC]ORIENT_OFFSET`, loads upstream tool tables through LinuxCNC `tooldata_load()`/`Interp::load_tool_table()`, reads LinuxCNC INI `SUBROUTINE_PATH`, passes `[RS274NGC]PARAMETER_FILE` through vendored `ini_load()`/`Interp::init()`/`restore_parameters()` when the staged variable file exists, captures LinuxCNC `(PRINT,...)` output through the existing stdout/Emscripten `print` boundary, and calls vendored `Interp::open()`, `read()`, and `execute()`; it does not implement O-word loop, break, unwind, subroutine, dynamic call, `M98/M99`, `EXISTS[]`, named-parameter, canned-cycle, cutter-compensation, inverse-time feed, recursive O-word or cam toolpath generation, path-control, naive-cam tolerance, arc tolerance, threading, rigid tap, `G10`, G52/G92 offset behavior, G92 persistence, tool-offset, absolute-position named-parameter, G28/G53 endpoint, INI-variable, read-only parameter, line-number, spindle-speed, spindle-orient, magic-comment formatting, subroutine lookup, ABORT hot-comment, error, or branch semantics | Vendor byte sync, `linuxcnc_interp_minimal_harness`, `tests/wasm/node/verify_interp_wasm.sh`, `tests/browser/verify_interp_browser.sh` | diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_millturn_user_m_boundary_probe.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_millturn_user_m_boundary_probe.cpp new file mode 100644 index 0000000..d265f4a --- /dev/null +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_millturn_user_m_boundary_probe.cpp @@ -0,0 +1,215 @@ +#include +#include +#include +#include + +#include "emc/ini/inifile.hh" + +#ifndef LINUXCNC_SOURCE_CONFIG_DIR +#error "LINUXCNC_SOURCE_CONFIG_DIR must point at the LinuxCNC configs/sim tree" +#endif + +namespace { + +struct UserMCase { + const char *code; + const char *remap_code; + const char *script_rel; + const char *remap_rel; + const char *state_mode; + const char *guard_pin; + const char *switchkins_target; + const char *active_g5x; + const char *work_offset_pocket; + const char *work_offset_words; + const char *min_limit_key; + const char *max_limit_key; +}; + +std::string source_config_path(const std::string &rel) +{ + return std::string(LINUXCNC_SOURCE_CONFIG_DIR) + "/" + rel; +} + +std::string read_text(const std::string &path) +{ + std::ifstream input(path); + return std::string( + std::istreambuf_iterator(input), + std::istreambuf_iterator()); +} + +bool contains(const std::string &text, const std::string &needle) +{ + return text.find(needle) != std::string::npos; +} + +void print_bool(const std::string &name, bool value) +{ + std::cout << name << "=" << (value ? 1 : 0) << "\n"; +} + +bool check_ini_value( + const linuxcnc::IniFile &ini, + const std::string &label, + const std::string §ion, + const std::string &tag, + const std::string &expected) +{ + const auto actual = ini.findString(tag, section); + std::cout << label << "_" << section << "." << tag << "=" + << (actual ? *actual : "") << "\n"; + const bool ok = actual && *actual == expected; + print_bool(label + "_" + section + "." + tag + "_ok", ok); + return ok; +} + +bool check_axis_targets( + const linuxcnc::IniFile &ini, + const UserMCase &user_m, + const char *axis, + const char *expected_min, + const char *expected_max, + const char *expected_velocity, + const char *expected_acceleration) +{ + const std::string section = std::string("AXIS_") + axis; + const std::string label = std::string(user_m.code) + "_" + axis; + bool ok = true; + ok &= check_ini_value(ini, label, section, user_m.min_limit_key, expected_min); + ok &= check_ini_value(ini, label, section, user_m.max_limit_key, expected_max); + ok &= check_ini_value(ini, label, section, "MAX_VELOCITY", expected_velocity); + ok &= check_ini_value(ini, label, section, "MAX_ACCELERATION", expected_acceleration); + return ok; +} + +bool check_script(const UserMCase &user_m) +{ + const std::string text = read_text(source_config_path(user_m.script_rel)); + bool ok = true; + ok &= contains(text, "#!/usr/bin/tclsh"); + ok &= contains(text, "package require Linuxcnc"); + ok &= contains(text, "package require Hal"); + ok &= contains(text, "parse_ini $::env(INI_FILE_NAME)"); + ok &= contains(text, std::string("hal getp ") + user_m.guard_pin); + ok &= contains(text, "hal setp ini.$l.min_limit"); + ok &= contains(text, "hal setp ini.$l.max_limit"); + ok &= contains(text, "hal setp ini.$l.min_velocity"); + ok &= contains(text, "hal setp ini.$l.max_acceleration"); + ok &= contains(text, user_m.min_limit_key); + ok &= contains(text, user_m.max_limit_key); + print_bool(std::string(user_m.code) + "_script_tcl_hal_runtime", ok); + return ok; +} + +bool check_remap_caller(const UserMCase &user_m) +{ + const std::string text = read_text(source_config_path(user_m.remap_rel)); + const std::string remap_code(user_m.remap_code); + const bool ok = + contains(text, user_m.code) && + contains(text, "# = 3") && + contains(text, std::string("# = ") + user_m.switchkins_target) && + contains(text, "M68") && + contains(text, "M68 E# Q#") && + contains(text, "M66") && + contains(text, "M66 E0 L0") && + contains(text, std::string("G10 L2 ") + user_m.work_offset_pocket + " " + user_m.work_offset_words) && + contains(text, user_m.active_g5x) && + contains(text, "#<_hal[motion.switchkins-type]>") && + contains(text, std::string("[#<_hal[motion.switchkins-type]> NE ") + user_m.switchkins_target + "]"); + std::cout << remap_code << "_switchkins_output_pin=motion.analog-out-03\n"; + std::cout << remap_code << "_switchkins_target=" << user_m.switchkins_target << "\n"; + std::cout << remap_code << "_work_offset_pocket=" << user_m.work_offset_pocket << "\n"; + std::cout << remap_code << "_work_offset_words=" << user_m.work_offset_words << "\n"; + std::cout << remap_code << "_active_g5x=" << user_m.active_g5x << "\n"; + print_bool(remap_code + "_calls_" + user_m.code, contains(text, user_m.code)); + print_bool(remap_code + "_source_transition_from_linuxcnc", ok); + print_bool(std::string(user_m.code) + "_remap_calls_user_m_process", ok); + return ok; +} + +bool check_user_m_case(const linuxcnc::IniFile &ini, const UserMCase &user_m) +{ + bool ok = true; + ok &= check_script(user_m); + ok &= check_remap_caller(user_m); + if (std::string(user_m.code) == "M128") { + ok &= check_axis_targets(ini, user_m, "X", "-300", "300", "60.0", "400.0"); + ok &= check_axis_targets(ini, user_m, "Y", "-100", "100", "60.0", "400.0"); + ok &= check_axis_targets(ini, user_m, "Z", "-240", "0", "60.0", "400.0"); + } else { + ok &= check_axis_targets(ini, user_m, "X", "-240", "0", "60.0", "400.0"); + ok &= check_axis_targets(ini, user_m, "Y", "-100", "100", "60.0", "400.0"); + ok &= check_axis_targets(ini, user_m, "Z", "-300", "300", "60.0", "400.0"); + } + print_bool(std::string(user_m.code) + "_source_state_targets_from_linuxcnc", ok); + return ok; +} + +} // namespace + +int main() +{ + const std::string ini_path = source_config_path("axis/vismach/millturn/millturn.ini"); + linuxcnc::IniFile ini(ini_path); + const bool opened = static_cast(ini); + print_bool("millturn_ini_open", opened); + if (!opened) { + return 1; + } + + bool ok = true; + ok &= check_ini_value(ini, "millturn", "RS274NGC", "USER_M_PATH", "./mcodes"); + ok &= check_ini_value(ini, "millturn", "RS274NGC", "SUBROUTINE_PATH", "./remap_subs"); + ok &= check_ini_value(ini, "millturn", "DISPLAY", "PYVCP", "millturn.xml"); + ok &= check_ini_value(ini, "millturn", "HAL", "HALUI", "halui"); + ok &= check_ini_value( + ini, + "millturn", + "HAL", + "HALCMD", + "net :kinstype-select <= motion.analog-out-03 => motion.switchkins-type"); + + const UserMCase cases[] = { + { + "M128", + "M428", + "axis/vismach/millturn/mcodes/M128", + "axis/vismach/millturn/remap_subs/428remap.ngc", + "mill", + "kinstype.is-0", + "0", + "G59.1", + "P7", + "X-290 Y0 Z-160 A0", + "MIN_LIMIT", + "MAX_LIMIT", + }, + { + "M129", + "M429", + "axis/vismach/millturn/mcodes/M129", + "axis/vismach/millturn/remap_subs/429remap.ngc", + "turn", + "kinstype.is-1", + "1", + "G59.2", + "P8", + "X-160 Y0 Z-290 A0", + "MIN_LIMIT_TURN", + "MAX_LIMIT_TURN", + }, + }; + + for (const auto &user_m : cases) { + std::cout << user_m.code << "_state_mode=" << user_m.state_mode << "\n"; + std::cout << user_m.code << "_guard_pin=" << user_m.guard_pin << "\n"; + ok &= check_user_m_case(ini, user_m); + } + + print_bool("millturn_user_m_native_source_state_proof", ok); + print_bool("millturn_user_m_execution_enabled", false); + print_bool("millturn_user_m_promotion_allowed", false); + return ok ? 0 : 1; +} diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_python_remap_boundary_probe.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_python_remap_boundary_probe.cpp new file mode 100644 index 0000000..f4318c6 --- /dev/null +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_python_remap_boundary_probe.cpp @@ -0,0 +1,189 @@ +#include +#include +#include +#include + +#ifndef LINUXCNC_SOURCE_DIR +#error "LINUXCNC_SOURCE_DIR must point at the LinuxCNC source tree" +#endif + +#ifndef LINUXCNC_SOURCE_CONFIG_DIR +#error "LINUXCNC_SOURCE_CONFIG_DIR must point at the LinuxCNC configs/sim tree" +#endif + +namespace { + +std::string source_path(const std::string &rel) +{ + return std::string(LINUXCNC_SOURCE_DIR) + "/" + rel; +} + +std::string source_config_path(const std::string &rel) +{ + return std::string(LINUXCNC_SOURCE_CONFIG_DIR) + "/" + rel; +} + +std::string read_text(const std::string &path) +{ + std::ifstream input(path); + return std::string( + std::istreambuf_iterator(input), + std::istreambuf_iterator()); +} + +bool contains(const std::string &text, const std::string &needle) +{ + return text.find(needle) != std::string::npos; +} + +void print_bool(const std::string &name, bool value) +{ + std::cout << name << "=" << (value ? 1 : 0) << "\n"; +} + +bool check_python_runtime_owner() +{ + const std::string interp_python = read_text(source_path("src/emc/rs274ngc/interp_python.cc")); + const std::string python_plugin = read_text(source_path("src/emc/pythonplugin/python_plugin.cc")); + + const bool pycall_dispatch = + contains(interp_python, "PythonPlugin *python_plugin") && + contains(interp_python, "Interp::pycall") && + contains(interp_python, "python_plugin->call(module,funcname"); + const bool remap_phases = + contains(interp_python, "PY_PROLOG") && + contains(interp_python, "PY_BODY") && + contains(interp_python, "PY_EPILOG"); + const bool generator_finish = + contains(interp_python, "PyGen_Check(retval.ptr())") && + contains(interp_python, "PY_FINISH_PROLOG") && + contains(interp_python, "PY_FINISH_EPILOG"); + const bool callable_lookup = + contains(interp_python, "Interp::is_pycallable") && + contains(interp_python, "python_plugin->is_callable(module,funcname)"); + const bool execute_runtime = + contains(interp_python, "Interp::py_execute") && + contains(interp_python, "python_plugin->run_string(cmd, retval, as_file)"); + + const bool initializes_python = + contains(python_plugin, "PyConfig_InitPythonConfig(&config)") && + contains(python_plugin, "Py_InitializeFromConfig(&config)"); + const bool toplevel_exec = + contains(python_plugin, "findString(\"TOPLEVEL\", section)") && + contains(python_plugin, "bp::exec_file(abs_path, main_namespace, main_namespace)"); + const bool ini_python_path = + contains(python_plugin, "findString(n, \"PATH_PREPEND\", \"PYTHON\")") && + contains(python_plugin, "findString(n, \"PATH_APPEND\", \"PYTHON\")") && + contains(python_plugin, "PyRun_SimpleString(pycmd)"); + const bool callable_invoke = + contains(python_plugin, "PythonPlugin::call") && + contains(python_plugin, "PyObject_Call(function.ptr(), tupleargs.ptr(), kwargs.ptr())"); + const bool reload_on_change = + contains(python_plugin, "PythonPlugin::reload") && + contains(python_plugin, "reload_on_change"); + + print_bool("python_runtime_pycall_dispatch", pycall_dispatch); + print_bool("python_runtime_remap_phases", remap_phases); + print_bool("python_runtime_generator_finish", generator_finish); + print_bool("python_runtime_callable_lookup", callable_lookup); + print_bool("python_runtime_execute_runtime", execute_runtime); + print_bool("python_plugin_initializes_python", initializes_python); + print_bool("python_plugin_toplevel_exec_file", toplevel_exec); + print_bool("python_plugin_ini_python_path", ini_python_path); + print_bool("python_plugin_callable_invoke", callable_invoke); + print_bool("python_plugin_reload_on_change", reload_on_change); + + return pycall_dispatch && remap_phases && generator_finish && callable_lookup && + execute_runtime && initializes_python && toplevel_exec && ini_python_path && + callable_invoke && reload_on_change; +} + +bool check_axis_laser_family() +{ + const std::string ini = read_text(source_config_path("axis/laser/laser.ini")); + const std::string remap = read_text(source_config_path("axis/laser/python/remap.py")); + const bool ok = + contains(ini, "REMAP= M10 modalgroup=10 python=rasterStop") && + contains(ini, "REMAP= M11 modalgroup=10 python=rasterBegin") && + contains(ini, "REMAP= M12 modalgroup=10 python=rasterData") && + contains(ini, "REMAP= M13 modalgroup=10 python=rasterStart") && + contains(ini, "TOPLEVEL=python/toplevel.py") && + contains(ini, "PATH_APPEND=python") && + contains(remap, "def rasterBegin(self, **words):") && + contains(remap, "def rasterData(self, **words):") && + contains(remap, "def rasterStart(self, **words):") && + contains(remap, "def rasterStop(self, **words):"); + print_bool("python_family_axis_laser_inventory", ok); + return ok; +} + +bool check_twp_nutating_family() +{ + const std::string ini = read_text(source_config_path( + "axis/vismach/5axis/table-rotary_spindle-rotary-nutating/xyzacb-trsrn_twp/xyzacb-trsrn.ini")); + const std::string remap = read_text(source_config_path( + "axis/vismach/5axis/table-rotary_spindle-rotary-nutating/python/remap.py")); + const bool ok = + contains(ini, "REMAP = G68.2") && + contains(ini, "python=g682") && + contains(ini, "REMAP = G68.3") && + contains(ini, "python=g683") && + contains(ini, "REMAP = G68.4") && + contains(ini, "python=g684") && + contains(ini, "python=g53x_core") && + contains(ini, "python=g69_core") && + contains(ini, "PATH_APPEND = ../python") && + contains(ini, "TOPLEVEL = ../python/toplevel.py") && + contains(remap, "def g53x_core(self):") && + contains(remap, "def g69_core(self):") && + contains(remap, "def g682(self, **words):") && + contains(remap, "def g683(self, **words):") && + contains(remap, "def g684(self, **words):"); + print_bool("python_family_twp_nutating_inventory", ok); + return ok; +} + +bool check_cycle_and_stdglue_families() +{ + const std::string cycle_ini = read_text(source_config_path("axis/remap/cycle/cycle.ini")); + const std::string cycle_remap = read_text(source_config_path("axis/remap/cycle/python/remap.py")); + const std::string stdglue = read_text(source_config_path( + "axis/nc_files/remap_lib/python-stdglue/stdglue.py")); + const std::string gmoccapy_stdglue = read_text(source_config_path("gmoccapy/python/stdglue.py")); + + const bool cycle_ok = + contains(cycle_ini, "python=g842") && + contains(cycle_ini, "prolog=cycle_prolog") && + contains(cycle_ini, "epilog=cycle_epilog") && + contains(cycle_ini, "PATH_PREPEND=./python") && + contains(cycle_ini, "PATH_APPEND=../../nc_files/remap_lib/python-stdglue") && + contains(cycle_remap, "def g842(self,**words):") && + contains(stdglue, "def cycle_prolog(self,**words):") && + contains(stdglue, "def cycle_epilog(self,**words):"); + + const bool gmoccapy_ok = + contains(gmoccapy_stdglue, "def settool_prolog(self,**words):") && + contains(gmoccapy_stdglue, "def settool_epilog(self,**words):") && + contains(gmoccapy_stdglue, "def change_prolog(self, **words):") && + contains(gmoccapy_stdglue, "def change_epilog(self, **words):"); + + print_bool("python_family_axis_remap_cycle_inventory", cycle_ok); + print_bool("python_family_gmoccapy_stdglue_inventory", gmoccapy_ok); + return cycle_ok && gmoccapy_ok; +} + +} // namespace + +int main() +{ + bool ok = true; + ok &= check_python_runtime_owner(); + ok &= check_axis_laser_family(); + ok &= check_twp_nutating_family(); + ok &= check_cycle_and_stdglue_families(); + + print_bool("python_remap_native_source_inventory_proof", ok); + print_bool("python_remap_execution_enabled", false); + print_bool("python_remap_promotion_allowed", false); + return ok ? 0 : 1; +} diff --git a/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_tool_db_boundary_probe.cpp b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_tool_db_boundary_probe.cpp new file mode 100644 index 0000000..6a761b5 --- /dev/null +++ b/wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_tool_db_boundary_probe.cpp @@ -0,0 +1,177 @@ +#include +#include +#include +#include + +#include "emc/ini/inifile.hh" + +#ifndef LINUXCNC_SOURCE_DIR +#error "LINUXCNC_SOURCE_DIR must point at the LinuxCNC source tree" +#endif + +#ifndef LINUXCNC_SOURCE_CONFIG_DIR +#error "LINUXCNC_SOURCE_CONFIG_DIR must point at the LinuxCNC configs/sim tree" +#endif + +namespace { + +std::string source_path(const std::string &rel) +{ + return std::string(LINUXCNC_SOURCE_DIR) + "/" + rel; +} + +std::string source_config_path(const std::string &rel) +{ + return std::string(LINUXCNC_SOURCE_CONFIG_DIR) + "/" + rel; +} + +std::string read_text(const std::string &path) +{ + std::ifstream input(path); + return std::string( + std::istreambuf_iterator(input), + std::istreambuf_iterator()); +} + +bool contains(const std::string &text, const std::string &needle) +{ + return text.find(needle) != std::string::npos; +} + +void print_bool(const std::string &name, bool value) +{ + std::cout << name << "=" << (value ? 1 : 0) << "\n"; +} + +bool check_ini_value( + const linuxcnc::IniFile &ini, + const std::string &label, + const std::string §ion, + const std::string &tag, + const std::string &expected) +{ + const auto actual = ini.findString(tag, section); + std::cout << label << "_" << section << "." << tag << "=" + << (actual ? *actual : "") << "\n"; + const bool ok = actual && *actual == expected; + print_bool(label + "_" + section + "." + tag + "_ok", ok); + return ok; +} + +bool check_task_owner() +{ + const std::string text = read_text(source_path("src/emc/task/taskclass.cc")); + const bool db_init = + contains(text, "findString(\"DB_PROGRAM\", \"EMCIO\")") && + contains(text, "tooldata_set_db(db_mode)") && + contains(text, "tooldata_db_init(db_program, random_toolchanger)"); + const bool tbl_ignored = contains(text, "DB_PROGRAM active: IGNORING tool table file"); + const bool load_unload_notify = + contains(text, "tooldata_db_notify(SPINDLE_UNLOAD") && + contains(text, "tooldata_db_notify(SPINDLE_LOAD"); + + print_bool("tool_db_task_db_mode_init", db_init); + print_bool("tool_db_task_ignores_tool_table_with_db_program", tbl_ignored); + print_bool("tool_db_task_load_unload_notify", load_unload_notify); + return db_init && tbl_ignored && load_unload_notify; +} + +bool check_tooldata_db_owner() +{ + const std::string text = read_text(source_path("src/emc/tooldata/tooldata_db.cc")); + const bool child_process = + contains(text, "pipe2(pipes[PARENT_READ_PIPE]") && + contains(text, "pipe2(pipes[PARENT_WRITE_PIPE]") && + contains(text, "fork()") && + contains(text, "execv(myargv[0], myargv)"); + const bool executable_check = + contains(text, "access(child_argv[0],X_OK)") && + contains(text, "not executable"); + const bool version_handshake = + contains(text, "#define DB_VERSION \"v2.1\"") && + contains(text, "read_reply(reply,sizeof(reply))") && + contains(text, "strncmp(reply,DB_VERSION"); + const bool getall = + contains(text, "send_request((char*)\"g\\n\")") && + contains(text, "tooldata_reset()") && + contains(text, "strstr(reply,\"FINI\")") && + contains(text, "tooldata_read_entry(reply)"); + const bool notify = + contains(text, "snprintf(msg,sizeof(msg),\"l %s\\n\",buffer)") && + contains(text, "snprintf(msg,sizeof(msg),\"u %s\\n\",buffer)") && + contains(text, "snprintf(msg,sizeof(msg),\"p %s\\n\",buffer)") && + contains(text, "send_and_verify(msg)"); + + print_bool("tool_db_child_process_boundary", child_process); + print_bool("tool_db_program_executable_check", executable_check); + print_bool("tool_db_v2_1_handshake", version_handshake); + print_bool("tool_db_getall_g_until_fini", getall); + print_bool("tool_db_notify_l_u_p_protocol", notify); + return child_process && executable_check && version_handshake && getall && notify; +} + +bool check_db_program_owner() +{ + const std::string text = read_text(source_config_path("axis/db_demo/db.py")); + const bool imports = + contains(text, "from tooldb import tooldb_callbacks") && + contains(text, "from tooldb import tooldb_tools") && + contains(text, "from tooldb import tooldb_loop"); + const bool callbacks = + contains(text, "def user_get_tool(tno):") && + contains(text, "def user_put_tool(tno,params):") && + contains(text, "def user_load_spindle_nonran_tc(tno,params):") && + contains(text, "def user_unload_spindle_nonran_tc(tno,params):") && + contains(text, "tooldb_callbacks(user_get_tool") && + contains(text, "tooldb_tools(toollist)") && + contains(text, "tooldb_loop()"); + const bool state_targets = + contains(text, "db_nonran_savefile = \"/tmp/db_nonran_file\"") && + contains(text, "toolno_min = 10") && + contains(text, "toolno_max = 19") && + contains(text, "pocket_offset = 100") && + contains(text, "return tno+pocket_offset") && + contains(text, "D['P'] = \"0\"") && + contains(text, "nonran_restore_pocket(spindle_tool)") && + contains(text, "linuxcnc.command().load_tool_table") && + contains(text, "save_tools_to_file(db_savefile"); + const bool reload_rules = + contains(text, "apply_db_rules()") && + contains(text, "G10L0"); + + print_bool("tool_db_program_tooldb_module", imports); + print_bool("tool_db_program_nonran_callbacks", callbacks); + print_bool("tool_db_program_nonran_state_targets", state_targets); + print_bool("tool_db_program_reload_rules", reload_rules); + return imports && callbacks && state_targets && reload_rules; +} + +} // namespace + +int main() +{ + const std::string ini_path = source_config_path("axis/db_demo/db_nonran.ini"); + const std::string ini_text = read_text(ini_path); + linuxcnc::IniFile ini(ini_path); + const bool opened = static_cast(ini); + print_bool("db_nonran_ini_open", opened); + if (!opened) { + return 1; + } + + bool ok = true; + ok &= check_ini_value(ini, "db_nonran", "EMCIO", "RANDOM_TOOLCHANGER", "0"); + ok &= check_ini_value(ini, "db_nonran", "EMCIO", "DB_PROGRAM", "./db_nonran.py"); + const bool tool_table_ignored = contains(ini_text, "TOOL_TABLE= is not used with DB_PROGRAM"); + print_bool("db_nonran_tool_table_ignored_with_db_program", tool_table_ignored); + ok &= tool_table_ignored; + + ok &= check_task_owner(); + ok &= check_tooldata_db_owner(); + ok &= check_db_program_owner(); + + print_bool("tool_db_native_source_protocol_proof", ok); + print_bool("tool_db_execution_enabled", false); + print_bool("tool_db_promotion_allowed", false); + return ok ? 0 : 1; +} diff --git a/wasm-port/runtime/sdk/README.md b/wasm-port/runtime/sdk/README.md index e014d57..a949551 100644 --- a/wasm-port/runtime/sdk/README.md +++ b/wasm-port/runtime/sdk/README.md @@ -23,6 +23,7 @@ Use `src/index.js` for stable imports: ```js import { + analyzeIniRuntimeBoundaries, createLinuxCncIniSdk, createLinuxCncInterpSdk, planIniFileContextStaging, @@ -104,6 +105,20 @@ source manifest text, machine relative path, INI file name, and INI text. It uses `planIniFileContextStaging()` with a `configs/sim/` source root and `configs/sim` upward-search boundary. +`analyzeIniRuntimeBoundaries()` is a host-boundary classifier for LinuxCNC +INI-driven runs. It reads INI text plus optional execution text and manifest +text, then reports declared HAL, UI, HALUI MDI, Python, tool-database, and +external user-M process dependencies. User-M accounting is per execution code: +`executionCodes` lists `M100..M199` codes seen in the supplied execution text, +while `unstagedExecutionCodes` lists the subset not backed by vendored +`USER_M_PATH` files. Python accounting keeps UI/DB references separate from +Python remap runtime references, so a UI handler or DB program does not imply +Python-remap coverage. It also returns the currently recommended Layer 4 +blocked kind for hard process boundaries such as `L4-TOOL-DB` and +`L4-USER-M-PROCESS`. The classifier is policy/accounting only: it does not +execute HAL, task, UI, Python, user-M, or tool-database behavior and does not +change interpreter semantics. + `runFileWithIniContinueOnError()` uses the same LinuxCNC-backed file execution path but keeps the runner loop going after LinuxCNC reports an error, matching upstream `rs274 -n 0` regression tests such as `tests/interp/oword-unwind`. diff --git a/wasm-port/runtime/sdk/src/index.js b/wasm-port/runtime/sdk/src/index.js index 49dbfc8..1d16764 100644 --- a/wasm-port/runtime/sdk/src/index.js +++ b/wasm-port/runtime/sdk/src/index.js @@ -1,6 +1,7 @@ export { createLinuxCncIniSdk } from "./linuxcnc-ini.js"; export { createLinuxCncInterpSdk } from "./linuxcnc-interp.js"; export { + analyzeIniRuntimeBoundaries, planIniFileContextStaging, planSimConfigStaging, } from "./sim-config-staging.js"; diff --git a/wasm-port/runtime/sdk/src/sim-config-staging.js b/wasm-port/runtime/sdk/src/sim-config-staging.js index 0944af8..b5a05c6 100644 --- a/wasm-port/runtime/sdk/src/sim-config-staging.js +++ b/wasm-port/runtime/sdk/src/sim-config-staging.js @@ -172,6 +172,197 @@ function remapNgcNames(iniValues) { return names; } +function sectionValues(iniValues, section) { + const prefix = `${section.toUpperCase()}.`; + const values = []; + for (const [key, entries] of iniValues.entries()) { + if (!key.startsWith(prefix)) { + continue; + } + for (const value of entries) { + values.push({ key: key.slice(prefix.length), value }); + } + } + return values; +} + +function valuesMatching(iniValues, section, keys) { + const wanted = new Set(keys.map((key) => key.toUpperCase())); + return sectionValues(iniValues, section) + .filter((entry) => wanted.has(entry.key)) + .map((entry) => entry.value); +} + +function looksLikePythonReference(value) { + return /(^|\s|=|:)["']?[^"'\s]*\.py(["'\s]|$)/i.test(value); +} + +function userMCodesInText(text) { + const codes = new Set(); + for (const match of text.matchAll(/(? entry.value), + ...remapValues.filter((value) => /(?:^|\s)python=/i.test(value)), + ]; + const pythonUiReferences = [ + ...displayValues.filter(looksLikePythonReference), + ...(dbProgram && looksLikePythonReference(dbProgram) ? [dbProgram] : []), + ]; + const pythonReferences = [...pythonRemapReferences, ...pythonUiReferences]; + const vendoredUserMCodeList = vendoredUserMCodes({ + manifestEntries, + sourceDir, + normalizedSearchRoot, + userMPathValues, + }); + const vendoredUserMCodeSet = new Set(vendoredUserMCodeList); + const hasUserMPath = userMPathValues.length > 0; + const executionUserMCodes = [...new Set(executionTexts.flatMap(userMCodesInText))].sort(); + const unstagedExecutionUserMCodes = executionUserMCodes + .filter((code) => !vendoredUserMCodeSet.has(code)); + const hasExternalUserMUse = hasUserMPath && unstagedExecutionUserMCodes.length > 0; + + const dependencies = []; + if (dbProgram) { + dependencies.push("tool_database_process"); + } + if (halValues.length > 0) { + dependencies.push("hal_process"); + } + if (displayValues.some((value) => !/^axis$/i.test(value))) { + dependencies.push("ui_process"); + } + if (halUiMdiCommands.length > 0) { + dependencies.push("halui_mdi_process"); + } + if (pythonReferences.length > 0) { + dependencies.push("python_runtime"); + } + if (hasExternalUserMUse) { + dependencies.push("external_user_m_process"); + } + + let recommendedBlockedKind = "-"; + if (dbProgram) { + recommendedBlockedKind = "L4-TOOL-DB"; + } else if (hasExternalUserMUse) { + recommendedBlockedKind = "L4-USER-M-PROCESS"; + } else if (pythonRemapReferences.length > 0) { + recommendedBlockedKind = "L4-PYTHON-REMAP"; + } + + return { + dependencies: [...new Set(dependencies)].sort(), + recommendedBlockedKind, + toolDatabaseProgram: dbProgram ?? "", + halRuntime: { + values: halValues, + requiresProcess: halValues.length > 0, + }, + uiRuntime: { + values: displayValues, + requiresProcess: displayValues.some((value) => !/^axis$/i.test(value)), + }, + haluiRuntime: { + mdiCommands: halUiMdiCommands, + requiresProcess: halUiMdiCommands.length > 0, + }, + userMRuntime: { + paths: userMPathValues, + vendoredExecutableCount: vendoredUserMCodeList.length, + executionCodes: executionUserMCodes, + unstagedExecutionCodes: unstagedExecutionUserMCodes, + requiresExternalProcess: hasExternalUserMUse, + }, + pythonRuntime: { + references: pythonReferences, + remapReferences: pythonRemapReferences, + uiReferences: pythonUiReferences, + requiresProcess: pythonReferences.length > 0, + }, + }; +} + export function planSimConfigStaging({ manifestText, machineRel, diff --git a/wasm-port/tests/browser/interp_smoke.html b/wasm-port/tests/browser/interp_smoke.html index 29505ec..a03c020 100644 --- a/wasm-port/tests/browser/interp_smoke.html +++ b/wasm-port/tests/browser/interp_smoke.html @@ -8,6 +8,7 @@
running