# 03 RUN 第一步完成记录与下一步建议

生成时间：2026-06-22

## 1. 本轮完成范围

本轮只完成 `02-run-preconditions-test-and-implementation-steps.md` 中的第一步和第二步：

```text
Step 1: 增加 validateRunPreconditions(state)
Step 2: RUN action 先调用前置检查
```

本轮没有实现连续 feedback pump。也没有把 `RUN` 宣称为完整实时运行模型。

## 2. 已完成改动

### 2.1 RUN 前置条件 gate

新增源码：

```text
app/src/state/store.js
export function validateRunPreconditions(...)
```

校验内容：

```text
1. profile 必须是 xyzac-trt 或 xyzbc-trt。
2. LinuxCNC INI 必须已加载并 validation.ready=true。
3. profile.iniPath 必须与已加载 INI path 一致。
4. profile TRAJ coordinates 必须与 INI coordinates 一致。
5. profile.kinematicsModuleId 必须与 INI [KINS] 推导结果一致。
6. LinuxCNC kinematics runtime 必须 loaded。
7. kinematics runtime moduleId 必须匹配当前 profile。
8. RTCP frame 必须来自 source-derived-kinematics-wasm。
9. machine files 必须 staged。
10. 必须已选择 LinuxCNC source-directory G-code。
11. task/HAL runtime 必须 ready。
12. requireTaskHalSession=true 时，taskHalSession.programPath 必须匹配当前 selected G-code。
```

关键结果：

```text
当 taskHalRuntime 已加载时，RUN 不再直接发送 EMC_TASK_PLAN_RUN。
RUN 会先校验 INI/profile/kinematics/machine-file/task-HAL 上下文。
前置条件不满足时，只给 operatorMessage，不进入 fixture playback。
```

### 2.2 RUN 使用真实 machine-file session

新增内部流程：

```text
runValidatedTaskHalProgramRun()
```

执行顺序：

```text
1. validateRunPreconditions(..., requireTaskHalSession=false)
2. 如 taskHalSession 缺失或 programPath 不匹配，initializeTaskHalSession({ openProgram: true })
3. validateRunPreconditions(..., requireTaskHalSession=true)
4. 发送:
   EMC_TASK_SET_STATE ON
   EMC_TASK_SET_MODE AUTO
   EMC_TASK_PLAN_RUN line = activeLine - programStartLine
5. runTaskHalCommandSequence(..., allowFixtureSession=false)
```

这一步解决的是“RUN 之前先确定明确 INI、机床类型和五轴运动学算法”，不是连续执行问题。

### 2.3 新增测试

新增：

```text
tests/node/verify_run_preconditions.mjs
```

覆盖：

```text
1. xyzac-trt.ini 解析:
   MACHINE=sim-xyzac-trt-kins (switchkins)
   COORDINATES=XYZAC
   KINEMATICS=xyzac-trt-kins
   kinematicsModuleId=xyzac-trt

2. xyzbc-trt.ini 解析:
   MACHINE=sim-xyzbc-trt-kins (switchkins)
   COORDINATES=XYZBC
   KINEMATICS=xyzbc-trt-kins
   kinematicsModuleId=xyzbc-trt

3. applyIniConfigToProfile() 后 profile 与 INI 保持一致。
4. createLinuxCncKinematicsRuntime() 可按 moduleId 加载对应 WASM。
5. stageProfileMachineFiles() 和 buildTaskHalSessionFromMachineFiles() 能形成同一 machine-file 上下文。
6. validateRunPreconditions() 能阻断未加载 INI 的初始状态。
7. validateRunPreconditions() 能在 INI/kinematics/staged G-code ready 时通过非 task-HAL session 预检。
8. task/HAL runtime 缺失时返回明确阻断消息。
```

`app/package.json` 的 `smoke:node` 已加入：

```text
node ../tests/node/verify_run_preconditions.mjs
```

### 2.4 调整 task/HAL smoke

更新：

```text
tests/node/verify_linuxcnc_task_hal_runtime.mjs
```

调整点：

```text
1. 不再用内联 fixture G-code 直接测试真实 RUN。
2. 加载 xyzac-trt INI。
3. 加载 xyzac-trt kinematics runtime。
4. stage machine files。
5. LOAD_LINUXCNC_GCODE_SOURCE 选择:
   configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins_test_1.ngc
6. 等待 taskHalSession.programPath 指向该 G-code。
7. 再执行 POWER/HOME/AUTO/RUN。
```

这样 task/HAL RUN smoke 与新的 RUN 前置条件一致。

## 3. 已运行验证

通过：

```bash
node web-rtcp-5axis-sim-plan/tests/node/verify_run_preconditions.mjs
node web-rtcp-5axis-sim-plan/tests/node/verify_linuxcnc_task_hal_runtime.mjs
npm --prefix web-rtcp-5axis-sim-plan/app run build
```

输出：

