# Native Task 与实时 HAL 同步实现步骤

生成时间：2026-06-21 CST

## 1. 目标和边界

本文用于指导后续把当前保留的两个 blocker 推进到可验证完成状态：

```text
nativeTaskReady=false
nativeHalSyncReady=false
```

这里的“完成”不是把浏览器变成真实机床控制器，也不是接入真实硬件 IO；目标是建立一个 LinuxCNC 源码拥有语义的 task/HAL 同步 runtime 边界，使 Web 仿真能按 LinuxCNC task、motion、HAL 的顺序运行程序、执行 MDI/JOG、同步 HAL pin，并把状态反馈到 gmoccapy Web UI。

完成后的目标状态：

```text
nativeTaskReady=true
nativeHalSyncReady=true
plannerRuntimeReady=true
fullLinuxCncProgramExecutionReady=true for simulated machine-file runtime
hardwareDrive=false
promotionAllowed=true for Web simulation boundary only
```

仍不属于本文范围：

- 真实硬件 IO、Mesa/并口/伺服驱动；
- Linux 内核实时线程等同物；
- 任意外部 user-M 进程；
- Python GUI、GTK、Tk、QtVCP runtime；
- 未经过 LinuxCNC 源码边界验证的 JavaScript CNC 语义。

## 2. LinuxCNC 源程序参考清单

后续实现必须以这些源文件为主参考，不能用 Web 侧自定义状态机替代 CNC 语义：

```text
linuxcnc/src/emc/task/task.hh
linuxcnc/src/emc/task/emctask.cc
linuxcnc/src/emc/task/emctaskmain.cc
linuxcnc/src/emc/task/taskintf.cc
linuxcnc/src/emc/task/emccanon.cc
linuxcnc/src/emc/nml_intf/emc.hh
linuxcnc/src/emc/motion/usrmotintf.h
linuxcnc/src/emc/motion/motion.h
linuxcnc/src/emc/motion/motion.c
linuxcnc/src/emc/motion/command.c
linuxcnc/src/emc/motion/control.c
linuxcnc/src/emc/motion/mot_priv.h
linuxcnc/src/emc/tp/tp.c
linuxcnc/src/emc/tp/tc.c
linuxcnc/src/emc/tp/tcq.c
linuxcnc/src/hal/hal_lib.c
linuxcnc/src/hal/hal_priv.h
linuxcnc/src/hal/components/threads.c
```

当前 `wasm-port/vendor/linuxcnc` 已包含 interpreter、kinematics、TP 所需的一部分源码，但 task 和 HAL 目录是裁剪状态。实施前必须先把上述 task、motion、HAL、NML 相关源文件纳入 vendored source manifest，或者建立只读引用校验，确保构建用的源码和根目录 `linuxcnc/` 中的参考源码一致。

## 3. 推荐架构

推荐实现为单进程确定性 runtime：

```text
Web UI
  -> linuxcnc-task-hal-worker-client.js
  -> Web Worker
  -> linuxcnc_task_hal.wasm
  -> LinuxCNC task loop
  -> LinuxCNC canonical queue
  -> LinuxCNC motion command queue
  -> deterministic HAL scheduler
  -> LinuxCNC motion controller servo cycles
  -> status snapshot
  -> Web store / Three.js / DRO / G-code panel
```

这个结构不启动 LinuxCNC native 进程、不使用 OS NML IPC、不启动真实 HAL realtime thread。它把 LinuxCNC 的 task/motion/HAL 关键状态机编译到 WASM，并用显式 `step(period_ns)` API 驱动周期。这样浏览器中每一帧都是可复现的，Node 和 browser smoke 可以对同一 G-code 得到一致的 HAL/status 序列。

host-native LinuxCNC 只作为对照探针：

```text
native LinuxCNC/halrun probe
  -> 记录 task status、HAL pin、motion status 序列
WASM task/HAL runtime
  -> 记录同类序列
对比 artifact
  -> 允许提升 nativeTaskReady/nativeHalSyncReady
```

## 4. textbak 接续文件可复用结论

