441 lines
18 KiB
Markdown
441 lines
18 KiB
Markdown
# 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` 或全功能完成。
|