# XYZAC TRT Web/WASM 源码对标与唯一权威合同 文档状态:强制实施合同 v1.0 本合同是 [`xyzac-trt-web-wasm-implementation-plan.md`](xyzac-trt-web-wasm-implementation-plan.md) 的约束性补充。它回答一个更严格的问题:Web 控制面板如何证明自己是 LinuxCNC 源码行为的 Web/WASM 等价实现,并且所有控制功能唯一来自 LinuxCNC WASM,而不是来自 React、浏览器状态或第二套 JavaScript 运动模型。 适用案例: ```text linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini ``` ## 1. 强制结论 ### 1.1 唯一权威 以下数据只能由 LinuxCNC WASM runtime 产生;React、TypeScript、Three.js、Worker UI adapter 和浏览器不能自行生成“看起来合理”的替代值: - task state、task mode、interpreter state、current line、queued MDI。 - program parse state、canonical events、trajectory queue、active segment。 - Cartesian pose、X/Y/Z/A/C 轴位置、五个 joint 位置、速度、加速度和 limits。 - XYZAC forward/inverse kinematics、switchkins type、TCP/RTCP tool compensation。 - tool table、tool offset、G43/G49/G43.1、spindle、coolant、probe、home、limit、following error。 - HAL pin/signal/parameter 读值、PyVCP state、IO ack、报警、错误和恢复结果。 - checkpoint、journal、replay、recovery endpoint 和 state hash。 前端可以拥有以下本地状态,但必须明确标记为非权威: - 编辑器 draft、搜索词、文件选择、当前 tab、camera、图层显示、窗口尺寸、pending operation。 - 尚未提交的配置表单、UI 偏好和输入法状态。 ### 1.2 严禁的替代 authority 下列行为一律视为实现失败: 1. React 根据按钮点击直接把 task/mode/position/kinematics 写成目标状态。 2. JS 根据 A/C 角度和 tool length 自行计算 X/Y/Z 补偿并展示为实际 pose。 3. JS G-code preview、Three.js preview 或 canvas 轨迹被当作 canonical motion。 4. UI 通过 `setTimeout`、墙钟、`requestAnimationFrame` 或点击次数推进仿真 tick。 5. 浏览器直接访问 WASM 指针、导出内部内存、写 OPFS journal 或调用宿主 LinuxCNC。 6. 前端绕过 Worker gateway 直接发送 HAL pin 写入、M428/M429 或模拟 IO 副作用。 7. 收不到 `COMMAND_RESULT` 时把 pending 命令当作成功,或超时后无 ledger reconcile 直接重发。 8. 把 native/AXIS 行为复制成新的 JS 状态机,再用 WASM 只做最终演示。 9. 以截图、按钮存在、模块测试或“曲线看起来一样”宣称完整五轴 parity。 10. 把 HOST_BOUNDARY、REAL-EXCLUDED、SOURCE_BLOCKED 或缺少官方 oracle 的结果改写为 verified。 ## 2. 对标单位:source behavior slice 对标的最小单位不是“页面”或“组件”,而是 source behavior slice: ```text source symbol/control → input/event/command → native state gate → LinuxCNC canonical result → status/event/visual output → error/abort/recovery behavior ``` 每个 slice 必须有唯一 `slice_id`。示例: ```text AXIS-XYZAC-AUTO-RUN AXIS-XYZAC-M428-TCP AXIS-XYZAC-JOG-C AXIS-XYZAC-HOME-JOINT-3 AXIS-XYZAC-LOAD-PROGRAM AXIS-XYZAC-VISMACH-POSE ``` ### 2.1 Slice manifest 必填字段 ```json { "slice_id": "AXIS-XYZAC-M428-TCP", "source": { "path": "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/remap_subs/428remap.ngc", "symbols": ["428remap"], "lines": "1-24", "sha256": "..." }, "inputs": ["MDI_EXECUTE:M428", "task_state", "motion.switchkins-type"], "native_commands": ["M68 E3 Q1", "M66 E0 L0"], "wasm_commands": ["MDI_EXECUTE", "KINEMATICS_SELECT"], "authoritative_outputs": ["kinematics.active_type", "state_hash"], "ui_controls": ["AXIS-RTCP-TCP-XYZAC"], "gates": ["interp_idle", "hal_pin_present", "switchkins_net_present"], "normal_cases": [], "boundary_cases": [], "error_cases": [], "recovery_cases": [], "status": "queued" } ``` 没有 source path、symbol、输入、native command、WASM command、输出、gate 和测试的功能,不得进入“实现完成”统计。 ## 3. 源码到 WASM 的闭合分层 ### 3.1 Source inventory 层 必须锁定并哈希以下来源: | 层 | 来源 | |---|---| | AXIS controls | `linuxcnc/share/axis/tcl/axis.tcl`、`support.tcl`、`accel.tcl`、`dialog.tcl`、`combobox.tcl`、`sb.tcl` | | AXIS Python | `linuxcnc/src/emc/usr_intf/axis/scripts/axis.py` | | Preview/canon | `linuxcnc/lib/python/rs274/glcanon.py`、`gremlin.py`、`vismach.py` | | Case config | `xyzac-trt.ini`、`xyzac-trt.xml`、`switchkins_postgui.hal`、`xyzac-trt.tbl`、`xyzac.var` | | Program/remap | `demos/*.ngc`、`remap_subs/*.ngc` | | Kinematics | `xyzac-trt-kins.c`、`xyzbc-trt-kins.c`、`trtfuncs.c`、`switchkins.c/h`、`kins_util.c` | | Motion/TP | `motion/command.c`、`motion/control.c`、`motion/homing.c`、`motion/motion.c`、`tp/tp.c`、`tp/tcq.c`、`tp/blendmath.c` | | Interpreter | `rs274ngc/interp_read.cc`、`interp_execute.cc`、`interp_queue.cc`、`interp_convert.cc`、`modal_state.cc` | | HAL/IO | `task/emctaskmain.cc`、`iotask/ioControl.cc`、HAL component source and `basic_sim.tcl` | Inventory 不能只记录目录;必须展开到具体文件、source hash、引用关系和运行时 fixture。生成的 `sim.var`、`position`、journal 和临时 tool table 必须单独标为 `runtime-generated-fixture`。 ### 3.2 Compat API 层 WASM 不直接向 React 暴露 C 内部函数。应建立有限、版本化的 `LinuxCncCompat`: ```text LinuxCncCompat ├── task: state/mode/interpreter/queue ├── program: load/parse/run/pause/resume/step/abort/seek ├── mdi: execute/cancel/result ├── motion: jog/home/limit/override/spindle ├── kinematics: forward/inverse/select/diagnostics ├── hal: read/write/subscribe/type-check ├── io: tool/coolant/probe/spindle ack ├── snapshot: full/delta/hash └── recovery: checkpoint/replay/reconcile ``` 每个方法必须映射到 source symbol 和固定 tick 位置;不允许添加“为了 UI 方便”的隐式状态改变。 ### 3.3 Worker protocol 层 Worker gateway 负责 schema、capability、gate、ledger、seq、operation id 和错误包装;不负责猜测 motion 结果。协议命令必须能够回到 compat API,并最终回到 WASM canonical state。 ```text UI event → WorkerClient → protocol validator → capability/gate validator → CommandLedger.prepare → LinuxCncCompat → fixed-tick WASM runtime → snapshot/event/hash → CommandLedger.commit → UI projection ``` ### 3.4 Projection 层 React reducer 只做: - 校验消息。 - 保存 authoritative snapshot/event/result。 - 派生按钮 gate、标签、错误和可视化 props。 - 保留 pending/draft/ack/reconcile 状态。 Reducer 不得: - 生成新的 motion/joint/pose。 - 依据 UI 点击顺序补齐缺少的状态。 - 在没有 Worker 快照时把按钮变为成功。 - 把 preview segment 当成 active motion segment。 ## 4. 完整功能对标登记 ### 4.1 控制面板域 以下域必须全部有 source slice;每项还要登记 menu/toolbar/button/keyboard/HAL 入口: | 域 | 最低条目 | |---|---| | Shell | title、machine name、version、about、quick reference、window/min-size、focus、tooltip | | File | open、recent、reload、save-as、properties、tool data、quit、exact path | | Machine | ESTOP、power、reset、home all、home joint、unhome、override limits、touch-off | | Mode | manual、mdi、auto、joint/world/teleop、mode denial | | Program | run、pause、resume、step、abort、restart、run-from-line、optional stop、block delete | | MDI | input、history、queue、clear、calculator、error/ack | | Jog | axis/joint selection、continuous/incremental、linear/angular speed、press/release/stop | | DRO | actual/commanded/relative/machine、G5x/G92/tool offsets、DTG、rotation | | Preview | perspective/X/Y/Z、zoom、pan/rotate、grid、rapids、tool、limits、extents、live plot、clear | | Tool | tool table、reload、tool change、tool offset、G43/G49/G43.1、manual toolchange | | Spindle/IO | direction、speed、override、brake、coolant、lube、probe、digital/analog | | HAL/PLC | HAL graph/scope/command、PyVCP、ClassicLadder/PLC state、capability denial | | Diagnostics | alarm、error、event log、command trace、snapshot diff、runtime overrun、recovery | | Case-specific | XYZAC/XYZBC type buttons、M428/M429/M430、A/C limits、RTCP offsets、Vismach clear | ### 4.2 对标登记状态 每项只能处于: ```text UNREGISTERED → SOURCE_MAPPED → WASM_IMPLEMENTED → WORKER_VERIFIED → UI_VERIFIED → PARITY_VERIFIED ``` 任意阶段失败都必须停留在对应状态并保存原因。`UI_VERIFIED` 不能越过 `WASM_IMPLEMENTED`;`PARITY_VERIFIED` 不能只用浏览器截图证明。 ## 5. 状态和 gate 的唯一实现 ### 5.1 Native gate 取证 对于每个按钮,必须从原始 AXIS/LinuxCNC 源码提取: - handler 名和绑定位置。 - 读取的 `stat`、HAL pin、INI 值和局部变量。 - 允许状态/拒绝状态。 - 发送的 command 和参数。 - command 后检查的 state。 - 错误对话框/状态栏/恢复行为。 ### 5.2 WASM gate 复现 WASM gate 只允许读取 WASM snapshot: ```text gate(action, authoritative_snapshot, capability, configuration) → { enabled, reason, required_state, source_slice_id } ``` React 可以显示 gate,但不能覆盖 gate。若 native 与 WASM gate 不同,先生成差异报告;不能在 React 中添加特殊分支“修正”显示。 ### 5.3 XYZAC 特殊 gate ```text M428/TCP = interpreter_idle && HAL_PIN_VARS && switchkins_net && finite_offsets M429/identity = interpreter_idle && HAL_PIN_VARS && switchkins_net M430/userk = interpreter_idle && userk_capability A/C jog = manual_ok && axis_enabled && angular_limits && no_fault RTCP motion = active_type == 1 && pose/joint transform verified Vismach clear = visual-only,不改变 task/motion/program/hash ``` ## 6. Native/WASM 等价证明 ### 6.1 输入冻结 每次 parity run 固定: - context id、case source hashes、browser/runtime build hash。 - INI/HAL/NGC/TBL/VAR/Python/XML exact resources。 - 程序文本、MDI 文本、按钮动作序列、固定 logical tick 数量。 - 初始 task/mode/home/tool/offset/kinematics state。 ### 6.2 Trace 规范 ```json { "slice_id": "AXIS-XYZAC-M428-TCP", "step": 7, "input": {"kind": "MDI_EXECUTE", "line": "M428"}, "native": { "task_mode": "MDI", "motion_switchkins_type": 1, "state_hash": "..." }, "wasm": { "task_mode": "MDI", "motion_switchkins_type": 1, "state_hash": "..." }, "equal": true, "first_divergent_tick": null } ``` ### 6.3 等价层级 1. **Protocol**:信封、seq、operation id、command/result/error schema。 2. **Control**:按钮 gate、模式转换、队列、取消、abort/reconcile。 3. **State**:task/interp/motion/home/limit/tool/IO/kinematics snapshot。 4. **Canonical**:canonical events、TP queue、pose/joints/toolpath。 5. **Recovery**:checkpoint、replay、endpoint hash、无重复副作用。 6. **Visual**:DRO、当前行、轨迹、A/C pose、Vismach 非空和布局。 低层级通过不能替代高层级缺口;visual 通过尤其不能替代 canonical/control 失败。 ## 7. WASM-only 前端实施拆分 ### 7.1 Runtime 完整性 WASM bundle 必须包含或明确拒绝: - RS274NGC parser/interpreter、modal state、canonical events。 - TP queue/blend/arc/helix、fixed tick。 - XYZAC/XYZBC TRT forward/inverse、tool offset、rotation points、limits。 - task/motion/home/limit/IO/tool/probe/spindle/coolant。 - remap/Python capability model(无能力时稳定拒绝)。 - snapshot/event/hash/checkpoint/recovery。 `REAL-EXCLUDED` 能力不能通过宿主 LinuxCNC fallback 伪装成 WASM 支持。 ### 7.2 Worker 完整性 Worker 必须是: - WASM runtime 的唯一调度者。 - protocol schema 和 capability 的唯一入口。 - OPFS journal/checkpoint 的唯一写者。 - command ledger 和 reconcile 的唯一实现者。 - snapshot/event/trajectory 的发布者。 Worker 不得把某些命令转给主线程 JS authority;若能力未实现,返回 `capability_unavailable`/`source_blocked`。 ### 7.3 Web 控制台完整性 React 页面必须从 `PanelSnapshotV1`/扩展快照显示: - case/configuration/source hash。 - task/mode/interpreter/kinematics state。 - gates 和 reason。 - program/line/preview/active segment。 - Cartesian pose、XYZAC joints、tool offset、A/C limits。 - HAL/IO/tool/spindle/coolant/probe/alarms。 - pending/ack/result/reconcile/recovery。 所有 button handler 只能调用 `WorkerClient`/`AxisOperationController`;禁止 `setState` 直接表示 command 已完成。 ## 8. 里程碑增强版 在原 `M0-M7` 上增加“源码唯一权威”退出条件: ### M0-SOURCE:完整 source manifest - AXIS、G-code、motion、TP、kinematics、HAL、IO、Vismach 所有功能已登记 slice。 - source hash、symbol、resource graph 和 version lock 可复现。 - unregistered count = 0;blocked count 单独报告。 ### M1-WASM-AUTHORITY:无 JS authority - 所有 task/motion/kinematics/program state 均由 WASM snapshot 产生。 - JS authority call count = 0;可以使用的 JS 只剩 projection/ledger/UI。 - 损坏/篡改 snapshot fail closed。 ### M2-CONTROL-PARITY:按钮和命令对标 - 每个 source slice 有 native/WASM button gate trace。 - 正常、拒绝、ESTOP、limit、pause、abort、reconcile 全部通过。 - gate mismatch count = 0。 ### M3-CANONICAL-PARITY:解释器、TP、运动学 - program/canonical/TP/XYZAC pose/joint/toolpath trace 一致。 - M428/M429/M430、helix、A/C 姿态和 tool offset 一致。 - first divergent tick 可定位且 verified 样本无差异。 ### M4-FRONTEND-PARITY:React/Three.js - 所有 UI controls 只消费 WASM state。 - Three.js 不重算姿态;canvas 与 snapshot hash 对账。 - DOM、keyboard/touch、错误、pending、recovery UI 通过。 ### M5-RECOVERY-PARITY:恢复和离线 - command ledger、checkpoint、journal、Worker restart endpoint 一致。 - 无重复 M-code、tool/IO side effect、trajectory segment。 - offline/OPFS quota/schema mismatch 证据完整。 ### M6-RELEASE-PARITY:严格发布门 - source slice coverage = 100%(verified + explicit blocked 分开统计)。 - native/WASM/Worker trace、hash、错误、恢复和 browser matrix 报告齐全。 - 任何外部 oracle/browser/hardware/license/owner blocker 都保持 `STOP_RELEASE`。 ## 9. 任务新增与调整 在 `xyzac-trt-web-wasm-implementation-plan.md` 的 `RTCP-00..12` 之前增加以下治理任务: ### SRC-00:AXIS/XYZAC Source Slice Inventory **输出**:`coverage/xyzac-trt-source-slice-inventory.report.json`、`web/workspace/xyzac-trt-source-slices.mjs`。 **门禁**:所有 source controls、handlers、commands、state fields、visual outputs 和 errors 有唯一 slice id;unregistered=0。 ### WASM-00:唯一权威审计 **输出**:`coverage/xyzac-trt-wasm-authority-audit.report.json`。 **门禁**:扫描 JS/TS/React/WASM bridge,证明没有 JS task/motion/kinematics authority、JS G-code execution 或 OPFS direct writer。 ### PARITY-00:Native/WASM Trace Comparator **输出**:`scripts/compare_xyzac_native_wasm_trace.py`、`web/worker/test_xyzac_trace_parity.mjs`、parity report。 **门禁**:协议、control、state、canonical、recovery 五级比较器能报告 first divergent tick,而不是只比较最终位置。 ### UI-00:Source Control Binding Audit **输出**:React control manifest、每个 control 的 source slice/gate/command/result 映射。 **门禁**:每个 button/menu/keyboard/gesture 都能追溯到 source id;每个 UI action 都通过 WorkerClient。 ### RELEASE-00:WASM-only Release Gate **输出**:`coverage/xyzac-trt-wasm-only-release-gate.report.json`。 **门禁**:WASM-only capability、source coverage、trace parity、browser matrix、recovery、错误和 blocker identity 全部审计;任何缺口都输出 `STOP_RELEASE`。 ## 10. 测试和证据规则 每个 source slice 最少包含: ```text native normal native boundary native error WASM normal WASM boundary WASM error Worker command/result UI gate projection pause/resume/abort checkpoint/recovery(适用时) deterministic state hash ``` 测试不能只调用纯 JS helper;必须运行真实 WASM module、Dedicated Worker/session、固定 logical tick 和实际 snapshot publisher。`mock` 只能用于协议单元测试,不能用于功能通过。 报告必须记录:source hash、input hash、output hash、command sequence、tick sequence、state hash、first divergent tick、error code、failure sample、environment and exclusion reason。 ## 11. 停止条件 下列任一条件出现,停止当前“完全对标”声明: - 任意功能没有 source slice 或 source hash。 - 任意程序/运动/RTCP 结果来自 JS/React/Three.js 推算。 - 任意 button gate 与 native 不一致且没有明确 source/version 差异。 - `M428/M429/M430` 没有通过 WASM remap/kinematics 状态确认。 - canonical trace 只比较最终坐标,未比较首个 divergent tick。 - recovery 可能重复 segment、M-code、tool/IO side effect。 - browser 截图通过但 Worker/WASM authority 或 state hash 未验证。 - 缺少官方 oracle、浏览器、实时硬件、OPFS crash 或 owner 输入时试图 promote release。 ## 12. 对当前项目状态的诚实结论 当前仓库已有通用 AXIS gate、Worker protocol、React reducer、Three.js workflow 和选定案例证据,但这些不能直接等同于 `xyzac-trt.ini` 的完整 WASM-only parity。按照本合同,下一步应先执行 `SRC-00` 和 `WASM-00`,再实现 `RTCP-01..12` 中的缺口;在 source slice coverage、WASM authority audit、RTCP trace parity 和 recovery 完成前,状态必须保持 `in_progress` 或 `blocked`,不能写成 `verified` 或全功能完成。