已分析 `textbak` 中和 native task / HAL 相关的接续文件，结论是：当前仓库已有大量 Web 仿真级 virtual HAL、motion matrix、native opt-in probe 和 promotion lock 资产，后续实现 native task/HAL 边界时必须复用这些成果，但不能把它们直接当成 native task/HAL runtime 已完成。

### 4.1 可直接复用的工作

`textbak/text17.txt` 记录了完整 virtual HAL 闭环，当前对应代码主要在：

```text
wasm-port/runtime/sdk/src/linuxcnc-hal.js
wasm-port/runtime/opfs/snapshot-store.js
wasm-port/runtime/ui/simulation/simulation-app.js
wasm-port/tests/host/verify_project_release_readiness_artifact.mjs
```

可复用内容：

- HAL pin family registry：`axisui`、`halui`、`iocontrol`、`motion`、`axis`、`joint`、`spindle`、`coolant`、`tool`；
- HAL pin/signal/param/net store 结构；
- `executeVirtualHalcmd()` / `executeVirtualHalCommand()` 的 halcmd fixture 语义；
- `stepVirtualHalMotion()` / `stepVirtualHalMotionController()` 的 deterministic servo-period stepping 测试模式；
- `createVirtualHalMotionControllerMatrixReport()` 的 motion matrix 验证项；
- OPFS snapshot 中的 `createVirtualHalSessionPayload()`、`restoreVirtualHalStateFromSessionSnapshot()`；
- source compliance、sim-config source coverage、release diagnostics artifact 结构。

这些内容应作为阶段 2、阶段 3、阶段 7 的输入，避免重新设计 HAL registry、snapshot、diagnostics 和 motion matrix。

### 4.2 只能作为 evidence，不能直接提升的工作

`textbak/text17.txt` 和 `textbak/text19.txt` 明确：virtual HAL 在 Web 仿真范围内可以替代 host `halcmd`、host realtime HAL process 和 host motion process，但不能声称提供 Linux kernel hard-realtime ABI、外部硬件驱动 ABI 或 native HAL module ABI。

因此：

```text
virtualHalReady=true
motionControllerMatrix.complete=true
sourceCompliance.complete=true
```

只能作为 `nativeHalSyncReady` 的前置 evidence，不能直接使：

```text
nativeTaskReady=true
nativeHalSyncReady=true
fullLinuxCncProgramExecutionReady=true
```

真正提升仍必须由 LinuxCNC task/motion/HAL WASM runtime 或 host-native 对照探针完成。

### 4.3 native opt-in probe 模式

`textbak/text21.txt`、`textbak/text24.txt`、`textbak/text28.txt`、`textbak/text35.txt` 和 `wasm-port/docs/full-process-boundary-design.md` 已形成一套可复用规则：

```text
source proof ready
native runtime readiness checked
probe disabled by default
ENABLE_*_RUNTIME_PROBE=1 才运行真实 host runtime
缺少 host runtime 时 skip，不失败
已有 LinuxCNC runtime 冲突时 blocked，不抢占
execution_enabled=0
promotion_allowed=0 until Node/WASM/browser proof also passes
```

当前已有可参考脚本：

```text
wasm-port/tests/native/probe_millturn_user_m_runtime.sh
wasm-port/tests/native/probe_tool_db_runtime.sh
wasm-port/tests/native/probe_python_remap_runtime.sh
```

后续 `probe_trt_task_hal_runtime.sh` 必须照这个模式写，尤其是：

- 检查 `linuxcnc`、`halcmd`、`halrun`、`milltask` 或所需命令；
- 默认只报告 readiness，不执行独占 runtime；
- 显式 opt-in 后才启动 native runtime；
- 如果发现已有 `linuxcncsvr -ini` 或 `rtapi_app load`，报告 blocked；
- 输出 key/value artifact，且默认保持 `promotion_allowed=0`。

### 4.4 Web/virtual HAL user-M proof 可借鉴

`textbak/text28.txt` 的 L4-USER-M-PROCESS 记录说明：millturn `M429 -> M129 -> turn`、`M428 -> M128 -> mill` 已接入 Web/virtual HAL 状态 proof，验证了：