```text
run_preconditions_ini_profile_smoke=ok
run_preconditions_kinematics_smoke=ok
run_preconditions_machine_file_smoke=ok

linuxcnc_task_hal_runtime_smoke=ok
task_hal_machine_file_smoke=ok
switchkins_remap_hal_sync_smoke=ok
browser_task_hal_worker_smoke=ok

gmoccapy_static_build=ok
```

部分通过后失败：

```bash
npm --prefix web-rtcp-5axis-sim-plan/app run smoke:node
```

该命令已通过本轮新增和相关测试：

```text
linuxcnc_kinematics_runtime_smoke=ok
linuxcnc_interpreter_runtime_smoke=ok
linuxcnc_ini_runtime_smoke=ok
run_preconditions_ini_profile_smoke=ok
run_preconditions_kinematics_smoke=ok
run_preconditions_machine_file_smoke=ok
linuxcnc_task_hal_runtime_smoke=ok
task_hal_machine_file_smoke=ok
switchkins_remap_hal_sync_smoke=ok
browser_task_hal_worker_smoke=ok
```

随后在既有 native audit 停止：

```text
wasm-port/tests/native/verify_task_hal_phase0.sh failed with status 1
```

直接运行该脚本确认失败点是：

```text
wasm-port/tools/verify_task_hal_source_manifest.sh
```

日志：

```text
task_hal_source_manifest_ready=0
task_hal_reference_source_ready=0
task_hal_missing_reference_source_count=20
```

说明：该失败来自外部 reference source `../linuxcnc` 缺失 task/HAL manifest 需要的 20 个文件，不是本轮 RUN 前置条件改动造成。

## 4. 当前 RUN 状态

现在 `RUN` 的第一道边界已经收紧：

```text
没有明确 INI -> 不 RUN
profile/INI 坐标不一致 -> 不 RUN
kinematics module 不一致 -> 不 RUN
kinematics frame 未 ready -> 不 RUN
machine files 未 staged -> 不 RUN
没有 LinuxCNC source G-code -> 不 RUN
task/HAL runtime 未 ready -> 不 RUN
taskHalSession.programPath 不匹配当前 G-code -> 不 RUN
```

但当前 `RUN` 仍然是：

```text
发送 task command
-> runCycles({ taskCycles: 5 })
-> readStatus() 一次
-> TASK_HAL_STATUS_APPLIED 一次
```

所以 `01-run-gcode-execution-principle-and-test.md` 中指出的连续 feedback 问题仍未解决。

## 5. 下一步工作建议

下一步应实现 `02` 文件中的 Step 3 和 Step 4：

```text
Step 3: 拆分 task command 与执行 pump
Step 4: 增加 RUN pump 状态
```

建议最小实现范围：

```text
1. 在 store state 增加 taskHalRunPump:
   active
   sequence
   profileId
   iniPath
   kinematicsModuleId
   tickCount
   lastStatusAt
   lastError

2. 增加 programRuntimeFeedbackHistory，最多保留 100 条。

3. RUN 发送 EMC_TASK_PLAN_RUN 后，不只 runCycles 5 次。
   改为启动 pump:
   runCycles({ taskCycles: batchSize })
   readStatus()
   dispatch TASK_HAL_STATUS_APPLIED
   append feedback history
   根据 interpState / task.nextProgramLine / openedLineCount / paused / aborted 停止。

4. STOP/ABORT 必须停止 pump。

5. PAUSE 停止或降频 pump，并保留 paused status。

6. RESUME 重新启动 pump。

7. STEP 在 task/HAL runtime loaded 时不走 fixture sample playback，
   而是推进一个明确 task cycle batch 并 readStatus 一次。
```

下一步测试建议：

```text
1. 新增 tests/node/verify_run_feedback_pump.mjs。
2. 使用 xyzac_switchkins_test_1.ngc。
3. RUN 后采集至少 8 个 feedback tick。
4. 断言 taskCycle 或 servoCycle 单调递增。
5. 断言 activeLine 不停留在 RUN 后第一帧。
6. 断言每个 tick 的 sourceMode 都是 linuxcnc-task-motion-hal-wasm。
7. 断言 programRuntimeFeedbackHistory 至少包含 3 条。
8. 断言 STOP 后 pump.active=false。
```

浏览器测试建议：

```text
扩展 qa/web-rtcp-5axis-site-test/capture-toolpath-preview-cases.mjs
新增 07-run-preconditions-and-feedback case。
采集 RUN 后 0.2s / 0.5s / 1.0s / 2.0s 的 state。
断言 activeLine、DRO、runtime feedback、canvas RTCP 状态来自同一 feedback snapshot。
```

## 6. 重要边界

下一步实现 pump 时仍需保持：

```text
不引入 JS G-code parser。
不在 UI 里自增 activeLine。
不在 UI 里自造 axisPose。
不把 canonical timing estimate 当作真实 task/HAL runtime。
不把 fixture playback 标记为 fullLinuxCncProgramExecutionReady。
```

RUN 的真实推进必须来自：

```text
taskHalRuntime.runCycles()
taskHalRuntime.readStatus()
TASK_HAL_STATUS_APPLIED
```
