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。