```text
motion.switchkins-type
motion.analog-out-03
kinstype.is-0 / kinstype.is-1
ini.x.min_limit / ini.x.max_limit
ini.z.min_limit / ini.z.max_limit
```

这对 TRT `M428/M429/M430` 的 task/HAL 同步很有价值：可复用状态目标、guard pin、source-boundary report 的写法。但它仍然不执行 arbitrary external user-M process，不解除 native promotion。

### 4.5 kinematics 和 HAL shim 已有注意事项

`textbak/text39.txt`、`textbak/text40.txt`、`textbak/text41.txt` 记录了 kinematics WASM ABI 和 HAL shim 经验：

- `wasm-port/runtime/core/shims/hal.h` 已是 C ABI 边界；
- `linuxcnc_hal_adapter.cpp` 需要对 C/C++ 调用者保持一致 ABI；
- kinematics C 源可能直接调用 `hal_*`，所以 task/HAL runtime 的 HAL API 不能只做 JS wrapper；
- kinematics ready 不能等同于 interpreter/remap/full-process ready。

后续新增 `linuxcnc_hal_runtime.hh/.cpp` 时，应兼容现有 `hal.h` 和 `linuxcnc_hal_adapter.hh`，不要另起一套不兼容 HAL 类型定义。

### 4.6 应写入后续实现的复用点

后续代码实施时，优先按下面映射复用：

| 后续阶段 | 复用来源 | 用法 |
| --- | --- | --- |
| 阶段 1 Native 对照探针 | `probe_millturn_user_m_runtime.sh` | 复制 opt-in、skip、blocked、key/value 输出模式 |
| 阶段 2 HAL runtime | `linuxcnc-hal.js`、`hal.h`、`linuxcnc_hal_adapter.hh` | 复用 pin 类型、family、source evidence、C ABI 类型 |
| 阶段 3 Motion HAL sync | `createVirtualHalMotionControllerMatrixReport()` | 把 matrix 从 virtual HAL fixture 升级为 task/motion/HAL runtime 对比 gate |
| 阶段 5 Machine-file session | `linuxcnc-machine-file-staging.js`、`snapshot-store.js` | 复用 OPFS 文件和 virtual HAL session payload 结构 |
| 阶段 6 SWITCHKINS | `VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY` | 复用 guard pin / state target / source-boundary report 方法 |
| 阶段 8 Full boundary | `full-process-boundary-design.md` | 保持 promotion lock，直到 native/WASM/browser 全链路通过 |

## 5. 分阶段实现

### 阶段 0：源码和构建清单补齐

目标：

- 把 task、motion、HAL、NML 相关源码加入可追溯清单；
- 明确哪些源文件参与 WASM 构建，哪些只用于 native 对照；
- 禁止直接从 JS 手写 task/HAL 语义。

要编写或更新的文件：

```text
wasm-port/tools/source-manifest.txt
wasm-port/docs/source-reuse-map.md
web-rtcp-5axis-sim-plan/docs/traceability-matrix.md
```

具体步骤：

1. 在 `source-manifest.txt` 中加入 `src/emc/task`、`src/emc/motion`、`src/hal`、`src/libnml`、`src/emc/nml_intf` 的必要文件。
2. 建立 manifest 校验脚本，比较 `linuxcnc/` 和 `wasm-port/vendor/linuxcnc/` 的 hash。
3. 对 `emctaskmain.cc`、`emctask.cc`、`taskintf.cc`、`emccanon.cc` 做编译依赖扫描，列出必须 shim 的函数。
4. 对 `hal_lib.c`、`hal_priv.h`、`threads.c`、motion HAL pin 定义做依赖扫描，列出 HAL API 最小集合。
5. 验收时输出机器可读 artifact：

```text
task_hal_source_manifest_ready=1
task_source_count>0
hal_source_count>0
motion_source_count>0
```

### 阶段 1：Native 对照探针

目标：

