text41.txt

一、接续说明

执行时间：2026-06-21 CST

本文件接续 `textbak/text40.txt` 的“九、后续建议”：

```text
无需继续扩展 kinematics module 列表。
下一步不应再手写或补造 JS kinematics 数学。
后续重点应转向把 Web/M4/M5 simulation UI 从 fixture/frame 逻辑接入 createLinuxCncKinematicsSdk() 输出，或继续推进 remap/planner/browser 集成验证。
```

本文件只规划下一阶段详细执行步骤，不新增 JS-owned kinematics 数学，不继续扩大
LinuxCNC kinematics module 列表。

二、当前事实基线

已完成事实：

```text
1. `wasm-port` 已有 17 个独立 kinematics WASM module。
2. `createLinuxCncKinematicsSdk()` 已能加载这些 module 并调用 `lckins_*` C ABI。
3. `tests/wasm/node/verify_kinematics_wasm.sh` 已验证所有 module 的 forward/inverse 或 inverse/forward roundtrip。
4. `textbak/text40.txt` 已记录可加载 LinuxCNC kinematics module 全量 ABI 完成。
```

Web/M4/M5 当前状态：

```text
1. `web-rtcp-5axis-sim-plan/app/src/runtime/rtcp-frame.js`
   仍由 fixture pose + JS 计算 toolAxisVector/compensation/tcpPose。

2. `web-rtcp-5axis-sim-plan/app/src/state/store.js`
   RUN/STEP/JOG/HOME 仍推进 fixture axis pose，frame sourceMode 仍是 `fixture-ui-only`。

3. `web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-boundary-adapter.js`
   已有 adapter entrypoint，但 `linuxCncKinematicsReady=false`，没有加载 kinematics WASM。

4. `web-rtcp-5axis-sim-plan/tests/node/verify_rtcp_store.mjs`
   明确断言 `linuxCncKinematicsReady=false`，并把 fixture frame 作为当前 smoke 目标。
```

因此下一阶段的目标不是“再实现 kinematics”，而是：

```text
把 Web/M4/M5 的 frame 来源从 fixture-ui-only 升级为 LinuxCNC kinematics WASM 输出；
保留 fixture frame 作为 fallback 和 UI smoke，不把 fallback 冒充 LinuxCNC runtime proof。
```

三、总目标

阶段总目标：

```text
Web/M4/M5 simulation UI 能通过 createLinuxCncKinematicsSdk() 加载 LinuxCNC kinematics WASM，
使用 LinuxCNC-owned forward/inverse 结果生成 RTCP/motion frame，
并在 UI/store/browser smoke 中明确标记 sourceMode=source-derived-kinematics-wasm。
```

完成后应满足：

```text
1. fixture frame 仍可运行，但 sourceMode 只能是 `fixture-ui-only`。
2. LinuxCNC kinematics frame 由 WASM C ABI 输出，不由 JS 复写数学。
3. M4 profile/boundary adapter 能报告 kinematics runtime ready。
4. M5 operator workflow 的 RUN/STEP/JOG/HOME 能消费同一 frame contract。
5. Node smoke 和 browser smoke 都能区分 fixture fallback 与 LinuxCNC kinematics proof。
```

四、实施阶段规划

## Phase A：固化 kinematics runtime adapter 边界

目标：

```text
在 Web app 侧新增一个窄 adapter，只负责加载 wasm-port kinematics SDK 并返回 frame 输入。
```

建议新增文件：

```text
web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-kinematics-runtime.js
```

职责：

```text
1. 接收 moduleId，例如 `xyzac-trt`。
2. 调用 `createLinuxCncKinematicsSdk({ moduleId, moduleOptions })`。
3. 暴露 `forward(joints, options)` / `inverse(pose, jointCount, options)`。
4. 暴露 runtime readiness：
   - apiName
   - moduleId
   - wasmFile
   - supportedModules
   - loaded
   - sourceMode=`source-derived-kinematics-wasm`
5. 不计算任何 kinematics 数学。
```

关键约束：

```text
1. 不能把 wasm-port SDK 源码复制到 web app。
2. 能 import 共享 SDK 时优先 import `wasm-port/runtime/sdk/src/index.js`。
3. 如果 browser bundling/static-copy 暂时不能直接加载 wasm-port build output，
   允许先做 Node-side adapter smoke，再规划 browser asset copy。
4. 不允许在 JS 中重新写 xyzac/xyzbc/trt compensation 公式。
```

验收：

```text
新增 Node smoke：加载 `xyzac-trt` kinematics WASM，调用 forward -> inverse，
确认 moduleId、wasmFile、sourceMode、rc=0。
```

建议测试文件：

```text
web-rtcp-5axis-sim-plan/tests/node/verify_linuxcnc_kinematics_runtime.mjs
```

## Phase B：把 RTCP frame builder 改为双来源

目标：

```text
`buildRtcpFrame()` 保留 fixture fallback，但新增 LinuxCNC kinematics frame 输入路径。
```

