# 04 RUN status loop 完成记录与下一步建议 生成时间:2026-06-22 ## 1. 本轮完成范围 本轮完成 `03-run-step1-preconditions-complete-next-steps.md` 建议中的连续 feedback 工作,但命名从 `pump` 调整为更明确的: ```text taskHalStatusLoop ``` 这里的 loop 不生成 CNC 状态,不解析 G-code,也不自增行号。它只负责在 `RUN` 之后持续调度: ```text taskHalRuntime.runCycles(...) taskHalRuntime.readStatus() dispatch TASK_HAL_STATUS_APPLIED ``` `activeLine`、`axisPose`、`currentVelocity`、`switchkinsType`、DRO 和 runtime feedback 仍来自同一个 task/HAL/motion status snapshot。 ## 2. 已完成改动 ### 2.1 store 增加 taskHalStatusLoop 更新: ```text app/src/state/store.js ``` 新增状态: ```text taskHalStatusLoop: active sequence profileId iniPath kinematicsModuleId tickCount batchSize intervalMs taskPeriodNs servoPeriodNs lastStatusAt lastError stopReason ``` 并新增: ```text programRuntimeFeedbackHistory ``` 最多保留 100 条 task/HAL/motion runtime feedback。 ### 2.2 RUN 改为连续读取 task/HAL status `RUN` 当前流程: ```text 1. validateRunPreconditions(..., requireTaskHalSession=false) 2. 初始化或复用当前 machine-file task/HAL session 3. validateRunPreconditions(..., requireTaskHalSession=true) 4. 发送: EMC_TASK_SET_STATE ON EMC_TASK_SET_MODE AUTO EMC_TASK_PLAN_RUN 5. runCycles/readStatus 一次,应用首帧 status 6. 如果 status 仍处于 READING,则启动 taskHalStatusLoop 7. loop 持续 runCycles/readStatus,并通过 TASK_HAL_STATUS_APPLIED 更新 UI 状态 ``` 停止条件: ```text interpState=IDLE 且 nextProgramLine >= openedLineCount -> complete interpState=PAUSED 或 motion.paused=true -> paused motion.aborted=true -> stopped ``` ### 2.3 STOP / ABORT / PAUSE / RESUME / STEP 更新行为: ```text STOP/ABORT: 先停止 taskHalStatusLoop,再发送 EMC_TASK_ABORT,并读取一次 status。 PAUSE: 先停止 taskHalStatusLoop,再发送 EMC_TASK_PLAN_PAUSE,并读取一次 paused status。 RESUME: 发送 EMC_TASK_PLAN_RESUME,若 status 回到 READING,则重新启动 taskHalStatusLoop。 STEP: task/HAL runtime loaded 时不走 fixture playback。 改为明确 runCycles({ taskCycles: 1 }) 后 readStatus 一次。 ``` ### 2.4 新增验证 新增: ```text tests/node/verify_run_feedback_loop.mjs ``` 覆盖: ```text 1. 加载 xyzac-trt INI。 2. 加载 xyzac-trt kinematics WASM。 3. 加载 task/HAL runtime。 4. stage machine files。 5. 打开 xyzac_switchkins_test_1.ngc。 6. POWER/HOME/AUTO/RUN。 7. 等待 programRuntimeFeedbackHistory 至少 3 条。 8. 断言每条 feedback sourceMode 都是 linuxcnc-task-motion-hal-wasm。 9. 断言 semanticBoundary 是 linuxcnc_task_motion_hal_wasm_simulation_runtime。 10. 断言 taskCycle 和 servoCycle 单调递增。 11. 断言 STOP 后 taskHalStatusLoop.active=false。 ``` `app/package.json` 的 `smoke:node` 已加入: ```text node ../tests/node/verify_run_feedback_loop.mjs ``` ## 3. 已运行验证 通过: ```bash node tests/node/verify_run_feedback_loop.mjs node tests/node/verify_linuxcnc_task_hal_runtime.mjs node tests/node/verify_run_preconditions.mjs node tests/node/verify_rtcp_store.mjs npm --prefix app run build npm --prefix app run smoke:node ``` 关键输出: ```text run_feedback_status_loop_smoke=ok linuxcnc_task_hal_runtime_smoke=ok run_preconditions_ini_profile_smoke=ok rtcp_store_smoke=ok gmoccapy_static_build=ok ``` 本轮 `npm --prefix app run smoke:node` 已完整通过,包括 native task/HAL audit。 ## 4. 当前 RUN 状态 当前 `RUN` 已经从: ```text 发送 task command -> runCycles({ taskCycles: 5 }) -> readStatus() 一次 ``` 推进为: ```text 发送 task command -> runCycles/readStatus 首帧 -> taskHalStatusLoop 持续 runCycles/readStatus -> TASK_HAL_STATUS_APPLIED 持续消费同一 task/HAL/motion status 链 ``` 重要边界仍保持: ```text 不引入 JS G-code parser。 不在 UI 自增 activeLine。 不在 UI 自造 axisPose。 不把 canonical timing estimate 当作真实 task/HAL runtime。 status 内容必须来自 task/HAL/motion runtime。 ``` ## 5. 下一步工作建议 下一步建议做浏览器端证据采集: ```text 1. 扩展 qa/web-rtcp-5axis-site-test/capture-toolpath-preview-cases.mjs。 2. 新增 07-run-preconditions-and-feedback case。 3. 浏览器中执行 POWER/HOME/AUTO/RUN。 4. 采集 t=0.2s / 0.5s / 1.0s / 2.0s state。 5. 断言: - taskHalStatusLoop.tickCount 增长 - programRuntimeFeedbackHistory 增长 - activeLine 等于 UI 高亮行 - DRO 读取 state.programRuntimeFeedback.axisPose - RTCP canvas 状态与 state.rtcpState 一致 6. 输出 JSON 和截图证据。 ``` 随后再考虑: ```text 1. 把 M428/M429 switchkins 状态变化纳入 RUN loop 浏览器断言。 2. 增加 xyzbc-trt 的 RUN status loop 对称测试。 3. 如果需要更接近真实 UI 实时性,再评估是否把 loop 下沉到 worker push status,而不是 store setTimeout polling。 ```