- 先用 host-native LinuxCNC 证明期望行为；
- 不修改 Web runtime；
- 如果本机没有 LinuxCNC runtime 命令，探针允许 skip，但不得 promoted。
- 复用 `textbak` 中已有 native opt-in probe 规则，避免默认启动或抢占 LinuxCNC host runtime。

要编写的文件：

```text
wasm-port/tests/native/probe_trt_task_hal_runtime.sh
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_task_hal_native_probe.cpp
wasm-port/build/native/task-hal-reference/*.json
```

固定序列：

```text
SET_STATE ON
SET_MODE AUTO
OPEN impeller-7bl-xyzac.ngc
RUN
wait until first motion
PAUSE
RESUME
run through M428/M429 switchkins segment
ABORT
```

必须记录：

```text
task.state
task.mode
task.interpState
task.execState
motion.program-line
motion.motion-type
motion.switchkins-type
motion.coord-mode
motion.teleop-mode
motion.in-position
joint.N.motor-pos-cmd
joint.N.motor-pos-fb
axis pose / commanded pose / feedback pose
analog-out-03
synch digital/analog IO
```

验收：

```text
native_task_hal_probe=ok
native_probe_status=passed or skipped_missing_host_runtime
promotionAllowed=false until WASM comparison passes
```

### 阶段 2：HAL 内存模型和线程调度器

目标：

- 用 LinuxCNC HAL API 名称建立 WASM 内部 HAL registry；
- 支持 pin、signal、param、net、alias；
- 支持确定性 thread/function 调度。
- 复用 `linuxcnc-hal.js` 中的 HAL family/source evidence 和 `hal.h` 的类型定义。

参考源码：

```text
linuxcnc/src/hal/hal_lib.c
linuxcnc/src/hal/hal_priv.h
linuxcnc/src/hal/components/threads.c
wasm-port/runtime/core/shims/hal.h
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_hal_adapter.hh
```

要编写的文件：

```text
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_hal_runtime.hh
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_hal_runtime.cpp
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_halcmd_runtime.cpp
wasm-port/tests/wasm/node/verify_hal_runtime.sh
wasm-port/runtime/sdk/src/linuxcnc-hal.js
```

必须实现的 C/C++ API：

```text
hal_init
hal_ready
hal_exit
hal_malloc
hal_pin_bit_new
hal_pin_float_new
hal_pin_s32_new
hal_pin_u32_new
hal_pin_*_newf
hal_param_*_newf
hal_get_pin_value_by_name
hal_get_signal_value_by_name
hal_get_param_value_by_name
hal_link
hal_unlink
hal_set_p
hal_get_p
hal_create_thread
hal_add_funct_to_thread
hal_del_funct_from_thread
hal_start_threads
hal_stop_threads
```

必须实现的 WASM C ABI：

```c
int lchal_init_runtime(void);
int lchal_load_hal_file(const char *path, const char *text);
int lchal_set_pin_float(const char *name, double value);
int lchal_set_pin_s32(const char *name, int value);
int lchal_set_pin_bit(const char *name, int value);
int lchal_get_pin_json(const char *name, char *out, int out_len);
int lchal_get_snapshot_json(char *out, int out_len);
int lchal_step_threads(long period_ns, int cycles);
int lchal_reset_runtime(void);
```

编写要点：

1. 所有 HAL 值必须保存在 C/C++ runtime 内部，不放在 JS 里当语义源。
2. `net` 只建立 pin 到 signal 的绑定，值传播由 thread step 或显式 set/get 触发。
3. `halcmd` 先支持 TRT sim config 需要的最小命令：`loadrt`、`addf`、`net`、`setp`、`gets`。
4. 对 `loadusr`、外部进程、真实驱动组件必须返回 blocked evidence，不得静默忽略。
5. 每次 `lchal_step_threads()` 记录 cycle、thread name、function name、changed pins。

验收：

```text
hal_runtime_registry=ok
hal_thread_scheduler=ok
hal_net_signal_propagation=ok
loadusr_blocked_evidence=ok
```

### 阶段 3：Motion realtime 同步最小闭环

目标：