建议修改文件：

```text
web-rtcp-5axis-sim-plan/app/src/runtime/rtcp-frame.js
```

新增或调整 API：

```text
buildRtcpFrame({
  axisPose,
  activeLine,
  kinsType,
  rtcpEnabled,
  sourceMode,
  profile,
  linuxCncKinematicsResult,
})
```

LinuxCNC frame 输入建议字段：

```text
linuxCncKinematicsResult = {
  moduleId: "xyzac-trt",
  switchkinsType: 0 | 1 | 2,
  forward: {
    rc,
    pose,
    fflags,
    iflags,
  },
  inverse: {
    rc,
    joints,
    fflags,
    iflags,
  },
}
```

frame 输出必须新增/修正：

```text
sourceMode: "source-derived-kinematics-wasm"
semanticBoundary: "linuxcnc_kinematics_wasm_c_abi"
readiness.linuxCncKinematicsReady: true
readiness.promotionAllowed: true only for kinematics-frame proof, not interpreter/remap proof
kinematicsModuleId
kinematicsForwardRc
kinematicsInverseRc
kinematicsFlags
```

注意：

```text
1. `tcpPose` / `jointPose` 应来自 LinuxCNC forward/inverse 输出映射。
2. 若只拿到 one-way forward 结果，就不要声称 full program execution proof。
3. fixture fallback 的 semanticBoundary 必须保持 `fixture_frame_ui_plumbing_not_linuxcnc_kinematics_proof`。
```

验收：

```text
1. fixture frame smoke 仍通过。
2. 新增 LinuxCNC kinematics frame smoke：
   - sourceMode=source-derived-kinematics-wasm
   - readiness.linuxCncKinematicsReady=true
   - semanticBoundary=linuxcnc_kinematics_wasm_c_abi
   - jointPose 来自 inverse.joints
   - tcp/work pose 来自 WASM pose output
```

## Phase C：接入 boundary adapter readiness

目标：

```text
让 `createLinuxCncBoundaryAdapter()` 接收 kinematics runtime，
并把 adapter/readiness 从 entrypoint-only 升级到 kinematics-runtime-ready。
```

建议修改文件：

```text
web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-boundary-adapter.js
```

runtime 输入建议：

```text
runtime = {
  kinematicsWasm: {
    apiName,
    moduleId,
    wasmFile,
    loaded,
    sourceMode,
  },
  interpreterWasm: null,
}
```

readiness 语义：

```text
linuxCncKinematicsReady=true
promotionAllowed=true 仅代表 kinematics frame source 已接入；
如果 interpreter/remap 仍未接入，不得声明 full LinuxCNC program execution ready。
```

semanticBoundary 建议值：

```text
adapter_entrypoint_only_runtime_not_connected
linuxcnc_kinematics_wasm_runtime_connected
linuxcnc_runtime_supplied_but_interpreter_or_remap_not_promoted
```

验收：

```text
Node smoke 检查 adapter：
1. runtimeReady 可区分 kinematics-only 与 interpreter+kinematics。
2. linuxCncKinematicsReady=true。
3. missing 不再包含 kinematics runtime，但如果 interpreter 缺失，应保留 interpreter/remap 未完成提示。
```

## Phase D：Store 增加异步 kinematics runtime 初始化

目标：

```text
让 `createSimulationStore()` 可以在初始化或 action 中接入 kinematics runtime，
并在 RUN/STEP/JOG/HOME/SET_RTCP 后用 LinuxCNC kinematics frame 更新 DRO/preview。
```

建议修改文件：

```text
web-rtcp-5axis-sim-plan/app/src/state/store.js
```

建议新增 action：

```text
ATTACH_KINEMATICS_RUNTIME
SET_FRAME_SOURCE
REFRESH_KINEMATICS_FRAME
```

状态字段建议：

```text
kinematicsRuntime: null | runtimeAdapter
kinematicsRuntimeReadiness
frameSourceMode: "fixture-ui-only" | "source-derived-kinematics-wasm"
lastKinematicsResult
```

RUN/STEP/JOG/HOME 行为：

```text
1. 若 frameSourceMode=fixture-ui-only：
   保持当前 fixture line playback。

2. 若 frameSourceMode=source-derived-kinematics-wasm 且 runtime loaded：
   使用当前 axisPose/joints 调用 kinematics SDK；
   生成 linuxCncKinematicsResult；
   调用 buildRtcpFrame(..., linuxCncKinematicsResult)；
   更新 DRO、jointPose、tcpPose、toolAxisVector、rtcpFrame。

3. 若 runtime missing：
   fallback 到 fixture frame；
   operatorMessage 必须说明 kinematics runtime missing；
   readiness.linuxCncKinematicsReady=false。
```

验收：

