23 KiB
LinuxCNC Web/WASM 系统流程与后续执行基线
更新时间:2026-08-21
本文件把现有代码、LinuxCNC 源程序、仿真配置和测试程序放在同一条可执行链上。它的目的不是再次定义产品范围,而是回答三个问题:当前代码究竟完成到哪一层、一个 LinuxCNC 仿真入口如何穿过前端/Worker/WASM、后续任务应从哪里开始以及如何验收。
规范入口仍然是 nextTask.md。本文件是工程梳理和任务分解,不替换 context-lock.json、协议 schema、覆盖矩阵或 release gate。
1. 先给结论
1.1 当前正式任务起点
当前正式指针是 WAIT-OWNER-01,状态为 blocked。它等待六项 owner decision 或新的 locked context input;coverage/owner-decision-intake.report.json 在输入缺失时只能生成 blocked report。此期间不能刷新 K8 release gate、创建新 context、把 partial 改成 accepted,也不能重复执行已完成的实现矩阵。
这与技术路线中的“实现任务已完成”并不矛盾:
| 层次 | 当前结论 | 证据 | 含义 |
|---|---|---|---|
| 基线 | LinuxCNC 2.10.0~pre0,source SHA 已冻结 |
context-lock.json |
源码变化必须重新建 context |
| WASM 单元能力 | posemath、解释器切片、motion queue、HAL、运动学、IO 均有 C ABI 和 native/WASM 测试 | wasm-core/CMakeLists.txt、build-native、build-wasm |
证明模块边界,不证明完整 Task 链 |
| Worker/存储适配 | 协议、配置/HAL preflight、虚拟设备、事件重放、workspace package、Python bridge 已有测试 | web/worker、web/workspace、coverage/*report.json |
证明适配器和错误边界 |
| 前端 | AppShell、WorkerClient、控制、状态、恢复、设备/HAL/机床视图已有 smoke | web/app、coverage/frontend-m*.report.json |
证明 UI 垂直切片,不证明所有真实命令已经驱动核心 |
| 配置矩阵 | 264 个注册配置条目、233 个入口;56 个 ready,208 个 blocked | coverage/full-configuration-startup-matrix.report.json |
入口闭包仍未完成 |
| 资源闭包 | 16,093 条资源边,15,112 resolved,981 blocked | coverage/configuration-startup-closure.report.json |
缺失资源不能被静默忽略 |
| 发布 | candidate_eligible=false、STOP_RELEASE |
coverage/release-candidate-gate.report.json |
当前不是发布候选 |
1.2 代码上的真实边界
目前最容易误判的地方是:模块测试都通过,但完整 LinuxCNC 行为还没有贯通。具体表现为:
wasm-core/src/sim_api.c仍是生命周期、加载标志、tick 和 pending event 的 bootstrap 状态;sim_command不解析命令,sim_step不调用解释器、TP、HAL、运动学或 IO。web/worker/sim-session.mjs已经把协议、幂等、配置/HAL preflight、虚拟设备、Python 和恢复接起来,但PROGRAM_*、COMMAND等未知于设备的命令目前会落入通用COMMAND_RESULT,不能视为已经执行了 LinuxCNC Task。web/app/project-workflow.mjs默认使用MemoryStorage;workspace package/migration/recovery 契约已验证,真实浏览器 OPFS、Service Worker 离线启动和崩溃后的实际恢复仍需浏览器矩阵验证。- 解释器、motion、kinematics、IO 的 C API 是可用的模块边界,但尚缺一个统一的
sim_task/session runtime,把“程序行 -> canonical -> TP -> IK -> joint motion -> feedback -> HAL/IO -> snapshot”作为一个原子固定 tick 执行。
因此,当前状态应写成“适配器和核心切片已验证,端到端仿真 Task 尚未完成”,不能写成“LinuxCNC 已完整移植”。
2. 一次仿真入口的实际流程
下面的流程区分了已经存在的代码路径和必须补齐的目标路径。
浏览器 UI
-> WorkerClient 生成 protocol.v1 envelope
-> sim-worker.mjs 单 Worker 接收消息
-> SimSession 校验 schema/context/session/seq/tick
-> sim_protocol_accept (WASM C ABI)
-> HELLO/ATTACH 或 LOAD_WORKSPACE
-> configuration preflight (INI/HAL/资源图)
-> HAL preflight (component/pin/thread/function 图)
-> sim_load_workspace (当前仍为 bootstrap load flag)
-> command / program / step
-> [应补] sim_task: interpreter -> canonical -> TP -> motion/IK -> HAL/IO/Python
-> event log + replay timeline + state hash
-> snapshot/checkpoint/recovery
-> Worker envelope 返回
-> WorkerClient promise + domain reducer
-> 状态面板、设备面板、HAL 诊断、Three.js/Canvas 视图
-> workspace journal/package/OPFS 持久化
2.1 前端到 Worker
入口是 web/app/app.mjs 和 web/app/worker-client.mjs。前端只发送带 schema_version、context_id、session_id、单调 seq、可选 operation_id 和 payload 的消息;前端不得读取 WASM 指针或直接写 Worker 内部状态。
WorkerClient 的主要调用对应关系如下:
| UI 操作 | Worker 消息 | 当前实现 |
|---|---|---|
| 连接/能力协商 | HELLO |
返回 capabilities |
| 建立会话 | SESSION_ATTACH |
调用 sim_create,进入 ready |
| 加载工程 | LOAD_WORKSPACE |
运行配置/HAL preflight,再调用 sim_load_workspace |
| 推进仿真 | SIM_STEP |
调用 sim_step,更新 tick 和 timeline |
| 读取状态 | SNAPSHOT_REQUEST |
返回 snapshot/checkpoint 摘要 |
| 控制命令 | PROGRAM_*、HOME、ESTOP 等 |
设备命令进入 VirtualDevices;程序/Task 命令仍待接入 |
| 恢复 | CHECKPOINT、RECOVER |
事件重放和 workspace 状态恢复已覆盖 |
2.2 Worker 到 WASM
web/worker/sim-session.mjs 是唯一的 Worker 编排边界。它先调用 _sim_protocol_accept,再把能改变仿真结果的事件写入 ReplayTimeline 和 C event log。所有操作必须串行执行;相同 operation_id 的重复请求返回原结果并写入 OPERATION_REPLAY。
WASM 导出列表在 wasm-core/CMakeLists.txt 中冻结,当前可以分为四类:
- 协议/生命周期:
sim_create、sim_load_workspace、sim_command、sim_step、状态导入导出。 - 核心模块:
sim_interpreter_*、sim_motion_*、sim_kinematics_*、sim_posemath_*。 - 运行时对象:
sim_hal_*、sim_io_*、event log。 - 运动集成:
sim_kinematics_motion_*、feedback、home/limit、switchkins、userk 和 registry。
后续不能继续增加孤立导出函数;应先把这些函数收拢进一个有明确状态、错误回滚和 snapshot 字段的 sim_task runtime,再由 Worker 调用。
2.3 固定 tick 的目标顺序
固定 tick 顺序属于行为契约,建议按以下顺序实现并为每一步保留前后状态 hash:
- 接收本 tick 的 Task/MDI/jog/设备输入,检查命令权限、模式和 abort/estop。
- 解释器读取一行 G-code/O-code/M-code,更新 modal、参数、当前行和 canonical queue。
- 执行 canonical queue 的 TP:前瞻、速度/加速度限制、blend/exact stop、pause/abort。
- 将笛卡尔 pose 送入 inverse kinematics,生成 joint command;奇异、越界和非有限值必须事务性失败。
- 推进 joint/motion queue,执行正解 feedback,更新 axis/joint/pose/velocity/following error。
- 按固定线程顺序执行 HAL component graph;组件失败不应推进半个 tick。
- 推进 spindle/tool/probe/limit/estop 等虚拟 IO 和 Python callback;Python 只能使用 allowlist API。
- 生成事件、报警、canonical、snapshot 和状态 hash;提交 checkpoint 或 journal 时才写持久层。
3. LinuxCNC 源程序、案例和测试的对应关系
LinuxCNC 的 configs/sim 不是文档附件,而是启动闭包和功能来源。下面先用少量代表性案例建立可跑的纵向切片,再扩展到全部 233 个入口。
| 功能域 | LinuxCNC 源程序 | 代表性仿真案例 | 代表性测试程序 | WASM/Worker 目标 | 前端工作流 |
|---|---|---|---|---|---|
| 启动、INI、资源 | src/emc/ini/emcIniFile.cc、iniaxis.cc、inijoint.cc、initraj.cc |
configs/sim/axis/minimal_xyz.ini、ini_with_includes/includes_demo.ini |
tests/rs274ngc-startup、tests/startup-state、tests/io-startup |
解析 section/include/变量、坐标和资源;构造 sim_task_config |
工程选择、预检错误定位、启动/重启 |
| 解释器、canonical | src/emc/rs274ngc/*、src/emc/task/emccanon.cc、src/emc/nml_intf/interpl.cc |
axis/minimal_xyz.ini 的 G0/G1、axis/iocontrolv2/owordm6-ui.ini |
tests/interp/good、g52、m98m99、remap/oword-pycall、unit_tests/interp/* |
从文件/MDI 读行,输出 canonical 和当前行;错误回到协议 | 程序编辑器、MDI、当前行、语法/运行错误 |
| TP、运动 | src/emc/tp/tp.c、tc.c、tcq.c、blendmath.c;src/emc/motion/* |
axis/minimal_xyz.ini、axis/gantry/gantry.ini |
unit_tests/tp/test_blendmath.c、tests/motion/g0、tests/trajectory-planner/circular-arcs、tests/abort/* |
固定 tick TP -> motion queue,支持 pause/abort/queue-buster | 运行/暂停/单步/轨迹预览/倍率 |
| 运动学 | src/emc/kinematics/*kins.c、kins_util.c、switchkins.c |
axis/gantry/gantry.ini、axis/ldelta.ini、axis/pentapod/pentapod.ini、axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini |
tests/matrixkins、运动学配置案例;官方 unit_tests/kinematics/** 在锁定来源中缺失 |
registry + FK/IK + branch/singularity + feedback/home/limit | 轴/关节/姿态、3D 模型、故障和奇异性 |
| HAL | src/hal/hal_lib.c、halmodule.cc、utils/halcmd*、src/hal/components/*.comp |
axis/gantry/gantrysim.hal、axis/ini_hal_demo.ini |
tests/hal-*、tests/basic、tests/edge/*、tests/module-loading/*、tests/hal-link-unlink |
类型化 pin/signal/thread/function 图,固定顺序执行 | HAL browser、pin 值、连接图、波形 |
| IO、主轴、换刀、探针 | src/emc/iotask/ioControl*.cc、src/emc/tooldata/* |
axis/iocontrolv2/*、axis/lathe.ini、axis/gladevcp/probe.ini |
tests/io-startup/*、tests/toolchanger/*、tests/tool-info/*、tests/t0/* |
虚拟主轴/工具/探针状态机,故障、互锁和事件 | 主轴、工具、探针、报警和恢复 |
| Python/remap/filter | src/emc/rs274ngc/interp_python.cc、interp_remap.cc、lib/python/* |
axis/remap/*、axis/plasma/*、axis/ngcgui/* |
tests/remap/*、tests/interp/python*、tests/interp/pymove |
Worker-only allowlist,异常和资源限额映射为 Task 错误 | remap 参数、宏、材料表、插件状态 |
| UI/VCP/可视化 | src/emc/usr_intf/*、lib/python/rs274/glcanon.py、hal/user_comps/vismach/* |
axis/gladevcp/*、axis/qtvcp/*、axis/vismach/*、qtplasmac/* |
UI test scripts、对应配置的启动测试和浏览器 E2E | descriptor -> Web component;轨迹/姿态只读 snapshot | 控制台、VCP、3D、示波器、配置编辑 |
| 持久化/恢复 | LinuxCNC 参数、tool table、日志语义 + 本项目 web/workspace/* |
sim.var、*.tbl、工程 package |
tests/save.*、tests/source.0,本项目 test_recovery.mjs、test_migration.mjs |
checkpoint/event/journal/package 双向迁移、fail-closed | 工程导入导出、离线、刷新、恢复 |
3.1 第一批必须跑通的案例
先不要从最复杂的 QtVCP/PlasmaC/机器人界面开始。建议按以下顺序建立可重复的端到端样例:
minimal_xyz.ini:HELLO -> ATTACH -> LOAD -> home -> PROGRAM_LOAD -> G0 X1 -> step -> snapshot。它验证最小启动、解释器、trivkins、motion、snapshot 和前端状态。gantry/gantry.ini:验证XYZY重复坐标、四关节映射、HOME_SEQUENCE=-1同步回零和 CoreXY/gantry HAL。iocontrolv2/axis-iocontrolv2-demo.ini:验证T/M6的 prepare/change、主轴停止互锁、tool table、IO pin 和失败恢复。vismach/5axis/table-rotary-tilting/xyzac-trt.ini:验证姿态、TRT kinematics、tool orientation、FK feedback 和 3D 轨迹。remap/oword-pycall:验证 O-word、Python remap、虚拟 API、异常、参数和 checkpoint/replay。hard-limits+abort/*:验证 soft/hard limit、estop、abort、following error 和恢复后状态 hash。plasma/metric.ini或gladevcp/probe.ini:验证虚拟探针/torch/材料表以及 UI/设备交互。
每个案例都必须保留原始配置资源边、native 运行结果、WASM 结果、首个 divergent tick、字段路径、错误码和状态 hash;只看页面截图不算通过。
4. 按技术路线的任务分层
下面把路线图的 M0-M5 和代码实际状态对齐。verified 表示该任务的实现证据已生成,不等于 release accepted。
| 阶段 | 目标 | 已有结果 | 未完成的关键闭环 | 退出条件 |
|---|---|---|---|---|
| M0 基线 | 来源、manifest、依赖、context lock | 8,053 source entries,321 test entries,清单生成器稳定 | 6,249 seed 仍未分配 feature owner | source/manifest/context hash 可重建 |
| M1 会话骨架 | protocol、create/load/step/snapshot/recover | C ABI、Worker session、event/replay、Python manifest 已验证 | sim_load_workspace 尚未真正构造核心 runtime;无完整 task state |
真实 WASM Worker 可加载最小工程并恢复 |
| M2 核心行为 | interpreter、canonical、TP、motion、kinematics | C 模块和 15 项 native CTest 通过;K0-K6 运动学切片已有 | 模块未在 sim_task 内按固定 tick 串联;完整 G/M/O 不全 |
native/WASM golden 逐 tick 对照 |
| M3 虚拟设备 | HAL/PLC/IO、Python、恢复和故障 | M3-CFG/RT/FS/PY 报告均有 verified implementation evidence | 981 资源阻断,HAL 动态组件和真实 Python remap 未全执行 | 故障矩阵、配额、重启、离线全通过 |
| M4 Web 工作流 | 控制台、工程、3D、VCP、诊断 | FE-M1..M4 smoke 已通过 | UI 目前没有完整真实 G-code/Task 状态源;OPFS/跨浏览器不足 | 关键 UI workflow 与核心状态一致 |
| M5 发布 | 全配置、兼容、oracle、浏览器、许可证、回滚 | REG-01/03/04 证据已生成但 partial | 六项 release blocker 未解除 | 全部可计入条目 accepted,STOP_RELEASE 清除 |
5. 后续任务和依赖图
5.1 正式 release 轨道
WAIT-OWNER-01 (当前 blocked)
-> OWNER-INPUT-01: 校验六项 blocker decision
-> CONTEXT-REFRESH-01: 审查并生成新 context lock
-> K8-REL-17: 重新生成 closure/audit/gate
-> 仅在 blocker 有证据解除后进入 release candidate
六项 decision 是:manifest ownership、accepted entries、official oracle、configuration resources、browser matrix、implementation license。没有外部输入时,正确动作是等待,不是自动重跑报告。
5.2 文档冲突的处理顺序
仓库中部分路线文档是在前端和 REG 任务完成前生成的,存在历史状态描述。例如 docs/linuxcnc-web-wasm-next-work.md 仍写着“没有前端应用壳”和“当前任务是 REG-01”,但 web/app、coverage/frontend-m1..m4.report.json、coverage/full-configuration-startup-matrix.report.json 已给出后续实现证据。执行时按以下优先级判断:
nextTask.md的 Current/Task/Verify/Stop 是唯一接续指针;context-lock.json是源码、工具链、schema 和版本基线;coverage/*.report.json、native/WASM/Worker 测试是实际状态证据;- 路线图、task map 和 next-work 用于理解目标和依赖,若与前三者冲突必须修正文档,而不是回退代码或重复任务。
本文件已经按这个顺序梳理;它不把旧文档中的 REG-01、FE-M1..M4 再次认领为当前任务。
5.3 技术实现轨道:第一个可执行起点
在 owner 输入和新 context 审查完成后,技术实现不应从运动学重写开始,而应从 INT-01 sim_task 固定 tick 集成 开始。它是前端、WASM 和后端融合的真正缺口。
| ID | 任务 | 主要变更 | 直接测试/产物 | 依赖 |
|---|---|---|---|---|
| INT-01 | 建立 sim_task 状态对象和 C ABI |
统一 interpreter/TP/motion/kinematics/feedback/HAL/IO/Python 引用;定义 mode、program、line、pause、abort、alarm、state hash | wasm-core/include/sim_task.h、native/WASM task test、ABI report |
M1 ABI、protocol v1 |
| INT-02 | PROGRAM_LOAD/RUN/PAUSE/RESUME/ABORT/STEP 真正执行 |
Worker workspace 文件 -> G-code 行流 -> sim_interpreter_execute;未知命令和非法模式 fail-closed,不再通用 verified |
minimal_xyz E2E、tests/interp/* 迁移结果、command golden |
INT-01、configuration resolver |
| INT-03 | TP -> IK -> motion -> FK 固定 tick | 复用 sim_kinematics_motion、feedback 和 sim_motion_queue;实现事务回滚、queue-buster、奇异/限位错误 |
motion/g0、trajectory-planner、gantry/TRT scenarios;首个差异 tick report |
INT-01/02、K0-K6 |
| INT-04 | HAL/IO/Python 进入同一 tick | 配置图实例化 HAL;设备命令由 sim_io 作为权威源;M6、主轴、探针、estop 与 Task 状态互锁 |
io-startup、toolchanger、hard-limits、remap/oword-pycall |
INT-03、M3 RT/PY |
| INT-05 | 配置资源到 runtime 的启动闭包 | 将 resolver 的 resolved rows 转成可加载 workspace;对 981 blocked rows 给出 source/line/code;处理 .var/.tbl/.ngc/.py/.xml/.hal |
REG-01 每入口 ready/blocked/error;configuration startup report |
M3-CFG、INT-01 |
| INT-06 | Python/remap/filter 真执行 | Pyodide Worker bridge 加入 session/task callback、参数、异常、时间/内存限额;宿主能力一律拒绝 | tests/remap/*、python session/replay、bridge report |
INT-02、M3-PY |
| INT-07 | 真实 OPFS 与 Worker 重启恢复 | 实现 OPFS adapter、journal commit、checkpoint、lease 和 offline cache;MemoryStorage 仅保留测试替身 | browser reload/crash/quota/offline matrix、migration/rollback report | M3-FS、INT-01 |
| INT-08 | 前端改为权威 Task snapshot | WorkerClient 增加 program/MDI/jog/override/subscribe;reducer 消费真实 snapshot/event,不用本地假状态 |
浏览器 E2E:运行/暂停/单步/报警/恢复;FE report 升级 | INT-02/04、FE-M1..M4 |
| INT-09 | 3D 轨迹和机床模型 | 由 snapshot 的 pose/joints/toolpath 驱动 Three.js;支持 axis/gantry/TRT/机器人姿态和故障可视化 | vismach samples、canvas/WebGL pixel/nonblank、性能矩阵 | INT-03、INT-08 |
| INT-10 | 全量配置启动和差异闭环 | 运行 233 entrypoints;按 ready/blocked/error 分类,不删样本;逐个关联 source/resource/component | coverage/full-configuration-startup-matrix.report.json、native/WASM/Worker summaries |
INT-05/06/07/08 |
任务顺序中,INT-01 至 INT-04 是功能主链,INT-05 至 INT-07 是运行时闭环,INT-08/09 是前端融合,INT-10 是规模化回归。任何任务都不能通过降低检查、删除 blocked 样本或把资源缺失标为 REAL-EXCLUDED 来“完成”。
6. 测试和验收办法
6.1 四层测试
| 层 | 测试内容 | 当前命令/来源 | 作用 |
|---|---|---|---|
| L0 基线 | context、source、manifest、pointer、下载索引 | validate_baseline.py、validate_task_pointer.py、脚本 unittest |
防止在错误源码或错误任务上工作 |
| L1 native C | sim_* ABI、posemath、interpreter、motion、kinematics、HAL、IO |
ctest --test-dir build-native --output-on-failure,15 项 |
算法和错误码的快速反馈 |
| L2 WASM/Worker | Emscripten exports、协议、配置/HAL preflight、设备、Python、replay/recovery | node web/worker/test_*.mjs、WASM tests |
验证浏览器运行时边界 |
| L3 浏览器/E2E | WorkerClient、命令幂等、UI 状态、OPFS、离线、3D、跨浏览器 | web/app/test_*.mjs、后续 Playwright/浏览器矩阵 |
验证用户可见工作流和恢复 |
6.2 每个功能切片的最小验收包
每个 INT/REG 任务必须同时包含:
- 一个正常案例,例如
G0 X1或 spindle start/stop; - 一个边界案例,例如重复 modal、queue full、奇异点、超速或缺资源;
- 一个错误/报警案例,例如 syntax、limit、estop、Python capability denied;
- 一个 pause/resume/abort/recovery 案例;
- 一个持久化或 Worker 重启案例(适用时);
- native 结果、WASM 结果、事件顺序、当前行、错误码、状态 hash 和首个 divergent tick。
6.3 参考命令
开始任何实现任务前执行:
python3 scripts/validate_baseline.py
python3 scripts/validate_download_index.py
python3 scripts/validate_task_pointer.py
python3 -m unittest discover -s scripts -p 'test_*.py' -v
ctest --test-dir build-native --output-on-failure
完成一个核心垂直切片后至少执行:
node web/worker/test_wasm_session.mjs
node web/worker/test_sim_session.mjs
node web/worker/test_configuration_preflight.mjs
node web/worker/test_hal_preflight.mjs
node web/worker/test_virtual_devices.mjs
node web/worker/test_workspace_session_integration.mjs
node web/app/test_frontend_m1.mjs
node web/app/test_frontend_m2.mjs
node web/app/test_frontend_m3.mjs
node web/app/test_frontend_m4.mjs
7. 当前阻塞和处理原则
| 阻塞 | 数量/现象 | 正确处理 |
|---|---|---|
| manifest seed 无 owner | 6,249 | owner assignment;不能本地猜测并升级 accepted |
| 资源闭包 | 997 missing、91 unresolved、59 unindexed、3 unregistered startup | 按 source/line 逐项补资源或经审查明确阻断;不能 basename 猜测覆盖 |
| 官方 oracle | 锁定来源缺少 linuxcnc/unit_tests/kinematics/** 和 recovery roots |
补充真实官方输入并新建 context,或由 owner 批准替代 oracle;不能把 matrixkins 冒充官方 |
| 浏览器矩阵 | context 中 Chromium/Firefox/Safari minimum 为 TBD;当前只测 Chromium | owner 锁定最低版本,执行三浏览器 workflow/offline/fault/performance |
| 实现许可证 | 57 个 Web/WASM 条目 blocked_unassigned |
完成 SPDX/NOTICE 决策;上游 LinuxCNC 许可证不能自动覆盖新实现 |
| 端到端 Task | sim_api bootstrap,Worker 未串联 interpreter/TP/IK/HAL/IO |
以 INT-01 为技术起点,先固定状态/ABI/错误回滚,再扩展功能 |
8. 任务完成定义
一个任务只有在以下条件全部满足时才能标记 verified:
- 代码、manifest/source map 和协议/ABI 变更互相可追溯;
- 正常、边界、错误、恢复测试均存在,且测试不依赖删除样本或静默降级;
- native/WASM(适用时)和 Worker/browser(适用时)结果可重复;
- snapshot、event、checkpoint、operation ledger 的状态 hash 能重建;
- 性能、内存、OPFS 配额和离线影响有记录;
- 失败时有明确 error code、source path/line、rollback point 和下一任务;
- 仍然受发布 blocker 影响的任务保持
partial/blocked,不得伪装为accepted。
项目最终完成不是“页面能点”或“15 个 CTest 全绿”,而是:任意纳入范围的 configs/sim 入口都能进入 READY 或给出可诊断的 fail-closed 错误;典型 G-code/IO/运动学/恢复场景在 native、WASM 和浏览器状态上可复现;所有来源、资源、测试、oracle、许可证和排除项都有闭合证据。