- 把 LinuxCNC motion controller 以确定性 servo cycle 方式接入；
- task 发出的 trajectory/jog 命令进入 motion command queue；
- motion controller 每周期更新 status 和 HAL pins。
- 把现有 virtual HAL motion controller matrix 改造为 task/motion/HAL runtime 的对比 gate。

参考源码：

```text
linuxcnc/src/emc/motion/usrmotintf.h
linuxcnc/src/emc/motion/motion.h
linuxcnc/src/emc/motion/motion.c
linuxcnc/src/emc/motion/command.c
linuxcnc/src/emc/motion/control.c
linuxcnc/src/emc/motion/mot_priv.h
linuxcnc/src/emc/task/taskintf.cc
```

要编写的文件：

```text
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_motion_runtime.c
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_motion_runtime.h
wasm-port/tests/wasm/node/verify_motion_hal_sync.sh
wasm-port/runtime/sdk/src/linuxcnc-motion.js
```

必须实现的 C ABI：

```c
int lcmot_init_from_ini(const char *ini_path, const char *ini_text);
int lcmot_write_command_json(const char *json);
int lcmot_step_servo(long period_ns, int cycles);
int lcmot_read_status_json(char *out, int out_len);
int lcmot_read_hal_snapshot_json(char *out, int out_len);
int lcmot_reset(void);
```

编写要点：

1. 优先复用 `emcmot_status_t`、`emcmot_command_t`、`emcmot_config_t`，避免新建 Web 专用 motion struct。
2. `usrmotWriteEmcmotCommand()` 在 WASM 中改为写入内存队列。
3. `usrmotReadEmcmotStatus()` 在 WASM 中从同一 runtime snapshot 读取。
4. `emcmotController(void *arg, long period)` 按固定周期调用。
5. motion HAL pins 必须按 `mot_priv.h` 中的方向和名称输出。
6. 至少覆盖 `EMC_JOG_*`、`EMC_TRAJ_LINEAR_MOVE`、`EMC_TRAJ_CIRCULAR_MOVE`、`EMC_TRAJ_PAUSE`、`EMC_TRAJ_RESUME`、`EMC_TRAJ_ABORT`、override 类命令。

验收：

```text
motion_hal_servo_cycle=ok
motion_program_line_hal_sync=ok
switchkins_type_hal_sync=ok
jog_motion_status_sync=ok
```

### 阶段 4：Task runtime 移植

目标：

- 让 Web runtime 使用 LinuxCNC task loop 处理 operator command；
- `RUN/PAUSE/RESUME/STOP/ABORT/MDI/JOG` 不再只走 Web policy mirror；
- task status、exec state、interp state 来自 LinuxCNC task runtime。

参考源码：

```text
linuxcnc/src/emc/task/task.hh
linuxcnc/src/emc/task/emctask.cc
linuxcnc/src/emc/task/emctaskmain.cc
linuxcnc/src/emc/task/taskintf.cc
linuxcnc/src/emc/task/emccanon.cc
linuxcnc/src/emc/nml_intf/emc.hh
```

要编写的文件：

```text
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_task_hal_wasm.cpp
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_task_nml_inproc.hh
wasm-port/runtime/core/linuxcnc_wrap/linuxcnc_task_nml_inproc.cpp
wasm-port/tools/build_task_hal_wasm.sh
wasm-port/runtime/sdk/src/linuxcnc-task-hal.js
web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-task-hal-runtime.js
web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-task-hal-worker.js
web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-task-hal-worker-client.js
```

必须实现的 C ABI：

```c
int lctask_init_session(const char *session_json);
int lctask_stage_file(const char *path, const char *text);
int lctask_open_program(const char *path);
int lctask_send_command_json(const char *command_json);
int lctask_run_cycles(long task_period_ns, long servo_period_ns, int task_cycles);
int lctask_read_status_json(char *out, int out_len);
int lctask_read_events_json(char *out, int out_len);
int lctask_reset_session(void);
```

command JSON 最小格式：