```text
1. 现有 `verify_rtcp_store.mjs` fixture 断言继续通过。
2. 新增 kinematics runtime store smoke：
   - attach runtime 后 linuxCncBoundaryReadiness.linuxCncKinematicsReady=true
   - SET_RTCP/RUN/STEP 后 sourceMode=source-derived-kinematics-wasm
   - activeLine 更新仍符合 M5 operator workflow
   - dro 与 rtcpFrame 来自同一 LinuxCNC kinematics frame
```

## Phase E：Browser asset / worker 接入

目标：

```text
让真实 browser smoke 能加载 kinematics WASM 产物。
```

需要决定的 asset 策略：

```text
方案 1：build-static 阶段复制 `wasm-port/build/wasm/kinematics/*` 到 web app dist。
方案 2：通过相对路径直接引用 wasm-port build output。
方案 3：新增 worker，隔离 Emscripten module 加载和 runtime calls。
```

推荐顺序：

```text
1. Node adapter smoke 先完成。
2. build-static copy 最小化接入 browser。
3. 若主线程加载 Emscripten module 造成 UI 阻塞，再迁移 worker。
```

建议修改文件：

```text
web-rtcp-5axis-sim-plan/app/scripts/build-static.mjs
web-rtcp-5axis-sim-plan/app/src/main.js
web-rtcp-5axis-sim-plan/tests/browser/verify_gmoccapy_shell_browser.sh
```

验收：

```text
1. `npm --prefix web-rtcp-5axis-sim-plan/app run build`
2. `npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node`
3. `npm --prefix web-rtcp-5axis-sim-plan/app run smoke`
4. Browser DOM 能看到 sourceMode=source-derived-kinematics-wasm 或明确的 kinematics-ready badge。
```

## Phase F：文档与追溯矩阵更新

目标：

```text
把 traceability 从 planned/fixture-only 更新为 source-derived kinematics WASM。
```

建议修改文件：

```text
web-rtcp-5axis-sim-plan/docs/program-implementation-guide.md
web-rtcp-5axis-sim-plan/docs/traceability-matrix.md
web-rtcp-5axis-sim-plan/docs/implementation-plan.md
web-rtcp-5axis-sim-plan/docs/technical-roadmap.md
```

必须更新的旧文本：

```text
linuxCncKinematicsReady=false
fixture_frame_ui_plumbing_not_linuxcnc_kinematics_proof
Adapter 目前只是接入点
尚未连接 LinuxCNC interpreter/kinematics WASM ABI
```

替换原则：

```text
1. kinematics frame source 可以标记为 LinuxCNC WASM proof。
2. program execution 如果仍是 fixture line playback，必须继续标记为 fixture/interpreter-not-connected。
3. remap/planner/browser full-process 不得因 kinematics 接入而自动 promotion。
```

五、建议执行顺序

建议下一轮按下面顺序实施：

```text
1. 新增 `linuxcnc-kinematics-runtime.js`，只做 SDK loader/adapter。
2. 新增 Node smoke 验证 web app 可加载 `xyzac-trt` kinematics SDK。
3. 修改 `rtcp-frame.js` 支持 linuxCncKinematicsResult 输入。
4. 扩展 `verify_rtcp_store.mjs`，保留 fixture 断言并新增 kinematics frame 断言。
5. 修改 `linuxcnc-boundary-adapter.js` readiness。
6. 修改 `store.js` 支持 attach runtime 和 kinematics source mode。
7. 完成 browser asset copy/loading。
8. 更新 docs/traceability。
9. 最后统一运行 build、node smoke、browser smoke。
```

六、验收总门槛

完成本阶段必须全部通过：

```bash
source /home/cnc/emsdk/emsdk_env.sh >/dev/null && bash wasm-port/tests/wasm/node/verify_kinematics_wasm.sh
npm --prefix web-rtcp-5axis-sim-plan/app run build
npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node
npm --prefix web-rtcp-5axis-sim-plan/app run smoke
```

新增 smoke 应输出类似：

```text
linuxcnc_kinematics_runtime_smoke=ok
rtcp_store_smoke=ok
```

七、禁止事项

下一阶段明确禁止：

```text
1. 禁止继续新增 JS 版本 xyzac/xyzbc/RTCP 逆解公式。
2. 禁止把 fixture frame 标记为 LinuxCNC proof。
3. 禁止把 kinematics-ready 等同于 interpreter/remap/full-process-ready。
4. 禁止把 browser virtual HAL 声称为 Linux kernel realtime ABI。
5. 禁止为了 UI 方便复制 LinuxCNC kinematics 数学到 web app。
```

八、完成后应写入的下一份接续文件内容

如果下一轮实际实施，应在新接续文件中记录：

```text
1. 哪些 web app 文件已从 fixture-only 改为 kinematics WASM source。
2. 具体 sourceMode/semanticBoundary 字段变化。
3. Node/browser smoke 输出。
4. 哪些内容仍是 fixture line playback。
5. 是否已经接入 browser asset copy 或 worker。
6. 下一步是否转向 interpreter/remap/planner/browser full execution。
```