```json
{"type":"EMC_TASK_SET_STATE","state":"ON"}
{"type":"EMC_TASK_SET_MODE","mode":"AUTO"}
{"type":"EMC_TASK_PLAN_RUN","line":0}
{"type":"EMC_TASK_PLAN_PAUSE"}
{"type":"EMC_TASK_PLAN_RESUME"}
{"type":"EMC_TASK_ABORT"}
{"type":"EMC_TASK_PLAN_EXECUTE","mdi":"G0 X1"}
{"type":"EMC_JOG_INCR","axis":"X","distance":1,"velocity":60}
```

编写要点：

1. `emcTaskOnce()` 是 task loop 的首选入口；不能直接复制 Web 现有 `linuxcnc-task-policy.js` 的判断结果作为完成状态。
2. `RCS_CMD_CHANNEL`、`RCS_STAT_CHANNEL`、NML channel 在 WASM 中用 in-process queue shim 替代，消息类型仍来自 `emc.hh`。
3. `emcTaskQueueCommand()` 输出的 `EMC_TRAJ_*` 消息必须进入 motion runtime，而不是只生成 UI event。
4. `emccanon.cc` 生成的 canonical motion 要同时进入 task queue evidence、motion command queue、TP planner timing evidence、G-code 当前行映射。
5. task cycle 和 servo cycle 分开，例如每个 10 ms task cycle 运行 10 个 1 ms servo cycle。

验收：

```text
linuxcnc_task_runtime_smoke=ok
task_status_from_linuxcnc_runtime=ok
task_commands_drive_motion_runtime=ok
mdi_jog_task_motion_hal_sync=ok
```

### 阶段 5：TRT machine-file session 接入

目标：

- 复用现有 OPFS machine-file staging；
- task/HAL runtime 读取同一 INI、HAL、tool table、remap、G-code 文件；
- `xyzac-trt` 和 `xyzbc-trt` 都能跑 smoke。

要更新的文件：

```text
web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-machine-file-staging.js
web-rtcp-5axis-sim-plan/app/src/runtime/linuxcnc-interpreter-runtime.js
web-rtcp-5axis-sim-plan/app/src/state/store.js
web-rtcp-5axis-sim-plan/app/src/ui/gmoccapy-shell.js
```

具体步骤：

1. 给 staging 结果增加 `taskHalSession`，记录 INI、HAL、tool table、remap、program path。
2. Worker 初始化时把所有 staged 文件写入 Emscripten FS。
3. `LOAD_LINUXCNC_GCODE_SOURCE` 后自动调用 `lctask_open_program()`。
4. `RUN` 优先走 task/HAL runtime；失败时可 fallback 到现有 interpreter runtime，但 UI 必须显示 fallback boundary。
5. G-code panel 当前行改用 task/motion status 的 `motion.program-line`，interpreter canonical line 只作为辅助 evidence。

验收：

```text
task_hal_machine_file_staging=ok
xyzac_trt_task_hal_run=ok
xyzbc_trt_task_hal_run=ok
gcode_current_line_from_motion_hal=ok
```

### 阶段 6：SWITCHKINS 和 M428/M429/M430 同步

目标：

- `M428/M429/M430` 的状态变化由 LinuxCNC task/remap/motion/HAL 链路驱动；
- Web runtime 不再单独用 JS 事件切换 RTCP 作为主语义源。

参考源：

```text
linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc
linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/429remap.ngc
linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/430remap.ngc
linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/switchkins_postgui.hal
linuxcnc/src/emc/motion/control.c
linuxcnc/src/emc/kinematics/switchkins.c
linuxcnc/src/emc/kinematics/xyzac-trt-kins.c
linuxcnc/src/emc/kinematics/xyzbc-trt-kins.c
```

具体步骤：

1. 在 HAL runtime 中保证 `motion.switchkins-type` 可读写。
2. 在 remap execution 中保留 `M68`/`M66` 同步语义。
3. motion servo cycle 读取 `motion.switchkins-type` 后调用 kinematics switch。
4. Three.js 和 DRO 从 task/HAL snapshot 中读取 `rtcpState`、`kinsType`、tool axis。
5. 当前已有的 JS switchkins event 只保留为 diagnostics fallback，不作为 promoted source。

验收：

```text
switchkins_remap_hal_sync=ok
m428_to_tcp_xyzac=ok
m429_to_identity=ok
m430_to_userk_or_profile_defined=ok
rtcp_frame_from_task_hal_runtime=ok
```

### 阶段 7：浏览器 Worker 和 store 接线

目标：

- task/HAL runtime 在 Worker 内运行；
- UI 不直接阻塞；
- status snapshot 驱动 gmoccapy UI。

Worker message 类型：

```text
init
stageFiles
openProgram
command
runCycles
readStatus
reset
```

store action 映射：

```text
TOGGLE_POWER -> EMC_TASK_SET_STATE
RESET -> EMC_TASK_SET_STATE RESET / task reset sequence
SET_MODE -> EMC_TASK_SET_MODE
RUN -> EMC_TASK_PLAN_RUN
PAUSE -> EMC_TASK_PLAN_PAUSE
RESUME -> EMC_TASK_PLAN_RESUME
STOP/ABORT -> EMC_TASK_ABORT + EMC_TRAJ_ABORT
RUN_MDI -> EMC_TASK_PLAN_EXECUTE
JOG -> EMC_JOG_INCR or EMC_JOG_CONT + EMC_JOG_STOP
ADJUST_OVERRIDE -> EMC_TRAJ_SET_SCALE / EMC_TRAJ_SET_RAPID_SCALE
```

UI 显示要求：

```text
taskRuntimeReady
halRuntimeReady
taskCycle
servoCycle
motionQueueDepth
halChangedPinCount
nativeTaskReady
nativeHalSyncReady
fullLinuxCncProgramExecutionReady
```

验收：

```text
browser_task_hal_worker_smoke=ok
gmoccapy_task_hal_dom_smoke=ok
canvas_updates_from_task_hal_snapshot=ok
```

### 阶段 8：Full boundary 提升

目标：

- 只有所有 task/HAL smoke 通过后，才修改 full boundary；
- 把 blocker 从当前状态移除。

提升条件：

```text
kinematicsReady=true
interpreterReady=true
plannerRuntimeReady=true
machineFileStagingReady=true
machineFileRemapReady=true
taskRuntimeReady=true
motionRuntimeReady=true
halRuntimeReady=true
nativeTaskReady=true
nativeHalSyncReady=true
taskHalComparisonReady=true
```

`createFullLinuxCncExecutionBoundary()` 修改规则：

```text
nativeTaskReady = taskHal?.summary?.taskRuntimeReady === true
nativeHalSyncReady = taskHal?.summary?.halSyncReady === true
fullLinuxCncProgramExecutionReady =
  kinematicsReady &&
  interpreterReady &&
  canonicalProgramReady &&
  machineFileStagingReady &&
  machineFileRemapReady &&
  plannerRuntimeReady &&
  nativeTaskReady &&
  nativeHalSyncReady
```

semantic boundary 名称：

```text
linuxcnc_task_motion_hal_wasm_simulation_runtime
```

不允许的提升：

- 只有 Web policy mirror 通过；
- 只有 interpreter canonical events 通过；
- 只有 TP timing 通过；
- 只有 HAL source map 或 PyVCP schema 通过；
- 没有 task cycle 与 HAL servo cycle 对比 artifact。

## 5. 详细编程顺序

建议严格按以下顺序写程序，避免一次性移植 task、HAL、motion 后难以定位问题。

1. 新建 `linuxcnc_hal_runtime.hh/.cpp`，只实现 pin registry、`hal_init()`、`hal_ready()`、`hal_malloc()`、`hal_pin_*_newf()`。
2. 写 `verify_hal_runtime.sh`，证明 pin 创建、set/get、snapshot JSON 可用。
3. 增加 signal/net/link，写 `halcmd_runtime.cpp` 支持 `net` 和 `setp`。
4. 增加 thread registry，支持 `hal_create_thread()`、`hal_add_funct_to_thread()`、`lchal_step_threads()`。
5. 接入 motion HAL pin 初始化，先让 `motion.switchkins-type`、`motion.program-line`、`joint.0.motor-pos-cmd` 能在 snapshot 中出现。
6. 新建 `linuxcnc_motion_runtime.c`，实现 in-memory `usrmotWriteEmcmotCommand()` 和 `usrmotReadEmcmotStatus()`。
7. 调用 `emcmotController()` 运行固定 servo cycles，先验证空闲状态 heartbeat 增长。
8. 接入 `EMC_TRAJ_LINEAR_MOVE`，验证 motor/carte command position 随周期变化。
9. 接入 JOG 命令，验证 FREE/TELEOP/COORD 模式切换和 HAL pins。
10. 新建 in-process NML queue shim，消息类型必须来自 `emc.hh`。
11. 编译 `emctask.cc`、`emctaskmain.cc`、`taskintf.cc`、`emccanon.cc` 的最小 task runtime。
12. 实现 `lctask_init_session()` 和 `lctask_send_command_json()`，先跑 `SET_STATE`、`SET_MODE`。
13. 实现 `lctask_open_program()`，读取 staged G-code。
14. 实现 `RUN/PAUSE/RESUME/ABORT`，验证 task status 和 motion status 同步。
15. 接入 existing interpreter/remap machine-file path，确保 M428/M429/M430 不再被 Web 主逻辑单独处理。
16. 把 task/HAL runtime 包成 SDK `linuxcnc-task-hal.js`。
17. 写 Web Worker client，加入 sequence guard，防止旧 status 覆盖新 session。
18. 修改 store：优先 task/HAL runtime，失败时保留现有 interpreter fallback 并显示 fallback boundary。
19. 修改 UI diagnostics，显示 task/HAL readiness 和 cycle counters。
20. 修改 full boundary，只有全部新 smoke 通过后才把 `nativeTaskReady`、`nativeHalSyncReady` 置为 true。

## 6. 验收测试矩阵

Node smoke：

```text
node web-rtcp-5axis-sim-plan/tests/node/verify_linuxcnc_task_hal_runtime.mjs
node web-rtcp-5axis-sim-plan/tests/node/verify_task_hal_machine_file_run.mjs
node web-rtcp-5axis-sim-plan/tests/node/verify_full_execution_boundary.mjs
npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node
```

Browser smoke：

```text
npm --prefix web-rtcp-5axis-sim-plan/app run build
npm --prefix web-rtcp-5axis-sim-plan/app run smoke
```

WASM smoke：

```text
bash wasm-port/tools/build_task_hal_wasm.sh
bash wasm-port/tests/wasm/node/verify_hal_runtime.sh
bash wasm-port/tests/wasm/node/verify_motion_hal_sync.sh
bash wasm-port/tests/wasm/node/verify_task_hal_wasm.sh
```

Native optional proof：

```text
ENABLE_TRT_TASK_HAL_RUNTIME_PROBE=1 bash wasm-port/tests/native/probe_trt_task_hal_runtime.sh
```

最终 gate：

```text
linuxcnc_task_hal_wasm_build=ok
hal_runtime_smoke=ok
motion_hal_sync_smoke=ok
linuxcnc_task_runtime_smoke=ok
task_hal_machine_file_smoke=ok
switchkins_remap_hal_sync_smoke=ok
browser_task_hal_worker_smoke=ok
full_execution_boundary_smoke=ok
```

## 7. 完成定义

只有同时满足以下条件，才允许把文档和 UI 中的 blocker 改为完成：

```text
task commands are accepted by LinuxCNC task-derived runtime
task runtime drives motion command queue
motion runtime advances through deterministic servo cycles
HAL pins are created from LinuxCNC-style HAL API
HAL thread/function scheduler advances with servo cycles
M428/M429 switchkins changes are visible through motion.switchkins-type
G-code current line comes from motion/task status
Node smoke passes
Browser source smoke passes
Browser dist smoke passes
Optional native LinuxCNC probe either passes or is explicitly skipped without promotion dependency
Traceability document records every source file and boundary
```

完成后仍必须在 UI 和文档里显示：

```text
hardwareDrive=false
hostRealtimeKernel=false
externalUserMProcessReady=false unless separately implemented
toolDbProcessReady=false unless separately implemented
```
