Implement AXIS parity UI and execution baseline

This commit is contained in:
2026-08-23 07:28:37 +08:00
parent 1325504544
commit 06f96f85e5
463 changed files with 84893 additions and 692 deletions

View File

@@ -0,0 +1,590 @@
# LinuxCNC AXIS 完全对标规范与执行计划
**文档状态**:执行基线 v1.0(源程序已冻结;实现和验收按任务逐项关闭)
**适用版本**:LinuxCNC `2.10.0~pre0` 239dcf4284762ad7e9c65d390bc5524d855c2f8e
**项目上下文**:`linuxcnc-2.10.0-pre0-wasm-m1-py-c1`
**主入口**:[`web/react`](../web/react)
**原始 AXIS 入口**:[`linuxcnc/share/axis/tcl/axis.tcl`](../linuxcnc/share/axis/tcl/axis.tcl)
**配套通信契约**:[前端与通信详细设计](linuxcnc-web-wasm-frontend-communication-design.md)
**配套案例契约**:[案例对标计划](linuxcnc-web-wasm-case-parity-plan.md)
本文件是“Web 主界面完全对标 LinuxCNC 原始 AXIS”的唯一执行规范。它把原始 AXIS 的功能、界面结构、状态门控、快捷键、图标、绘图和外部集成拆成可追溯任务;没有来源、命令序列、状态结果和验收证据的功能,不得标记为完成。
## 1. 目标、定义和边界
### 1.1 对标目标
对标不是把网页做成相似的深色控制台,而是对同一配置、同一程序、同一输入序列满足以下四类等价:
1. **结构等价**:菜单、工具栏顺序、Notebook、程序区、DRO、状态栏、控制件和图标的角色与布局对应 AXIS。
2. **操作等价**:同一用户动作发出同一 LinuxCNC 语义命令,按相同状态条件启用、禁用、暂停、恢复或拒绝。
3. **状态等价**:任务态、解释器态、模式、轴/关节选择、位置显示、倍率、主轴、工具、冷却、报警和恢复结果来自同一权威状态,事件顺序和当前行一致。
4. **结果等价**:native AXIS oracle 与 WASM/Worker 的 command trace、tick、快照、事件、错误和 checkpoint 哈希一致;允许的浮点误差必须在功能条目中明确,不能事后放宽。
### 1.2 规范性术语
| 词 | 含义 |
|---|---|
| MUST | 必须满足,否则该条目失败 |
| MUST NOT | 严禁发生,否则停止验收 |
| SHOULD | 默认要求;若不满足必须记录理由和影响 |
| source oracle | 锁定 LinuxCNC 源码、原始 AXIS 运行或其确定性输出 |
| Web-equivalent | 浏览器中实现相同工作流和状态语义的等价控件,不复制桌面窗口进程 |
| host boundary | 原始程序依赖宿主进程、动态库、真实设备或外部窗口的边界;必须显式显示为 blocked/excluded |
| verified | 代码、测试、native/WASM/Worker 证据、视觉证据和自哈希报告均通过 |
| blocked | 输入、官方 oracle、浏览器能力或宿主边界不足;保留失败样本,不得伪造 verified |
### 1.3 明确边界
- LinuxCNC 原始 AXIS 是 Tk 前端;Web 采用 React/TypeScript/Worker/Three.js,实现的是 **Web-equivalent**,不是复制 Tk 窗口或在浏览器启动桌面进程。
- `exec classicladder`、`halshow`、`halmeter`、`halscope`、`linuxcnctop`、`debuglevel`、外部编辑器、真实硬件和原始 socket 不得伪装为浏览器已支持;用 Web 面板或 `HOST_BOUNDARY` 诊断替代。
- WASM、HAL、IO、Python、OPFS 和快照的权威状态在 Dedicated Worker;React 只能通过协议读写,不得访问 WASM 指针或直接写 OPFS。
- 原始图标必须使用锁定源码中的字节;重新绘制、emoji、通用 icon 库或不同来源的同名图标不算对标。
- 所有视觉结论必须在固定视口、固定字体/缩放和固定资源哈希下产生;动态 canvas 区域单独做像素/非空检查,不得用“截图看起来差不多”替代 DOM 和行为检查。
## 2. 锁定的 AXIS 源程序和证据入口
### 2.1 源文件分工
| 领域 | 原始来源 | 对标内容 |
|---|---|---|
| 主窗口、菜单、工具栏、Notebook、控件门控 | [`share/axis/tcl/axis.tcl`](../linuxcnc/share/axis/tcl/axis.tcl) | 全部主界面结构、动作、启用条件、快捷键和默认变量 |
| 图标加载、动态帮助、控件辅助函数 | [`share/axis/tcl/support.tcl`](../linuxcnc/share/axis/tcl/support.tcl)、[`accel.tcl`](../linuxcnc/share/axis/tcl/accel.tcl) | 资源解析、tooltip、菜单/控件 accelerator |
| 自定义下拉、滚动条、对话框 | [`share/axis/tcl/combobox.tcl`](../linuxcnc/share/axis/tcl/combobox.tcl)、[`sb.tcl`](../linuxcnc/share/axis/tcl/sb.tcl)、[`dialog.tcl`](../linuxcnc/share/axis/tcl/dialog.tcl) | Jog increment、MDI history、文件和错误对话框的交互语义 |
| AXIS 设计说明 | [`src/emc/usr_intf/axis/README`](../linuxcnc/src/emc/usr_intf/axis/README) | AXIS 的定位是 file preview + live plot;自解释控件、tooltip 和 Quick Reference |
| 3D/预览窗口 | [`lib/python/gremlin.py`](../linuxcnc/lib/python/gremlin.py)、[`gremlin_view.py`](../linuxcnc/lib/python/gremlin_view.py) | 视角、缩放、拖动/旋转、预览加载、live plot、当前行和绘图刷新 |
| G-code 绘图和坐标叠加 | [`lib/python/rs274/glcanon.py`](../linuxcnc/lib/python/rs274/glcanon.py) | rapid、path、dwell、tool、origin、offset、extents、grid、limits、velocity、DTG |
| 配置声明和 GUI 家族 | [`configs/sim/axis`](../linuxcnc/configs/sim/axis) | DISPLAY=axis、PYVCP/GLADEVCP/NGCGUI/VisMach/外部脚本及资源闭包 |
| 原始 bitmap | [`share/axis/images`](../linuxcnc/share/axis/images) | AXIS logo、toolbar、spindle、标准报警图标、banner |
本文中的 `axis.tcl:N-M` 是 [`linuxcnc/share/axis/tcl/axis.tcl`](../linuxcnc/share/axis/tcl/axis.tcl) 的行号简写;`gremlin.py` 和 `glcanon.py` 同理分别指上表中的完整路径。
### 2.2 源哈希和变更规则
基线文件的初始 SHA-256 记录如下;每次源更新必须重新生成 manifest 和本文件引用,不得沿用旧报告:
```text
share/axis/tcl/axis.tcl c9f0b4dc686717b37565f85fb0ab8cc8ded9cfa0028cc0aaaccdbcf808c4c524
lib/python/gremlin.py 7559a52300de92ed156fe22267c8fbca975338321cf3afada141360a244756a3
lib/python/rs274/glcanon.py 0dfb20f1fdc05289894f3aa638357d98e1063fbd53329c723c777399ec7b33b7
src/emc/usr_intf/axis/README 2fe357ba28bb0aa66565f85fb0ab8cc8ded9cfa0028cc0aaaccdbcf808c4c524
```
若报告发现文件内容与上述哈希不一致,先修正文档/manifest,再开始实现。源码树中由运行时生成的 `tool.tbl`、`sim.var`、`linuxcnc.var` 必须标明是 `source-owned` 还是 `runtime-generated-fixture`,不可混用。
## 3. AXIS 原始功能完整清单
功能 ID 是后续任务、协议、测试和验收报告的稳定主键。每个 ID 至少绑定一条源码路径、一个 Web 控件、一个命令/查询、一个状态字段和一份 evidence。
### 3.1 应用壳、菜单和窗口
| ID | 原始功能 | 原始实现/行 | Web 对标要求 |
|---|---|---|---|
| AXIS-SHELL-01 | 窗口标题 `AXIS <version> on <machine>`,无文件时显示 `(no file)`,有文件时显示文件名 | `axis.tcl:1755-1765` | 根据 Worker 的 machine/taskfile 快照更新标题;标题更新不能改变仿真状态 |
| AXIS-SHELL-02 | 顶级菜单 File、Machine、View、Help | `axis.tcl:33-53,468-482` | 顺序、命名、子菜单、快捷键和 enabled 状态一致;菜单项必须有可测试的 `data-axis-command` |
| AXIS-SHELL-03 | 最小窗口尺寸随 pane 请求尺寸更新 | `axis.tcl:2234-2240` | CSS 使用稳定最小尺寸和滚动策略;窄屏切换布局,不能让高风险按钮被裁掉 |
| AXIS-SHELL-04 | About AXIS、Quick Reference 对话框 | `axis.tcl:453-464,1549-1632` | Web modal 保留版本、许可证、源码链接、快捷键和关闭/焦点语义;外部链接另标记 host/network boundary |
| AXIS-SHELL-05 | 动态帮助 tooltip | `axis.tcl:2250-2270`、`accel.tcl:150-185` | 所有图标按钮的 tooltip 文案、快捷键和 disabled 原因可通过 DOM/辅助技术读取 |
### 3.2 File 菜单和工程入口
原始菜单定义位于 `axis.tcl:55-102`。Web 实现必须保留以下条目和顺序:
| ID | 菜单项 | 语义 |
|---|---|---|
| AXIS-FILE-01 | Open… (`O`) | 选择 G-code,解析、预览并进入 `PROGRAM_LOAD`; 不允许 basename 替换 |
| AXIS-FILE-02 | Recent Files | 最近文件列表、序号快捷键、清空列表;路径/哈希来自 Worker 工程存储 |
| AXIS-FILE-03 | Edit… | 以配置声明的 editor 或 Web G-code editor 打开;宿主 editor 必须显示 `HOST_BOUNDARY` |
| AXIS-FILE-04 | Reload (`Ctrl-R`) | 仅在解释器 idle 且有 taskfile 时启用;重新读取精确资源 |
| AXIS-FILE-05 | Save G-code as… (`Ctrl-S`) | 保存当前内容/版本,写 journal,返回文件哈希 |
| AXIS-FILE-06 | Properties… | 显示程序路径、大小、行数、解析诊断、单位和 source hash |
| AXIS-FILE-07 | Edit tool data… | Web tool table editor;原始 `tooledit` 外部窗口标为 boundary |
| AXIS-FILE-08 | Reload tool data | 重新加载工具表并显示 table hash、当前刀、prepared/pocket |
| AXIS-FILE-09 | Ladder Editor… | Web ClassicLadder 面板;无法运行宿主 editor 时不得静默忽略 |
| AXIS-FILE-10 | Quit | 浏览器不能关闭宿主窗口;显示“关闭标签页”提示并记录 `WEB_EQUIVALENT` |
### 3.3 Machine 菜单和任务控制
原始定义位于 `axis.tcl:105-264`。下列条目是 P0/P1,不得只保留 Run/Pause:
| ID | 功能 | 关键语义 |
|---|---|---|
| AXIS-MACHINE-01 | Toggle Emergency Stop (`F1`) | `ESTOP` 状态机;急停时禁止运动/IO,界面进入 pressed/fault,恢复必须有独立 `IO_RECOVER`/reset 结果 |
| AXIS-MACHINE-02 | Toggle Machine Power (`F2`) | task state OFF/ON;按钮 relief 与状态一致,不能把 recover 当作已上电 |
| AXIS-MACHINE-03 | Run program (`R`) | 仅 task ON、程序有效、解释器 idle 时启用;返回当前行、interp state、tick |
| AXIS-MACHINE-04 | Run from selected line | 以选中行建立确定性 seek/预读语义;没有选中行必须 disabled |
| AXIS-MACHINE-05 | Step (`T`) | 只执行下一行/下一 canonical 单元;记录 line before/after 和状态 hash |
| AXIS-MACHINE-06 | Pause (`P`) / Resume (`S`) | 只在对应 interp state 启用;pause 图标切换 `tool_pause`/`resume_inhibit` |
| AXIS-MACHINE-07 | Stop (`Esc`) | 中止程序而不是销毁 session;queue、tool、spindle、IO 和恢复点结果必须明确 |
| AXIS-MACHINE-08 | Stop at M1 | `optional_stop` checkbutton/toolbar relief 与 M1 行为一致 |
| AXIS-MACHINE-09 | Skip lines with `/` | `block_delete` checkbutton/toolbar relief 与程序过滤语义一致 |
| AXIS-MACHINE-10 | MDI history clear/copy/paste | `Ctrl-M`、`Ctrl-H`、`Ctrl-Shift-H`;历史只在 Worker committed state 中更新 |
| AXIS-MACHINE-11 | Calibration | 原始 `emccalib.tcl` 是外部窗口;Web 提供能力诊断或 boundary,不得模拟完成 |
| AXIS-MACHINE-12 | Show HAL Configuration / HAL Meter / HAL Scope | 分别映射 HAL graph、HAL sample/plot、scope;原始外部窗口路径保留诊断 |
| AXIS-MACHINE-13 | Show LinuxCNC Status / Set Debug Level | 映射状态时间线、日志和 debug level 白名单;未经授权的 level 必须拒绝 |
| AXIS-MACHINE-14 | Homing / Unhoming | 动态子菜单按轴/关节生成;顺序、homed、limit、门控和错误一致 |
| AXIS-MACHINE-15 | Zero coordinate system | P1…P9/G54…G59.3/G92 全部入口;每次写入显示坐标系、旧值、新值和 hash |
| AXIS-MACHINE-16 | Tool touch off to workpiece/fixture | `tto_g11` 两种模式;选择影响 G10/G11 语义并在快照中可见 |
### 3.4 View 菜单、DRO 和坐标显示
原始定义位于 `axis.tcl:266-449`。View 菜单必须拆成可验证状态,不得只做文字菜单:
| ID | 功能 | 状态字段/输出 |
|---|---|---|
| AXIS-VIEW-01 | Top / Rotated Top / Side / Front / Perspective | `view_type`、camera pose、视角图标 relief;对应 `set_view_z/z2/x/y/p` |
| AXIS-VIEW-02 | Display Inches / Display MM | `metric`;DRO、速度、倍率单位同步;切换不改机床内部单位 |
| AXIS-VIEW-03 | Show program | program path overlay 开关 |
| AXIS-VIEW-04 | Show program rapids | rapid segments 是否显示 |
| AXIS-VIEW-05 | Alpha-blend program | program overlay alpha |
| AXIS-VIEW-06 | Show live plot | 已运行轨迹与预览轨迹分层;clear 不得删除程序预览 |
| AXIS-VIEW-07 | Show tool | tool cone/model、tool position、orientation |
| AXIS-VIEW-08 | Show extents | program/machine extents bounding box |
| AXIS-VIEW-09 | Grid Off/Custom | grid size、origin、spacing 和自定义参数 |
| AXIS-VIEW-10 | Show offsets | G5x/G92/tool offset 可视化和数值 |
| AXIS-VIEW-11 | Show machine limits | axis/joint limits overlay 和 limit fault |
| AXIS-VIEW-12 | Show velocity | velocity vector/数值;来源为 snapshot,不使用墙钟推算 |
| AXIS-VIEW-13 | Show distance to go | DTG 与 commanded/actual、machine/relative 模式联动 |
| AXIS-VIEW-14 | Large coordinate font | DRO 字号开关,布局必须稳定 |
| AXIS-VIEW-15 | Clear live plot (`Ctrl-K`) | 仅清 live layer,返回新 plot revision |
| AXIS-VIEW-16 | Show PyVCP panel (`Ctrl-E`) | 配置声明 `PYVCP` 时显示 Web VCP;缺少 host plugin 时显示 boundary |
| AXIS-VIEW-17 | Show commanded/actual position | `display_type`,DRO 与状态栏同源 |
| AXIS-VIEW-18 | Show machine/relative position | `coord_type`,DRO 与触碰/坐标系同源 |
| AXIS-VIEW-19 | Joint mode / World mode | `teleop_mode`;非平凡 kinematics 未全 homed 时禁止切换到 world |
### 3.5 AXIS 工具栏和图标对照表
原始工具栏从 `axis.tcl:484-787` 创建并按 `671-787` 顺序 pack。图标文件必须来自 [`linuxcnc/share/axis/images`](../linuxcnc/share/axis/images):
| 序号 | 原始 widget | 图标 | 原始动作 | Web 对标 |
|---:|---|---|---|---|
| 1 | `machine_estop` | `tool_estop.gif` | `estop_clicked` | icon-only button,tooltip `Toggle Emergency Stop [F1]` |
| 2 | `machine_power` | `tool_power.gif` | `onoff_clicked` | task power 状态,初始 disabled/relief 与 oracle 一致 |
| 3 | `file_open` | `tool_open.gif` | `open_file` | 精确资源选择 + `PROGRAM_LOAD` |
| 4 | `reload` | `tool_reload.gif` | `reload_file` | reload gate |
| 5 | `program_run` | `tool_run.gif` | `task_run` | run gate |
| 6 | `program_step` | `tool_step.gif` | `task_step` | step gate |
| 7 | `program_pause` | `tool_pause.gif` / `resume_inhibit.gif` | `task_pauseresume` | pause/resume 图标切换 |
| 8 | `program_stop` | `tool_stop.gif` | `task_stop` | stop/abort gate |
| 9 | `program_blockdelete` | `tool_blockdelete.gif` | `toggle_block_delete` | pressed state + 程序语义 |
| 10 | `program_optpause` | `tool_optpause.gif` | `toggle_optional_stop` | pressed state + M1 语义 |
| 11 | `view_zoomin` | `tool_zoomin.gif` | `zoomin` | camera scale |
| 12 | `view_zoomout` | `tool_zoomout.gif` | `zoomout` | camera scale |
| 13 | `view_z` | `tool_axis_z.gif` | `set_view_z` | top camera |
| 14 | `view_z2` | `tool_axis_z2.gif` | `set_view_z2` | rotated top camera |
| 15 | `view_x` | `tool_axis_x.gif` | `set_view_x` | side camera |
| 16 | `view_y` | `tool_axis_y.gif` | `set_view_y` | front camera |
| 17 | `view_y2` | `tool_axis_y2.png` | `set_view_y2` | inverted front camera |
| 18 | `view_p` | `tool_axis_p.gif` | `set_view_p` | perspective camera |
| 19 | `rotate` | `tool_rotate.gif` | toggle drag/rotate | pressed state and pointer gesture |
| 20 | `clear_plot` | `tool_clear.gif` | `clear_live_plot` | live layer only |
验收必须检查:文件名、字节 hash、实际加载 URL、`alt`/tooltip、按钮顺序、disabled/pressed relief 和点击后的命令。QtVCP 同名镜像只能用于历史兼容,不得作为 AXIS source oracle。
### 3.6 Manual Control Notebook
原始布局在 `axis.tcl:803-1213`,默认页为 `Manual Control [F3]`:
| ID | 控件 | 必须保留的行为 |
|---|---|---|
| AXIS-MANUAL-01 | 轴选择 X/Y/Z/A/B/C/U/V/W | 3×3 radio;`axis_activated`;非平凡运动学切换为动态 joint numbers |
| AXIS-MANUAL-02 | Jog `-`/`+` | 增量模式 click 一次;Continuous 模式 pointer/key down 开始、release/leave 必须 `JOG_STOP` |
| AXIS-MANUAL-03 | Jog increment | `Continuous`, `0.1000`, `0.0100`, `0.0010`, `0.0001`;选择变化进入命令 payload |
| AXIS-MANUAL-04 | Home Axis | 当前轴/关节 home;Home 键快捷键;结果更新 homed/limit/position |
| AXIS-MANUAL-05 | Touch Off | G54 当前轴;End 快捷键;保存坐标系结果 |
| AXIS-MANUAL-06 | Tool Touch Off | Ctrl-End;只在有加载工具且模式允许时启用 |
| AXIS-MANUAL-07 | Override Limits | 只在 `on_any_limit` 时启用;临时越限必须有 fault/recover trace |
| AXIS-MANUAL-08 | Spindle CCW/Stop/CW | `spindledir` radio、16×16 原始图标、F10/F9;Stop 文案必须可读 |
| AXIS-MANUAL-09 | Spindle -/+ | 按下加速/减速、释放进入 constant;F11/F12;主轴未运行时 disabled |
| AXIS-MANUAL-10 | Brake | B/Shift-B;状态和互锁可见 |
| AXIS-MANUAL-11 | Mist/Flood | F7/F8;冷却状态、故障和恢复来自 device IO |
| AXIS-MANUAL-12 | Jog Speed/Max Velocity | 来源为 `jog_slider_val`/`maxvel_slider_val`,单位随 metric,显示值和内部速度转换一致 |
### 3.7 MDI Notebook
原始布局在 `axis.tcl:1215-1294`:History listbox、MDI Command entry、Go 按钮。Web 必须支持:
- 历史最多/最少行为与 Worker 的 `mdi_history` 一致,初始有空元素,不把草稿历史当已执行。
- Enter 与 Go 相同,发送 `MDI_EXECUTE`,返回 command result、当前行、模式和错误行。
- `queued_mdi_commands >= max_queued_mdi_commands` 时整个 MDI group disabled(`axis.tcl:1851-1855`)。
- `Ctrl-M` 清历史,`Ctrl-H` history→clipboard,`Ctrl-Shift-H` clipboard→history;浏览器 clipboard 权限失败必须显式诊断。
### 3.8 Preview、DRO、程序和状态栏
原始布局在 `axis.tcl:1296-1709`:
| 区域 | 原始行为 | Web 必须实现 |
|---|---|---|
| Preview tab | Gremlin/GLCanon 预览、程序/rapid/live/tool/extents/offset/grid/limit/velocity overlays | Three.js/WebGL 只消费 Worker snapshot/trajectory;每层可独立开关,canvas 必须非空 |
| DRO tab | 原始 AXIS DRO widget;显示 machine/relative、actual/commanded、DTG、单位、关节态 | 表格列和模式可切换;数值、单位、homed、limit、fault、tick/hash 同源 |
| `.info.task_state` | ESTOP/OFF/ON,sunken relief | `task_state` 颜色/状态必须由快照驱动 |
| `.info.tool` | 当前刀具/工具信息 | current/prepared/pocket/change state 和 tool table hash |
| `.info.position` | Position + coordinate type + display type | `Machine/Relative` 与 `Actual/Commanded` 组合准确 |
| G-code pane | 有滚动条、当前行/highlight、底部固定 pane | 编辑/选行/运行到选中行/错误定位;不能使用静态 `<pre>` 冒充 |
| Active G-Codes | `gcodes` text,disabled、2 行起步 | modal codes、units、plane、feed/spindle/tool/coolant 同步 |
| Jog sliders | `jogspeed`、`ajogspeed`、`maxvel`,值通过 `setval/val2vel` 转换 | 显示值与内部单位、min/max、metric 切换、键盘增量一致 |
| Overrides | `spinoverride`、`feedoverride`、`rapidoverride`,0…120%、整数分辨率 | worker authoritative override;滑块 release/commit 和 pending/error 可见 |
### 3.9 状态门控、默认状态和快捷键
`axis.tcl:1715-1887` 是行为对标的核心,不得只按按钮标签实现。门控规则:
1. `ESTOP` 时 machine power、程序、jog、主轴、冷却等高风险动作禁用;estop relief 按下。
2. task 非 ON 时 manual group disabled;task ON 且 interpreter idle 时才 enable manual group。
3. 有 taskfile 且 idle 才能 reload、edit、properties、open、block-delete;有 taskfile 且 ON 才能 step。
4. interpreter reading/waiting 才能 Pause;paused 才能 Resume;非 idle 才能 Stop。
5. `on_any_limit` 才能启用 Override Limits;非自由运动学或 identity kinematics 且 idle 才能 Touch Off。
6. 有有效工具、task ON、idle、模式允许时才能 Tool Touch Off。
7. MDI queue 未满才启用 MDI group。
8. 非平凡 kinematics 的自由/joint 模式显示 joint numbers;没有全 homed 不能从 joint 切换到 world。
默认变量见 `axis.tcl:1941-1985`,至少包含 `rotate_mode`、`taskfile`、`task_state`、`task_mode`、`task_paused`、`optional_stop`、`block_delete`、`interp_pause`、`interp_state`、`running_line`、`highlight_line`、`coord_type`、`display_type`、`spindledir`、`motion_mode`、`kinematics_type`、`metric`、`queued_mdi_commands`。Web store 必须有等价字段或明确映射,不能删除门控原因。
快捷键基线:
| 键 | 功能 | 来源 |
|---|---|---|
| F1/F2 | 急停/电源 | `axis.tcl:105-113` |
| O/Ctrl-R/Ctrl-S | Open/Reload/Save | `axis.tcl:55-76` |
| R/T/P/S/Esc | Run/Step/Pause/Resume/Stop | `axis.tcl:117-144` |
| Ctrl-M/Ctrl-H/Ctrl-Shift-H | MDI history | `axis.tcl:158-169` |
| Ctrl-K/Ctrl-E | Clear live plot/Show PyVCP | `axis.tcl:378-387` |
| F3/F5 | Manual/MDI tab | `axis.tcl:820-825` |
| Home/End/Ctrl-End | Home/Touch Off/Tool Touch Off | `axis.tcl:2258-2260` |
| F7/F8/F9/F10/F11/F12 | Mist/Flood/Spindle/速度 | `axis.tcl:2250-2257` |
| X/Y/Z/A/4/5 | 轴激活 | `axis.tcl:2261-2266` |
| Ctrl-Tab | Manual/MDI 切换 | `axis.tcl:1989-1996` |
## 4. LinuxCNC 源功能到 Web 实现的映射
### 4.1 分层映射原则
| 原始层 | Web 层 | 强制规则 |
|---|---|---|
| Tk widget/variable | React component + domain store | 控件可以换实现,字段名、启用条件、事件顺序不能换 |
| AXIS command procedure | protocol command | 每个副作用动作有 `operation_id`、pending/ack/result/error、tick/hash |
| LinuxCNC status/NML | Worker snapshot/event | UI 不可读取指针、共享内存或宿主 NML |
| Gremlin/GLCanon | Three.js visual workflow | 只读 pose/joints/toolpath/stock/overlay;渲染失败不能改变仿真 |
| Tcl external exec | Web panel or host boundary | 不可静默成功;必须有 capability result 和 source path |
| Tk image | exact bitmap URL | 记录字节 hash,禁止同名替换 |
| `state`/`relief` | `disabled`/`aria-pressed`/visual state | 状态由 authoritative snapshot 派生,不能由点击乐观设置 |
### 4.2 推荐组件和协议字段
```text
AxisShell
├─ AxisMenuBar File / Machine / View / Help
├─ AxisToolbar exact source icons, order and tooltip
├─ AxisNotebook
│ ├─ ManualControl axis/joint, jog, home, touch-off, spindle, coolant
│ └─ MDIControl history, command, go, queue gate
├─ ViewNotebook
│ ├─ Preview Three.js/trajectory/overlays
│ └─ DRO machine/relative × actual/commanded × DTG
├─ ProgramPane source, line selection, current line, active G-codes
├─ OverridePane feed/rapid/spindle/jog/max velocity
└─ AxisInfoBar task state, tool, position, alarm/recovery
```
最低命令集合:`PROGRAM_LOAD`, `PROGRAM_RUN`, `PROGRAM_SEEK`, `PROGRAM_STEP`, `PROGRAM_PAUSE`, `PROGRAM_RESUME`, `PROGRAM_ABORT`, `MDI_EXECUTE`, `JOG_START`, `JOG_STOP`, `HOME`, `SET_MODE`, `SET_OVERRIDE`, `SPINDLE_COMMAND`, `COOLANT_COMMAND`, `TOOL_PREPARE`, `TOOL_CHANGE`, `PROBE_CONFIG`, `ESTOP`, `IO_RECOVER`, `HAL_COMMAND`, `SNAPSHOT_REQUEST`, `CHECKPOINT`, `RECOVER`。新增命令必须先更新 protocol capability、source map、replay fixture 和本规范任务表。
## 5. 严格对标流程
每个 AXIS 功能 ID 都必须独立走完以下流程;不允许把多个功能合并成一张“整体通过”截图。
### R0:冻结基线
1. 读取 `context-lock.json`、`linuxcnc/VERSION` 和 source commit。
2. 计算源文件、图标、配置入口、HAL、TBL/VAR、程序和生成资源 hash。
3. 记录 OS、浏览器、DPR、viewport、字体、语言、单位和启动参数。
4. 若输入有未提交 runtime fixture,先分类 `source-owned`/`runtime-generated`/`user-approved-fixture`。
**退出条件**:source manifest、asset manifest、case manifest、运行环境 JSON 均 self-hashed;否则 STOP。
### R1:提取原始功能
1. 从 `axis.tcl` 的 menu/widget/proc/bind/state 定义生成 `axis-source-inventory.jsonl`。
2. 从 `support.tcl`、`accel.tcl`、`gremlin.py`、`glcanon.py` 提取依赖动作、tooltip、视觉层和状态字段。
3. 每个条目填写 `feature_id`, `source_path`, `source_lines`, `source_hash`, `ui_role`, `command`, `state_fields`, `external_boundary`。
4. 把源代码中实际未实现/历史 wishlist 与当前功能分开,不把 wishlist 当现状。
**退出条件**:功能 ID 覆盖菜单、工具栏、Notebook、DRO、程序、状态、快捷键、图形和外部集成;任何未归属文件进入 audit 缺口。
### R2:建立协议和状态契约
1. 为每个命令定义输入 schema、能力条件、幂等键、成功结果、错误码和恢复语义。
2. 为每个 UI 状态定义 authoritative snapshot 字段、派生选择器和 enabled predicate。
3. 固定 `pending → ack → result/error`;ACK 不得被渲染为 verified。
4. 录制最小 native trace:启动、加载、动作、step、快照、错误、恢复。
**退出条件**:同一操作可在 Worker replay 中重放;未定义的门控或错误不得进入 UI 实现。
### R3:实现结构和图标
1. 先实现 AXIS shell 和稳定布局,再接入动作;禁止用临时卡片替代原始区域。
2. 按原始 pack 顺序加载 20 个 toolbar 图标,记录每个文件 byte hash、尺寸和 URL。
3. 实现 File/Machine/View/Help 菜单和 Notebook;所有菜单 item 带稳定测试 ID。
4. 对 canonical 1440×900、1280×800、390×844 截图并做 DOM geometry 检查。
**退出条件**:结构 diff 只剩有记录的字体/平台边界;工具栏顺序和 icon hash 100% 一致。
### R4:实现控制和门控
1. 先实现 ESTOP/OFF/ON/idle/reading/waiting/paused/limit/not-homed 状态转换。
2. 再接 program/MDI/jog/home/touch-off/spindle/coolant/override。
3. 每个 pointer/key 事件测试按下、移动、离开、释放、重复触发和 Worker 重启。
4. 每个 disabled 状态测试“为什么 disabled”:UI 显示 source state、predicate 和 capability。
**退出条件**:状态矩阵的每一格都有 command trace 或明确 blocked 证据;没有基于本地 `useState` 的假成功。
### R5:实现预览、DRO 和编辑器
1. G-code load 后先产生解析/预览结果,再允许 run;程序预览、rapid、live plot、tool、offset、limits、grid 分层。
2. DRO 实现 machine/relative、actual/commanded、DTG、unit、joint/world、large font。
3. G-code editor 支持行号、当前行、高亮、选中行运行、错误列、滚动和程序 hash。
4. 3D canvas 检查非空像素、有限坐标、视角、缩放、旋转和 resize;绘图线程不得改仿真 tick。
**退出条件**:同一 native/WASM trace 的当前行、DRO、path layer、tool pose、状态 hash 相同。
### R6:案例和外部边界
1. `minimal_xyz.ini`:关闭 Cartesian P0 核心闭环。
2. `corexy_by_kins.ini` 与 `corexy_by_hal.ini`:分别验证 kinematics/HAL 路径。
3. lathe、9-axis、gantry、nontrivial kinematics、iocontrolv2、vismach、PYVCP/GLADEVCP/NGCGUI 代表案例按 family 扩展。
4. 每个 DISPLAY/插件声明都输出 Web capability、host boundary 和缺失资源;不能把外部 Python/Tk/动态 loader 当作浏览器已完成。
**退出条件**:每个案例有 exact resource graph、native startup、Worker startup、frontend mapping、差异和 self-hashed report。
### R7:视觉、交互和故障验收
1. DOM:区域、顺序、role、label、tooltip、快捷键、禁用/pressed、焦点顺序。
2. Screenshot:canonical viewport 的结构区域、工具栏顺序、icon byte/尺寸、颜色/边框、文字和间距。
3. Interaction:每个 command 的操作序列、pending/ack/result、错误和恢复。
4. Fault:ESTOP、limit、following error、invalid G-code、HAL blocked、tool busy、OPFS quota、Worker crash/restart。
5. Performance:首屏、Worker ready、snapshot latency、3D frame、stream backpressure、内存和长程序编辑器。
**退出条件**:报告包含失败截图/DOM/trace,而不是只有通过计数;任何 STOP 条件未关闭则 milestone 保持 blocked。
### R8:发布门禁
- `source_hash`, `asset_hash`, `case_hash`, `command_trace_hash`, `endpoint_hash`, `screenshot_hash` 全部可复现。
- native、WASM、Worker、React、浏览器矩阵版本和运行参数明确。
- host boundary、REAL-EXCLUDED、缺资源、官方 oracle 缺失和浏览器不支持分开统计。
- 不以“实现存在”“构建通过”替代行为或视觉验收。
- 报告自哈希失败、首个 divergent tick 未定位、恢复重复副作用、真实硬件误报或降低检查才能通过时立即 `STOP_RELEASE`。
## 6. 任务分解
任务状态初始为 `planned`。每个任务完成时必须提交代码、专属测试和 self-hashed evidence;依赖未完成不得跳过。
| 任务 ID | 任务 | 具体输出 | 依赖 | 专属验收 |
|---|---|---|---|---|
| AXIS-INV-01 | 冻结 AXIS 源 | source/version/environment manifest | 无 | R0 manifest hash |
| AXIS-INV-02 | 生成 Tcl UI inventory | menu/widget/proc/bind/state JSONL | INV-01 | 每行 source path/line/hash |
| AXIS-INV-03 | 生成 bitmap inventory | 20 toolbar + logo/spindle/std icon hash/size | INV-01 | byte hash、URL、尺寸一致 |
| AXIS-INV-04 | 生成 AXIS case inventory | `configs/sim/axis` exact graph + DISPLAY family | INV-01 | 无 basename substitution |
| AXIS-CON-01 | 状态枚举契约 | task/interp/motion/mode/coordinate/override/device schema | INV-02 | reducer/state contract tests |
| AXIS-CON-02 | 命令和 ledger 契约 | command schema、idempotency、ack/result/error | CON-01 | duplicate/replay/cancel tests |
| AXIS-CON-03 | 门控谓词契约 | `state()`/`relief()` 的 Web selector | CON-01 | 全状态矩阵覆盖 |
| AXIS-CON-04 | 诊断和 boundary 契约 | host/Python/loader/real hardware 分类 | CON-02 | blocked 不得伪造成功 |
| AXIS-UI-01 | AXIS shell | title、menu、main panes、responsive root | INV-02 | DOM geometry + screenshot |
| AXIS-UI-02 | File menu | Open/Recent/Edit/Reload/Save/Properties/tool/ladder/Quit | UI-01, CON-02 | menu order + command trace |
| AXIS-UI-03 | Machine menu | task controls、history、diagnostics、homing、offset、touch-off | UI-01, CON-03 | state-gated menu matrix |
| AXIS-UI-04 | View menu | views、units、overlays、DRO、grid、teleop | UI-01, CON-01 | setting round-trip + screenshot |
| AXIS-UI-05 | Exact toolbar | 20 icons、顺序、tooltip、pressed/disabled | INV-03, UI-01 | asset and DOM hash |
| AXIS-UI-06 | Notebook shell | Manual/MDI、Preview/DRO tabs,焦点/快捷键 | UI-01 | tab switching/no reinit |
| AXIS-UI-07 | Info/program panes | task/tool/position、G-code、active G-codes、scroll | UI-06, CON-01 | current-line/scroll tests |
| AXIS-CTRL-01 | ESTOP/power/recover | task/IO 状态机和视觉 relief | CON-02, CON-03 | ESTOP fault/recover trace |
| AXIS-CTRL-02 | Program controls | load/run/line-run/step/pause/resume/stop/restart | CTRL-01 | native vs Worker endpoint |
| AXIS-CTRL-03 | MDI | command、history、Go、clipboard、queue gate | CTRL-01 | queue-full/history tests |
| AXIS-CTRL-04 | Jog | axis/joint、continuous/increment、press/release/stop | CTRL-01 | release safety and replay |
| AXIS-CTRL-05 | Home/touch-off | home、G54、tool offset、override limits | CTRL-04 | homing/limit/offset oracle |
| AXIS-CTRL-06 | Spindle/coolant | direction、rpm delta、brake、mist/flood | CTRL-01 | IO/device result and fault |
| AXIS-CTRL-07 | Overrides | jog/axis/max velocity/feed/rapid/spindle、metric | CTRL-01 | conversion and range tests |
| AXIS-CTRL-08 | Keyboard map | F1/F2/F3/F5/R/T/P/S/Esc/O/Ctrl keys/F7-F12 | UI-06, CTRL-* | keyboard replay matrix |
| AXIS-VIEW-01 | Preview parser | G-code path、rapid、dwell、current line | CTRL-02 | preview hash/line mapping |
| AXIS-VIEW-02 | Camera | z/z2/x/y/y2/p、zoom、drag/rotate | UI-05, VIEW-01 | canvas nonblank + camera state |
| AXIS-VIEW-03 | Overlays | live/tool/extents/grid/offset/limits/velocity/DTG | VIEW-01 | per-layer toggle screenshots |
| AXIS-VIEW-04 | DRO | machine/relative × actual/commanded × DTG/units/font | CON-01, VIEW-01 | numeric endpoint parity |
| AXIS-EDIT-01 | G-code editor | line numbers、highlight、selection、error column | CTRL-02 | selected-line/run/error tests |
| AXIS-EDIT-02 | Tool table | edit/reload/current/prepared/pocket/hash | CTRL-06 | tool IO/native trace |
| AXIS-EDIT-03 | Config/resource UI | INI/HAL/TBL/VAR/include graph and diagnostics | INV-04 | exact-path report |
| AXIS-EXT-01 | HAL/PLC diagnostics | graph、pin、scope、ClassicLadder Web panels | CON-04 | virtual HAL/PLC replay |
| AXIS-EXT-02 | PyVCP/GLADEVCP/NGCGUI | descriptor→Web component、Python boundary | AXIS-EDIT-03 | capability and blocked cases |
| AXIS-CASE-01 | Minimal XYZ | native/WASM/Worker/frontend full controls | CTRL-*, VIEW-* | `minimal-xyz` report |
| AXIS-CASE-02 | CoreXY dual path | kins vs HAL path | CASE-01 | two independent reports |
| AXIS-CASE-03 | Lathe/9-axis/gantry | axis/joint/lathe variations | CASE-01 | case family matrix |
| AXIS-CASE-04 | VisMach/5-axis | pose/joint/tool orientation/model/stock | VIEW-02, CASE-01 | visual + kinematics report |
| AXIS-TEST-01 | DOM/accessibility | roles、labels、focus、tooltip、shortcut | UI-* | browser DOM report |
| AXIS-TEST-02 | Canonical visual | 1440×900、1280×800、390×844 screenshots | UI-05, VIEW-* | pixel/geometry report |
| AXIS-TEST-03 | Interaction replay | command/event/ack/error/recovery sequence | CTRL-*, EDIT-* | trace hash |
| AXIS-TEST-04 | Native/WASM parity | endpoint/tick/state/error/plot hash | CASE-* | differential report |
| AXIS-TEST-05 | Fault matrix | estop/limit/invalid/blocked/busy/quota/restart | CTRL-01, CON-04 | all failure samples retained |
| AXIS-TEST-06 | Browser/performance | Chromium/Firefox/Safari、WebGL、OPFS、worker | TEST-01..05 | matrix report; blocked explicit |
| AXIS-REL-01 | Evidence index | 每功能、任务、报告、hash、owner、date | TEST-* | self-hash + link audit |
| AXIS-REL-02 | Release gate | license/NOTICE、boundary、STOP_RELEASE 决策 | REL-01 | no unresolved P0/P1 |
## 7. 验收里程碑
里程碑是累积门槛;后一个里程碑不能覆盖前一个未关闭的失败。
### M0:源基线冻结
**目标**:AXIS source/UI/asset/case inventory 可重复生成。
**必须通过**:AXIS-INV-01…04;全部源引用、行号、hash 有效;不存在未分类的外部依赖。
**证据**:`coverage/axis-source-inventory.report.json`、`coverage/axis-asset-inventory.report.json`、`coverage/axis-case-inventory.report.json`。
**失败即停止**:源码提交、资源字节、案例资源或 fixture 变化未重新生成报告。
### M1:像素和结构对标
**目标**:首屏结构与原始 AXIS 一致。
**必须通过**:AXIS-UI-01…07、AXIS-TEST-01/02。
**硬门槛**:菜单四项顺序;toolbar 20 个图标顺序/byte hash/tooltip;Manual/MDI 与 Preview/DRO tab;程序区、Active G-Codes、info bar;canonical 桌面和窄屏无重叠、无裁切。
**不计入通过**:只截图而没有 DOM geometry、asset URL、aria/tooltip 检查。
### M2:控制和状态门控对标
**目标**:每个按钮在与原始 AXIS 相同的状态下启用/禁用/pressed,并产生相同语义命令。
**必须通过**:AXIS-CON-01…04、AXIS-CTRL-01…08、AXIS-TEST-03/05。
**硬门槛**:ESTOP、OFF、ON、idle、reading、waiting、paused、limit、not-homed、queue-full 全矩阵;jog release safety;重复 operation 不产生副作用。
**失败分类**:首个 divergent command/tick、错误码、门控谓词和恢复状态必须定位。
### M3:程序、MDI、DRO、预览对标
**目标**:G-code、MDI、程序预览、live plot、DRO、坐标/单位/模式全部对齐。
**必须通过**:AXIS-VIEW-01…04、AXIS-EDIT-01、AXIS-CASE-01、AXIS-TEST-04。
**硬门槛**:native/Worker 当前行、active G-codes、machine/relative、actual/commanded、DTG、metric、path layer、tool pose、state hash 一致;canvas 非空且切换视角不改变仿真结果。
### M4:工具、HAL、插件和外部边界
**目标**:工具表、主轴/IO、HAL/PLC、PYVCP/GLADEVCP/NGCGUI/VisMach 入口可用或明确 blocked。
**必须通过**:AXIS-EDIT-02/03、AXIS-EXT-01/02、AXIS-CASE-02…04。
**硬门槛**:所有 host-only 能力有 capability/boundary 记录;不允许用 mock 让外部菜单显示 verified;HAL pin 类型、线程顺序和工具 IO 事件可回放。
### M5:案例级 native/WASM/Worker/frontend parity
**目标**:代表案例及全量 AXIS 案例矩阵有 exact resource、startup、control、visual、recovery 证据。
**必须通过**:AXIS-TEST-04、案例对标计划 S8-03…S8-10。
**硬门槛**:每案例 endpoint/checkpoint/event hash 可重放;资源 blocker、host blocker、oracle blocker、error 分开;不能把 `STATIC READY` 当 `TASK_READY`。
### M6:浏览器、性能和恢复
**目标**:支持矩阵下 UI/Worker/OPFS/3D/恢复可复现。
**必须通过**:AXIS-TEST-01…06。
**硬门槛**:Chromium canonical visual/performance/recovery verified;Firefox/Safari/OPFS 若环境不支持则保留 blocked 证据;Worker crash/restart、offline、quota、half-commit 不丢 journal、不重复副作用。
### M7:发布关闭
**目标**:AXIS 对标交付有可审计证据和边界声明。
**必须通过**:AXIS-REL-01/02、所有 P0/P1 条目、所有 release gate。
**禁止发布**:视觉只验了 React 静态 DOM;native oracle 缺失未标记;浏览器矩阵未跑却宣称全平台;真实硬件/宿主能力被算作 Web 等价;报告无法自哈希。
## 8. 证据格式和差异判定
### 8.1 单功能 evidence schema
每个 `feature_id` 的报告至少包含:
```json
{
"schema": "axis-feature-evidence.v1",
"feature_id": "AXIS-MANUAL-02",
"status": "verified",
"source": {
"path": "linuxcnc/share/axis/tcl/axis.tcl",
"lines": "893-924",
"sha256": "..."
},
"web": {
"paths": ["web/react/src/App.tsx", "web/react/src/worker-client.ts"],
"selectors": ["[data-axis-feature=AXIS-MANUAL-02]"],
"asset_urls": []
},
"protocol": {
"commands": ["JOG_START", "JOG_STOP"],
"operation_ids": ["..."],
"capability_predicate": "task=ON && interp=IDLE && !ESTOP"
},
"oracle": {
"native_trace_hash": "...",
"worker_trace_hash": "...",
"endpoint_hash": "...",
"first_divergent_tick": null
},
"visual": {
"viewport": "1440x900@1x",
"dom_hash": "...",
"screenshot_hash": "...",
"asset_hashes": []
},
"failure_policy": "blocked|host_boundary|missing_oracle|resource|error",
"report_sha256": "..."
}
```
### 8.2 差异判定顺序
出现差异时按以下顺序停止和定位:
1. source/config/resource hash 是否相同;
2. 启动 phase 和 capability 是否相同;
3. command kind、payload、seq、operation_id 是否相同;
4. 第一个不同的 `simulation_tick`、task/interp/motion state;
5. 事件顺序、错误码、alarm/recovery、checkpoint/event hash;
6. 最后才比较 DOM geometry、样式和 canvas 像素。
不能先调 CSS 掩盖状态差异,也不能先放宽数值容差。数值容差应按来源类型登记:整数/枚举必须完全相等;位置/速度按固定浮点策略;哈希、事件序号、行号和命令序列不允许容差。
### 8.3 视觉判定
- **强等价**:布局区域、菜单顺序、工具栏顺序、原始 icon byte、控件 role/label、状态颜色和 disabled/pressed 必须精确。
- **规范化等价**:浏览器字体抗锯齿、滚动条、系统 checkbox 外观可在 report 中 mask,但区域尺寸、文本内容、边界和可访问名称不能 mask。
- **动态图层**:Three.js canvas 进行 nonblank/finite/pixel sample/相机状态检查;预览 path、tool、origin、grid、limit、live plot 分层截图。
- **固定视口**:`1440×900@1x`、`1280×800@1x`、`390×844@1x`;另测 DPR 2,但不能以 DPR 2 代替 canonical。
## 9. 当前实现状态和下一步执行顺序
当前 React 已具备 AXIS 风格 shell、原始 bitmap toolbar、Manual/MDI 与 Preview/DRO 结构、Worker-backed program/MDI/jog/home/override/spindle/coolant/ESTOP/recover 入口和 Three.js 视角交互;这只证明实现切片,不等于本规范的 M1…M7 已验收。
M0 的第一步已经执行:[`coverage/axis-source-inventory.report.json`](../coverage/axis-source-inventory.report.json) 由 [`scripts/generate_axis_source_inventory.py`](../scripts/generate_axis_source_inventory.py) 生成,专属契约测试为 [`scripts/test_axis_source_inventory.py`](../scripts/test_axis_source_inventory.py),当前 `AXIS-INV-01=verified`,报告自哈希为 `b8456ef0fd5214fdea9ef7b05682e543173c898a83658d7b005b0922f8808be0`。该报告只冻结来源,不代表任何 Web 功能已通过行为或视觉验收。
接续执行顺序固定为:
1. `AXIS-INV-01` 已完成;接着执行 `AXIS-INV-02…04`,补齐可复现 source/UI/asset/case inventory。
2. `AXIS-CON-01…04`:补齐状态门控、命令、错误和 host boundary schema。
3. `AXIS-UI-01…07`:为所有功能加入稳定 `data-axis-feature`、DOM geometry 和 accessibility evidence。
4. `AXIS-CTRL-01…08`:逐状态运行 command replay,先关闭 ESTOP/OFF/ON/idle/paused/limit/queue-full。
5. `AXIS-VIEW-01…04` 和 `AXIS-EDIT-01`:完成预览层、DRO 模式和选中行程序工作流。
6. `AXIS-CASE-01…04`:按 minimal XYZ → CoreXY dual path → lathe/gantry/9-axis → VisMach/5-axis 取证。
7. `AXIS-TEST-01…06`:Chromium visual/interaction/performance/recovery,外加明确的 Firefox/Safari/OPFS blocker。
8. `AXIS-REL-01/02`:只有所有 P0/P1 和报告自哈希通过,才更新 release gate。
第一批可执行命令:
```bash
python3 scripts/validate_baseline.py
python3 scripts/validate_task_pointer.py
sha256sum linuxcnc/share/axis/tcl/axis.tcl linuxcnc/lib/python/gremlin.py linuxcnc/lib/python/rs274/glcanon.py
find linuxcnc/share/axis/images -maxdepth 1 -type f -printf '%f\n' | sort
npm --prefix web/react run typecheck
npm --prefix web/react run build
for f in web/app/test_*.mjs; do node "$f" || exit 1; done
```
执行者每完成一个任务,必须在对应报告中记录:源文件行号、Web 文件、命令/状态字段、测试命令、native/WASM/Worker 哈希、视觉视口、失败分类和下一依赖。没有这些字段的“完成”只算 `implementation_present`,不算 `verified`。
## 10. STOP_RELEASE 条件
出现以下任一项,立即停止扩大范围并将当前里程碑标为 `blocked`:
- AXIS 源、图标或案例输入变化但未重新生成 hash;
- 首个 divergent command/tick 未定位;
- UI 使用本地乐观状态伪造 task/position/IO 已执行;
- jog release、急停、恢复或 checkpoint 可能重复副作用;
- 缺少 native oracle 却宣称结果一致;
- host-only、真实硬件、动态 loader、外部窗口被统计为 Web 已支持;
- 视觉测试只比较截图,没有 DOM/交互/状态证据;
- 浏览器或 OPFS 不支持被静默降级;
- 任何报告无法用固定输入重新生成或 self-hash 不一致。
本规范关闭的是“AXIS 对标工程”而不是“LinuxCNC 全功能发布”声明。所有未实现、缺资源、无官方 oracle、浏览器边界和真实硬件排除项都必须保留在最终 evidence index 中。

View File

@@ -0,0 +1,49 @@
# 持续执行提示词
本文是本仓库的持续执行操作提示词。用户只需要说“按 `nextTask1.md` 接续执行”,代理就应按当前指针自动认领并推进任务;不需要每轮重复粘贴完整规则。
## 可直接使用的提示词
```text
你是这个仓库的持续执行工程代理。请在当前工作区内持续推进任务,不要只给计划,不要在完成一个任务后停下来询问是否继续。
每轮执行以下流程:
1. 读取 `nextTask1.md` 的 `Current`、`Task`、`Next`、`Verify`、`Stop`。
2. 运行 `python3 scripts/validate_baseline.py` 和 `python3 scripts/validate_task_pointer.py nextTask1.md`。
3. 认领当前 `Next` 任务,将其写为 `in_progress`,确认 task_id、context_id、直接输入和完成报告。
4. 先写专项测试和失败边界,再实现最小可验证垂直切片;复用现有 ABI、protocol、schema、模块和测试。
5. LinuxCNC 源测试必须保留原始路径、输入、expected/checkresult、source hash 和适配分类;不得用自建 smoke test 冒充官方 oracle。
6. 每个任务必须保留正常、边界、错误、非有限值、容量、pause/resume/abort、恢复和确定性 hash/golden 证据(适用时)。
7. 运行任务专属测试、`scripts/build-wasm.sh`、native CTest、全部 Worker 测试和全部 App 测试。
8. 失败样本必须保留并明确标记为 `SOURCE_BLOCKED`、`HOST_EXCLUDED`、`REAL-EXCLUDED` 或具体 Worker/Task/motion pending;不得降低检查、删除失败或伪造通过。
9. 任务完成后生成自哈希报告,更新 `nextTask1.md` 和 `docs/task-history.md`,将下一个依赖满足的任务写入 `Next`,然后在同一轮立即把该任务认领为 `in_progress` 并继续执行;不得在 `verified + queued` 状态结束本轮。
10. 保留工作区已有改动,不使用 `git reset --hard`、`git checkout --` 或其他破坏性回退命令。
11. 远程 compact、网络断开或会话恢复后,重新读取 `nextTask1.md` 和已有报告,从最近的 `in_progress` 任务继续,不从头重做。
12. 只有 `nextTask1.md` 明确 `next_task: none`,或当前任务进入 `blocked` 且需要用户提供外部源码、权限、owner 决策或新 context 时才暂停;外部阻塞要保留证据并说明原因。
工作期间每隔约 30 秒发送简短进度更新。最终汇报实际完成项、测试结果、未闭合阻塞和下一个任务,不把模块测试通过说成全功能完成。
现在立即从 `nextTask1.md` 当前指针开始执行。
```
## 执行边界
- `nextTask1.md` 是唯一任务状态入口;本文件只提供操作规则,不保存任务状态或聊天历史。
- 任务只能按 `queued -> in_progress -> verified` 或 `in_progress -> blocked` 转移。
- `SOURCE_BLOCKED`、`HOST_EXCLUDED`、`REAL-EXCLUDED` 和官方 oracle 缺失不计入通过,但必须出现在报告中。
- 任务队列为空时不得自行发明 release、owner 或新 context 任务;需要新阶段时先创建有直接输入、专项测试和完成报告的正式任务。
- 所有报告必须包含 context、输入/输出 hash、测试命令、差异或首个 divergent tick、已知边界和 self-hash。
## 标准收口门禁
```bash
python3 scripts/validate_baseline.py
python3 scripts/validate_task_pointer.py nextTask1.md
scripts/build-wasm.sh
ctest --test-dir build-native --output-on-failure
for f in web/worker/test_*.mjs; do node "$f" || exit 1; done
for f in web/app/test_*.mjs; do node "$f" || exit 1; done
python3 scripts/validate_baseline.py
python3 scripts/validate_task_pointer.py nextTask1.md
```

View File

@@ -0,0 +1,153 @@
# LinuxCNC Simulation Case Parity Plan
This plan is the execution queue for making the real cases under
`linuxcnc/configs/sim` behave like LinuxCNC in the browser. It supplements the
implementation roadmap with case-level acceptance rules and keeps source
resource blockers explicit.
## Baseline
- Locked source: LinuxCNC `2.10.0~pre0`, commit `239dcf4284762ad7e9c65d390bc5524d855c2f8e`.
- Case catalog: 235 INI entrypoints and 2,080 exact files under `configs/sim` plus LinuxCNC HAL support files.
- Existing matrix: 264 registered configuration entries, 233 entrypoints, 56 static-ready and 208 blocked.
- Browser entrypoint: exact-path case loader, Worker startup diagnostics, G-code/MDI/manual controls and machine view are implemented by S8-01.
- Real LinuxCNC condition evidence: `coverage/native-linuxcnc-case-conditions.report.json`.
- Current hard blocker: source-owned `sim.var`, `linuxcnc.var` and `tool.tbl` contents are absent for the selected minimal/CoreXY cases; S8-02 remains blocked.
## Parity Contract
An individual case is `verified` only when all of these records exist for the same locked source and case hash:
1. Exact INI/include/resource graph with no basename substitution.
2. Native LinuxCNC run using the same case files and an explicit runtime directory policy.
3. WASM core and Worker startup state, diagnostic code, source line and state hash.
4. Fixed-tick golden covering load, home, jog, MDI, run, pause/resume, abort, estop, IO and recovery as applicable.
5. HAL graph/component status and all unsupported host operations classified.
6. Frontend control mapping from the case's `DISPLAY`, VCP/PyVCP/GladeVCP/QtVCP/Gscreen/Touchy/VisMach declarations to authoritative Worker state.
7. Checkpoint/replay endpoint equality and a self-hashed case report.
`STATIC READY` is only an index classification. It never promotes a case to
runtime `TASK_READY` without the native and Worker startup records above.
## Queue
### S8-02: Close One Real Case
Status: `verified`.
The user-authorized runtime fixture contract is complete. Real LinuxCNC
execution supplied `sim.var`, generated `minimal_xyz_cmds.hal`,
`linuxcnc.var`, and the selected sim tool table. Their target paths and SHA-256
values are recorded in `coverage/sim-case-startup-s8-02.report.json`.
Minimal XYZ and CoreXY both reach Worker `TASK_READY`; same-basename files from
unrelated cases remain forbidden.
### S8-03: Lock Runtime Resource Inputs
Status: `verified`, depends on S8-02.
- Pin the native LinuxCNC package/source version used as oracle.
- Decide and record whether parameter files and tool tables are source-owned,
generated-at-startup, or approved deterministic fixtures.
- Store every accepted fixture with source path, generator/command, bytes,
SHA-256 and mutation policy.
- Extend the browser workspace transaction to model LinuxCNC parameter-file
creation/update without host filesystem access.
- Re-run minimal and CoreXY native cases in isolated writable directories.
Exit: no unresolved resource input for the selected XZ batch; report
`coverage/sim-case-batch-s8-03.report.json` records all three TASK_READY states.
### S8-04: Minimal XYZ Vertical Slice
Status: `verified`, depends on S8-03.
- Native/WASM/Worker startup reaches `TASK_READY` for `minimal_xyz.ini`.
- Compare a fixed G-code program, MDI, home, XYZ jog, feed override, pause,
abort, estop/recover and checkpoint restore.
- Drive the frontend case panel and machine view from Worker snapshots only.
- Preserve LinuxCNC's generated `sim.var` semantics as a workspace transaction.
Evidence: `coverage/minimal-xyz-vertical-s8-04.report.json`.
### S8-05: CoreXY Dual Path
Status: `verified`, depends on S8-03 and S8-04.
- Verify both `corexy_by_kins.ini` and `corexy_by_hal.ini`.
- Compare CoreXY kinematics joints, HAL signal graph, home behavior and
following-error/limit boundaries.
- Keep the HAL implementation path distinct from the kinematics path in the
case report and UI diagnostics.
Evidence: `coverage/corexy-dual-path-s8-05.report.json`.
### S8-06: Resource and Startup Matrix
Status: `verified`, depends on S8-04 and S8-05.
- Execute all 235 browser case bundles with exact resource closure.
- Re-run native LinuxCNC for every case whose resources are complete.
- Classify each case as `TASK_READY`, `BLOCKED_RESOURCE`,
`BLOCKED_HOST_CAPABILITY`, `BLOCKED_SOURCE_ORACLE` or `ERROR`.
- Record the first divergent startup phase, source line and missing capability;
never collapse failures into a single count.
Evidence: `coverage/sim-case-matrix-s8-06.report.json`.
### S8-07: Display and Control Families
Status: `queued`, depends on S8-06.
Implement and verify case-declared frontend behavior in separate families:
- Axis: DRO, mode, jog, homing, overrides, program/run controls and plot.
- QtVCP/Gscreen: VCP pins, dialogs, tool/probe/spindle panels and custom tabs.
- GladeVCP/PyVCP: declared pins/widgets and explicit host-loader boundaries.
- Touchy/halui: touchscreen jog/MDI and mode controls.
- VisMach: kinematics-specific machine geometry, joints, toolpath and stock.
Each family must consume Worker authoritative state and retain unsupported
GUI/plugin actions as diagnostics rather than silently dropping them.
### S8-08: Machine Families
Status: `verified`, depends on S8-06.
Close representative cases for Cartesian, lathe, gantry, CoreXY, Delta,
Tripod, Pentapod, Hexapod, 5-axis/TRT, SCARA/PUMA/GenSer and wrapped rotary.
Use the existing native/WASM kinematics tests as golden inputs, then add the
case-specific INI/HAL/resource/startup and frontend evidence.
Current evidence: `coverage/machine-families-s8-08.report.json` covers the
real lineardelta/rdelta cases; remaining listed families continue in later
slices.
### S8-09: Program and Runtime Extensions
Status: `verified`, depends on S8-06.
Cover real cases using remap/Python, O-word/subroutines, filters, ClassicLadder,
tool changers, spindle orient, external offsets, probing and IO acknowledgements.
Every host-only operation must have an explicit capability result and a
browser-equivalent path where one is supported.
Evidence: `coverage/runtime-extensions-s8-09.report.json`.
### S8-10: Full Case Acceptance
Status: `queued`, depends on S8-07, S8-08 and S8-09.
- Run the 235-case matrix in deterministic batches.
- Compare native and Worker endpoint/checkpoint/event hashes.
- Run the browser control matrix at the supported browser versions.
- Publish accepted/blocked/error rows with input and report hashes.
- Keep official oracle, license, browser and owner/release blockers separate
from implementation coverage.
## Resume Gate
The next executable action is S8-03 only after the missing parameter/tool
inputs are supplied or explicitly approved as deterministic fixtures. Until
then, the project remains implementation-capable but not a complete
LinuxCNC-parity release candidate.

View File

@@ -0,0 +1,271 @@
# LinuxCNC Web/WASM 完整仿真移植实施计划
**版本**:1.0
**状态**:implementation baseline
**目标基线**:仓库 `context-lock.json` 锁定的 LinuxCNC 版本
**接续入口**:[`nextTask1.md`](../nextTask1.md)
**已有专项资料**:
- [`linuxcnc-web-wasm-full-port-implementation.md`](linuxcnc-web-wasm-full-port-implementation.md)
- [`linuxcnc-web-wasm-simulation-coverage.md`](linuxcnc-web-wasm-simulation-coverage.md)
- [`linuxcnc-web-wasm-source-map.md`](linuxcnc-web-wasm-source-map.md)
- [`linuxcnc-web-wasm-frontend-communication-design.md`](linuxcnc-web-wasm-frontend-communication-design.md)
- [`linuxcnc-web-wasm-kinematics-migration-plan.md`](linuxcnc-web-wasm-kinematics-migration-plan.md)
本文件是“完整仿真移植”实施轨道的唯一执行目录。仿真实现不依赖 release、owner、许可证审批或发布候选流程;这些内容不参与仿真任务的排队、执行和验收。
## 1. 目标和边界
### 1.1 目标
在浏览器 Dedicated Worker 中运行 LinuxCNC 的可观察仿真行为,使用 WASM 承载数值密集型核心,使用 Web API 承载工程、恢复、界面和可视化。用户应能:
1. 导入或创建一个 LinuxCNC 仿真工程。
2. 解析 INI/HAL/工具表/参数/程序/Python/VCP/ClassicLadder 等资源。
3. 启动仿真并看到确定性的 `READY`、`RUNNING`、`PAUSED`、`ESTOP`、`FAULT`、`STOPPED` 状态。
4. 执行 G-code、MDI、jog、home、pause、resume、single-step、abort、override 和模式切换。
5. 观察轴/关节/姿态/轨迹、HAL pin/signal、主轴、工具、探针、限位、冷却、报警和 Python/VCP 状态。
6. 注入故障、暂停、导出 checkpoint、刷新 Worker、从 OPFS 恢复并得到相同的确定性终点。
7. 对纳入范围的 `configs/sim` 入口给出 `READY` 或可定位的 `BLOCKED/ERROR`,不静默跳过资源。
### 1.2 仿真范围
以下行为必须实现或有原生/WASM 对照证据:
| 功能域 | 必须覆盖的行为 | 浏览器实现边界 |
|---|---|---|
| 工程与配置 | workspace、INI/include/变量、HAL、工具表、参数、程序、Python、VCP、ClassicLadder、资源错误 | `/workspace` 虚拟文件系统;禁止宿主绝对路径、`..`、符号链接逃逸 |
| Task/命令 | mode、MDI、program load/run/pause/resume/step/abort、错误、状态、operation ledger | Worker 单写者;主线程只能发送版本化命令 |
| 解释器 | G/M/O words、模态、单位、坐标、参数、子程序、循环、宏、过滤器和错误行号 | 运行在 WASM/Python Worker;能力拒绝必须稳定 |
| TP/motion | canonical queue、直线/圆弧/同步运动、速度/加速度/jerk、blend、exact stop、暂停和恢复 | 逻辑 tick 取代硬实时墙钟,保持顺序和结果确定 |
| 运动学 | trivkins、gantry/CoreXY、5/6 轴、TRT、机器人、Delta/Tripod/Hexapod/Pentapod、switchkins/userk | 静态链接、注册表选择;动态模块加载不进入浏览器 |
| 轴/关节 | joint/axis 映射、home、软限位、following error、外部偏置、jog、override、estop | 由数字孪生提供输入和故障状态 |
| HAL/组件 | pin、signal、parameter、thread、function、addf、setp、net、twopass、`.comp` 静态组件 | 组件不得访问宿主设备、进程、网络或动态库 |
| PLC/IO | ClassicLadder scan、寄存器、定时器、计数器、数字/模拟 IO、采样、触发、背压 | 虚拟寄存器和逻辑设备;真实 transport 为 `REAL-EXCLUDED` |
| 设备数字孪生 | 主轴、编码器、探针、限位、home、换刀、冷却/润滑、故障/延迟/抖动 | 故障注入必须可记录、回放、恢复,不使用未固定的随机数 |
| Python/remap/VCP | 白名单模块、参数/工具/INI API、remap/filter 生命周期、VCP pin/回调/异常 | Pyodide Worker;`subprocess/socket/device files` 明确拒绝 |
| 持久化/恢复 | journal、checkpoint、snapshot、event replay、Worker restart、OPFS quota、migration、rollback、offline | OPFS 只保存已提交数据,不参与运动计算 |
| Web 工作流 | 编辑器、MDI、控制台、HAL/PLC 面板、报警、恢复向导、轨迹和机床可视化 | UI 只消费 authoritative snapshot/event,不反写核心状态 |
### 1.3 明确排除
以下是宿主能力排除,不是仿真行为排除:
- 真实 PCI/USB/串口/GPIO/并口、真实伺服和真实安全回路。
- Linux PREEMPT_RT、内核线程、共享内存 NML/CMS 进程边界、`fork/exec` 和动态 `.so` 加载。
- 浏览器无法提供的设备文件、任意宿主路径、任意网络 socket 和真实硬件时钟。
被排除的宿主层必须返回稳定的 `REAL-EXCLUDED` 错误;对应的轴、主轴、编码器、探针、限位、换刀和 IO 仍必须由数字孪生覆盖。
## 2. 架构和不变量
```text
Web UI / Editor / Three.js
│ protocol.v1
Dedicated Worker
CommandRouter → TaskLedger → SimScheduler
├─ SimTask / rs274 / canonical
├─ TP / posemath / kinematics
├─ SimMotion / home / limits
├─ SimHAL / components / ClassicLadder
├─ SimIO / digital twins
└─ PythonRuntime / remap / VCP
├─ SnapshotPublisher / EventBus / TraceRecorder
└─ WorkspaceRuntime → WasmFS/POSIX → OPFS journal/checkpoint
│
└─ native oracle 使用同一输入和命令序列
```
必须保持以下不变量:
1. Worker 是唯一 authoritative state 写者;UI 不读取 WASM 指针,不直接写 HAL/OPFS。
2. `sim_step(cycles)` 是唯一改变仿真结果的入口;墙钟只负责调度和让出事件循环。
3. 命令按 `seq` 顺序提交,`operation_id` 幂等;确认丢失先对账,不重复执行副作用。
4. 固定宽度 ABI、明确的 protocol/snapshot/event/workspace schema 和稳定错误码优先于 UI 便利。
5. 状态、事件、轨迹、HAL、IO、Python 和恢复结果都能产生确定性 hash。
6. 缺少输入、未支持能力、配额不足、非法路径、非有限数和 schema mismatch 必须 fail closed。
7. 任何 native/WASM 差异都保留首个 divergent tick、字段路径、单位、容差和来源证据。
### 2.1 固定 tick 顺序
每一个逻辑 tick 依次执行:
1. 对账并去重已确认命令。
2. 执行 Task/解释器预算,更新模态、参数、当前行和 canonical。
3. 执行 TP 前瞻、速度/加速度/jerk、blend/exact-stop。
4. 调用 kinematics inverse,检查奇异性、joint 数量、limits 和 NaN/Inf。
5. 更新 motion、home、jog、following error、外部偏置、estop/limit。
6. 按静态线程/function 顺序运行 HAL、组件、编码器、主轴、探针、换刀和 PLC scan。
7. 运行 IO 完成、超时、报警、Python/remap/VCP 回调;回调不能越过当前 tick。
8. 生成 snapshot/event/trace/state hash,再执行已提交 checkpoint/journal。
快速运行、1x、单步、暂停恢复、导出导入和 replay 在相同逻辑终点必须得到相同 hash。
## 3. 功能实施顺序
### F0:输入、来源和契约
- 以 `context-lock.json`、source index、manifest、config resource graph 和 protocol schema 为输入。
- 为每个 source/file/symbol/config/test 建立 `source_id → feature_id → task_id → test_id → oracle_id` 关系。
- 固定 `sim_task.v1`、`command-envelope.v1`、`snapshot.v1`、`event-log.v1`、`workspace-package.v1` 的字段、版本和错误策略。
- 缺少官方测试输入时保留 `blocked`,不得用近似目录伪装官方 oracle。
### F1:运行时骨架
- 建立 `SimTask`、`SimScheduler`、`TaskLedger`、`SnapshotPublisher` 和 `EventBus`。
- 把现有 WASM lifecycle、fixed tick、event、snapshot、G-code runner 接入 authoritative task state。
- 增加容量、非有限值、取消、abort、pause/resume、operation replay 和 checkpoint 边界。
### F2:工作区和配置启动
- 实现虚拟 POSIX 文件 API、规范化路径、大小/配额和事务写入。
- 解析 INI/include/变量,解析 HAL/工具表/参数/程序/Python/VCP/ClassicLadder 资源图。
- 统一 `NEW → MOUNTED → PARSED → RESOLVED → CORE_CREATED → HAL_READY → TASK_READY` 状态机。
- 每个 `configs/sim` 入口输出 `READY` 或带文件/行/字段/source_id 的诊断。
### F3:解释器、Task、TP、motion、kinematics
- 先让 native oracle 输出每个 block 的 modal/canonical/参数和错误,再接入 WASM。
- 接入 O-word/子程序/循环/参数/宏/remap/filter、MDI、program state machine。
- 将 canonical queue 连接 TP、motion 和 kinematics;实现暂停、单步、abort、jog、home、override、limits、following error。
- 按 kinematics registry 逐族接入并保留每个族的 forward/inverse、branch、singularity 和 limit 证据。
### F4:HAL、PLC、IO 和数字孪生
- 解析并执行 pin/signal/parameter/thread/function、`loadrt/addf/setp/net/sets/link*` 和静态 `.comp`。
- 实现 ClassicLadder 工程、scan、寄存器、计数器、定时器、HAL 绑定和诊断。
- 接入 spindle/encoder/probe/limit/home/tool/coolant/IO,支持故障注入、延迟、抖动、恢复和回放。
### F5:Python、remap、VCP
- 固定 Pyodide 版本、manifest、模块白名单、内存/时间/源码限制。
- 实现 `linuxcnc/hal/gstat/INI/tool/parameter/workspace/virtual-clock` 兼容 API。
- 接入 remap/filter 生命周期、VCP descriptor、pin callback、异常隔离和权限拒绝。
### F6:恢复、离线和迁移
- 将 Task、解释器、TP、motion、kinematics、HAL、IO、Python、workspace 和 ledger 纳入 checkpoint。
- 实现 journal prepare/commit、确认丢失对账、崩溃恢复、OPFS quota、离线包、版本迁移和 rollback。
- 恢复必须从最近有效 checkpoint 重放已提交 event,不得只重新加载配置。
### F7:Web 工作流和可视化
- 完善工程导入、编辑器诊断、MDI、run/pause/step/abort、jog/home/override、HAL/PLC/IO/报警面板。
- 以 authoritative snapshot/event 驱动姿态、joint、toolpath、stock、坐标系、工具、主轴和故障渲染。
- 用 Worker 重启、离线、配额和错误场景覆盖 UI 恢复向导;不使用 mock 替代真实 Worker。
### F8:全量兼容、性能和交付
- 对所有纳入范围的 `configs/sim`、相关 tests/unit_tests 和资源入口执行 native/WASM 差异矩阵。
- 固定至少三次重复、快速/1x/单步/恢复、浏览器矩阵、性能、内存和离线报告。
- 许可证、来源、下载、迁移、回滚和 REAL-EXCLUDED 边界全部有证据;只有所有 gate 满足时才讨论 release candidate。
## 4. 任务分解
任务状态只能按 `queued → in_progress → verified` 或 `in_progress → blocked` 转移。每个任务只有一个主要结果,并必须提供输入 context、直接证据、专属测试、完整回归和回滚点。
| ID | 任务 | 依赖 | 主要产物 | 验收重点 |
|---|---|---|---|---|
| P0-01 | 冻结来源、工具链、schema 和 source hash | 无 | context/source baseline | baseline 可重建,缺输入 fail closed |
| P0-02 | 建立 source→feature→task→test 图 | P0-01 | coverage graph/manifest | 无孤儿、重复、未知 ID |
| P0-03 | 固定 ABI/protocol/snapshot/event/workspace 契约 | P0-01 | schema + compatibility tests | 版本 mismatch 和字段缺失拒绝 |
| P1-01 | 建立 `sim_task.v1` authoritative 状态对象 | P0-03 | Task state/native/WASM tests | state hash、状态机、错误码一致 |
| P1-02 | 固定 `sim_step` 调度顺序和 tick budget | P1-01 | scheduler + tick golden | 快速/1x/单步终点一致 |
| P1-03 | 接入 command ledger、幂等和 abort | P1-01 | ledger/replay tests | operation replay 不重复副作用 |
| P1-04 | 将现有 G-code/MDI runner 接入 Task snapshot | P1-01 | Worker/native/WASM report | 当前行、模态、程序状态可观察 |
| P2-01 | 虚拟 POSIX/Workspace API | P1-01 | workspace runtime | 路径、编码、配额、事务错误稳定 |
| P2-02 | INI/include/变量解析器 | P2-01 | parser/resource graph | 行号、循环、缺失资源可诊断 |
| P2-03 | HAL/工具表/参数/程序/Python/VCP/CLP resolver | P2-01 | config resource graph | 所有依赖可定位、不静默替换 |
| P2-04 | 统一配置启动状态机 | P2-02/P2-03/P1-02 | startup resolver/233-entry report | 入口只进入 READY 或 BLOCKED |
| P3-01 | rs274 grammar/modal/parameter 完整闭环 | P1-04 | native/WASM interpreter oracle | block、错误列和 modal hash 一致 |
| P3-02 | O-word、子程序、循环、宏和过滤器 | P3-01/P5-02 | interpreter golden | 深度、预算、异常边界完整 |
| P3-03 | canonical queue、TP 前瞻、blend/exact-stop | P1-02/P3-01 | TP golden/diff report | segment 顺序、速度和首差 tick |
| P3-04 | Task mode、MDI、program state machine | P1-03/P3-01 | command golden | run/pause/resume/step/abort 可恢复 |
| P3-05 | motion、jog、override、home、limits、following error | P3-03 | motion state/故障矩阵 | 轴/关节、estop、limit、home 一致 |
| P3-06 | kinematics registry 和 trivkins/gantry/CoreXY | P3-05 | registry + native/WASM tests | forward/inverse/branch/limits |
| P3-07 | 5/6-axis、TRT、机器人、并联和 switch/user kins | P3-06 | 每族 report/golden | singularity、非有限、缺 oracle 明确 |
| P4-01 | HAL graph/twopass/pin/signal/thread/function | P2-03/P1-02 | HAL graph/runtime | 顺序、类型、重复、未知组件 fail closed |
| P4-02 | 静态 `.comp` 组件和能力 manifest | P4-01 | component manifest/tests | 不动态加载、不访问宿主 |
| P4-03 | ClassicLadder/采样/触发/背压 | P4-01 | PLC runtime/report | scan 顺序、寄存器、故障可回放 |
| P4-04 | spindle/encoder/probe/limit/home/tool/coolant twin | P4-01/P3-05 | device model/fault matrix | 延迟、故障、恢复、hash 一致 |
| P4-05 | IO command/ack/timeout/estop/recover | P4-04/P1-03 | IO Worker/native tests | ack 丢失和恢复不重复副作用 |
| P5-01 | Pyodide runtime、模块白名单和虚拟时钟 | P2-01 | runtime manifest/report | 资源和能力限制稳定 |
| P5-02 | Python linuxcnc/hal/INI/tool/parameter API | P5-01/P3-04 | API compatibility tests | 正常、异常、禁止能力 |
| P5-03 | remap/filter/VCP callback 和隔离 | P5-02/P4-01 | remap/VCP report | 异常不破坏 Worker 核心 |
| P6-01 | snapshot/event/trace 全状态导出 | P1-02/P3-05/P4-05/P5-03 | schema/hash tests | 导入导出 round-trip |
| P6-02 | journal/checkpoint/operation reconciliation | P6-01/P1-03 | recovery matrix | crash、半提交、确认丢失 |
| P6-03 | OPFS/offline/migration/rollback | P6-02/P2-01 | browser recovery report | 离线、配额、版本迁移 |
| P7-01 | Worker protocol/client、backpressure、cancel | P1-03/P6-01 | protocol E2E | seq、schema、timeout、cancel |
| P7-02 | editor/diagnostic/MDI/run workflow | P3-04/P7-01 | browser E2E | 真实 Worker,不用 mock |
| P7-03 | state/HAL/IO/Python/PLC/alarm panels | P4/P5/P7-01 | UI tests | snapshot/event 单向消费 |
| P7-04 | Three.js pose/joint/toolpath/stock view | P3-05/P7-03 | WebGL/canvas tests | 非空、姿态和轨迹跟随 authoritative state |
| P7-05 | recovery/offline/error/permission UX | P6-03/P7-02 | browser fault E2E | 恢复状态可操作、错误可定位 |
| P8-01 | native oracle runner 和 golden schema | P0-03/P3/P4 | JSONL oracle | 同输入、同命令、首差 tick |
| P8-02 | 全量 sim entrypoint matrix | P2-04/P8-01 | startup/diff matrix | 每入口 READY 或诊断 BLOCKED |
| P8-03 | 三次重复和执行模式 determinism | P8-02/P6 | determinism report | 1x/fast/step/recover hash 一致 |
| P8-04 | browser/performance/memory/offline matrix | P7/P8-03 | perf/compat report | P95/P99、配额、WebGL、离线 |
| P8-05 | 来源/许可证/下载/迁移/回滚交付闭合 | P8-02/P8-04 | release evidence | 所有排除项和剩余 blocker 显式保留 |
## 5. 里程碑
| 里程碑 | 名称 | 包含任务 | 退出条件 |
|---|---|---|---|
| M0 | 输入和契约闭合 | P0-01..03 | context/source/schema hash 可重建;输入缺失不会被接受 |
| M1 | Task/WASM/Worker 会话闭合 | P1-01..04 | create/load/MDI/program/tick/pause/abort/snapshot/replay 通过 native/WASM/Worker |
| M2 | 解释器和运动主链 | P3-01..07 | G-code→canonical→TP→motion→kinematics→snapshot 闭合,首差可定位 |
| M3 | 配置启动闭合 | P2-01..04 | 纳入范围的每个入口进入 READY 或带来源诊断的 BLOCKED |
| M4 | HAL/IO/数字孪生闭合 | P4-01..05 | HAL/PLC/主轴/编码器/探针/限位/工具/冷却/estop 故障可执行、可回放 |
| M5 | Python/remap/VCP 闭合 | P5-01..03 | 白名单 API、remap、VCP、异常、能力拒绝和资源限制通过 |
| M6 | 恢复和离线闭合 | P6-01..03 | Worker 重启、OPFS checkpoint、journal、迁移、回滚、离线路径通过 |
| M7 | Web 工作流和可视化闭合 | P7-01..05 | UI 真实消费 Worker authoritative state,Three.js/Canvas 非空并可恢复 |
| M8 | 全量兼容和交付闭合 | P8-01..05 | 全量矩阵、三次 determinism、浏览器/性能和来源证据齐全;仿真结果独立可运行 |
每个里程碑完成时必须生成一份确定性 report,包含 `context_id`、任务 ID、输入/输出 hash、native/WASM/Worker 测试、已知 blocked 项和下一个依赖任务。里程碑不能从 `blocked` 自动跳回 `in_progress`。
## 6. 验收证据和回归门禁
每个任务至少保留:
- native test;适用时必须有 WASM/Worker 对照 test。
- 正常、边界、非有限值、容量、错误、abort、pause/resume、恢复和离线样本。
- 输入 context、source hash、ABI/protocol/schema 影响和直接 evidence 路径。
- 状态 hash、event hash、首个 divergent tick 或明确的 `REAL-EXCLUDED/BLOCKED` 原因。
- 可重跑命令和报告 self-hash。
技术任务的最小回归:
```bash
python3 scripts/validate_baseline.py
python3 scripts/validate_download_index.py
python3 scripts/validate_task_pointer.py
scripts/build-wasm.sh
ctest --test-dir build-native --output-on-failure
for f in web/worker/test_*.mjs; do node "$f" || exit 1; done
for f in web/app/test_*.mjs; do node "$f" || exit 1; done
```
修改配置、协议、恢复或发布证据时,再运行对应的生成器专项测试和完整 Python unittest;生成器产生的报告不能被手工改 hash 伪装为通过。
## 7. 停止线
立即将当前任务标记为 `blocked` 并保留证据的情况:
1. LinuxCNC 来源、官方测试输入、配置资源或协议契约缺失。
2. 需要改变 ABI/protocol/schema/manifest 时,必须同步更新兼容性测试和迁移证据。
3. native/WASM 差异的首个 divergent tick 未定位。
4. 只能删除失败样本、降低检查、静默替换资源或把缺失能力改成 `REAL-EXCLUDED` 才能通过。
5. Python/组件/VCP 需要未经允许的宿主路径、设备、进程或网络能力。
6. checkpoint/journal 无法验证 hash、确认丢失无法对账或恢复会重复副作用。
7. 运行结果依赖未固定的墙钟、随机数、线程竞争或浏览器环境。
blocked 不是失败样本删除理由,也不是自动跳过前置任务的理由。修复后必须重新运行原任务的专属测试和完整回归,再认领下一个依赖满足的任务。
## 8. 当前实现基线
截至本计划建立时,仓库已有:
- WASM/native 核心构建、posemath、解释器、多个 kinematics、HAL、IO 和固定 tick 切片。
- Worker protocol/session、虚拟设备、Python bridge、workspace recovery 和前端基础面板。
- G-code `PROGRAM_LOAD/RUN/PAUSE/RESUME/ABORT/STEP/SEEK`、`MDI_EXECUTE` 的 Worker/WASM 垂直切片。
这些能力仍不能替代 M1-M8 的完整验收。下一项直接实现任务由 [`nextTask1.md`](../nextTask1.md) 指向 `P1-01`:把已有 runner、解释器、motion/kinematics、HAL、IO 和 snapshot 统一纳入 `sim_task.v1` authoritative state,并固定首个可对照的 tick 边界。

View File

@@ -0,0 +1,104 @@
# LinuxCNC Web/WASM 连续执行计划
更新时间:2026-08-21
本计划只服务于仿真实现的连续接续;`nextTask1.md` 是仿真状态入口,
`context-lock.json` 只用于来源和工具链复现。
持续执行的可复制提示词集中在
[`持续执行提示词`](linuxcnc-web-wasm-autonomous-execution-prompt.md)。实际任务状态仍只以
`nextTask1.md` 为准。
## 当前状态
当前仿真轨道直接按 `nextTask1.md` 认领和执行,不等待外部输入。
- `context-lock.json` 当前 context 为 `linuxcnc-2.10.0-pre0-wasm-m1-py-c1`。
- 已完成任务不重复执行,后续任务按依赖顺序连续认领。
- ABI/protocol/schema 变更可以在仿真需要时实施,但必须同时更新兼容性测试和恢复证据。
因此采用两条泳道:
1. **治理泳道**:等待 owner 输入,完成 intake 校验,审查新 context,再重开 K8 release
任务。
2. **技术泳道**:维护 INT-01..INT-10 的有序队列、设计和测试准备;只有当前 context
明确允许实现时才修改 ABI 或 runtime。
仿真轨道只有实现正确性、确定性和可恢复性状态,不设置发布泳道或 owner 阻塞状态。
## 连续认领规则
每次接续按以下固定循环执行,避免再次停在模糊的“下一步”:
1. 读取 `nextTask.md` 的 `Current/Task/Verify/Stop`,再读取本任务直接输入。
2. 运行四个基线门禁:
`validate_baseline.py`、`validate_download_index.py`、脚本 unittest、
`validate_task_pointer.py`。
3. 从下面队列中选择第一个依赖已满足、没有外部决策缺口的任务;不得跳过前置任务。
4. 先写任务测试和失败边界,再实现最小垂直切片;每个任务保留 native、WASM/Worker
和状态 hash 证据。
5. 运行任务专属测试和回归门禁,生成确定性报告;失败时保留样本和错误码,不删样本、
不降低检查、不把资源缺失重分类为 `REAL-EXCLUDED`。
6. 更新任务报告和本计划的任务状态;下一项只有在依赖、测试和报告均 verified 后才能
认领。
7. 遇到 owner、源码、ABI、protocol、schema、浏览器或许可证外部输入时,生成 blocked
证据并转入治理泳道;禁止自动重试同一阻塞任务。
任务认领必须能回答四个问题:`task_id`、`context_id`、直接输入、完成报告。没有这四项
就不开始实现。
## 任务队列
| 顺序 | 任务 | 目标 | 主要产物 | 前置条件 | 当前状态 |
|---|---|---|---|---|---|
| 0 | `GOV-INTAKE-01` | 强化 owner decision 的字段、路径和证据 hash fail-closed 校验 | `scripts/validate_owner_decision_intake.py`、专项测试 | 当前 context | `verified` |
| 1 | `OWNER-INPUT-01` | 收集并校验六项 owner decision | `coverage/owner-decisions.json`、intake report | 外部 owner 输入 | `blocked` |
| 2 | `CONTEXT-REFRESH-01` | 审查新的锁定 context,确认源码/ABI/schema 变化 | 新 context lock、context packet | `OWNER-INPUT-01` 完整且已审查 | `blocked` |
| 3 | `INT-01` | 建立 `sim_task` 状态对象、固定 tick 边界和 C ABI | `sim_task.h/.c`、native/WASM task test、ABI report | 新 context、protocol v1 | `queued` |
| 4 | `INT-02` | 实现 `PROGRAM_LOAD/RUN/PAUSE/RESUME/ABORT/STEP` | minimal XYZ E2E、command golden | `INT-01`、配置 resolver | `queued` |
| 5 | `INT-03` | 串联 TP -> IK -> motion -> FK,并实现事务回滚 | motion/gantry/TRT 差异报告 | `INT-01/02`、K0-K6 | `queued` |
| 6 | `INT-04` | 把 HAL、IO、Python 放入同一固定 tick | IO/tool/probe/estop/remap 测试 | `INT-03`、M3-RT/PY | `queued` |
| 7 | `INT-05` | 将配置资源解析结果接入 runtime 启动 | 233 入口 ready/blocked/error 报告 | `INT-01`、M3-CFG | `queued` |
| 8 | `INT-06` | 执行 Python/remap/filter,保留能力拒绝边界 | remap、参数、异常、资源限制报告 | `INT-02`、M3-PY | `queued` |
| 9 | `INT-07` | 接入真实 OPFS、journal、checkpoint 和 Worker 重启 | browser recovery/offline 矩阵 | `INT-01`、M3-FS | `queued` |
| 10 | `INT-08` | 前端消费权威 Task snapshot/event | run/pause/step/alarm/recovery E2E | `INT-02/04`、FE-M1..M4 | `queued` |
| 11 | `INT-09` | 用真实 pose/joints/toolpath 驱动 Three.js | vismach、canvas/WebGL、性能报告 | `INT-03`、`INT-08` | `queued` |
| 12 | `INT-10` | 执行 233 个 sim entrypoint 的全量差异闭环 | startup matrix、source/resource/component 定位 | `INT-05..09` | `queued` |
| 13 | `K8-REL-17+` | 重新生成 closure/audit/gate,处理六项 blocker | release candidate gate | owner decision、新 context、对应证据 | `blocked` |
`INT-01..INT-04` 是功能主链;`INT-05..INT-07` 是运行时闭环;`INT-08..INT-09` 是前端
融合;`INT-10` 是规模化回归。任务状态只能按 `queued -> in_progress -> verified` 或
`in_progress -> blocked` 转移,不允许从 `blocked` 自动回到 `in_progress`。
## 当前可执行动作
在 `OWNER-INPUT-01` 仍缺失时,只执行以下动作:
```bash
python3 scripts/validate_baseline.py
python3 scripts/validate_download_index.py
python3 -m unittest discover -s scripts -p 'test_*.py' -v
python3 scripts/validate_task_pointer.py
python3 scripts/validate_owner_decision_intake.py
python3 scripts/test_owner_decision_intake.py
```
这些动作只确认仿真基线和阻塞证据,不重复实现已经完成的矩阵。
收到 owner 文件后,必须先验证六个 blocker 恰好各出现一次、context 一致、字段完整、
证据 hash 有效;即使六项都是 `approve`,也只能进入 `CONTEXT-REFRESH-01`,不能直接把
release 状态改为 accepted。
## 任务完成门禁
每个技术任务至少需要:
- 明确的输入 context 和来源 hash;
- native 测试;
- WASM 或 Worker 对照测试(适用时);
- 错误、非有限值、容量、abort/恢复边界;
- 确定性状态 hash 或报告 self-hash;
- 不改变无关任务的报告和六项 release blocker。
最终项目完成还必须通过完整回归、浏览器矩阵、资源闭包、许可证决策、官方 oracle 和
owner review。任何一项缺失都只能保持 `blocked`,不能以“模块测试通过”替代端到端完成。

View File

@@ -0,0 +1,112 @@
# LinuxCNC Web/WASM 契约快照
**契约版本**:`sim-contracts.v1`
**任务**:`P0-03`
**Context**:`linuxcnc-2.10.0-pre0-wasm-m1-py-c1`
**状态**:implementation-verified(只冻结现有边界;不表示 release accepted)
本文冻结浏览器 Dedicated Worker 与 WASM 核心之间可观察的字段、版本和错误策略。它是当前 context 的兼容性快照,不替换 `context-lock.json`,也不改变已有 C ABI、Worker protocol 或 recovery schema。`sim_task.v1` 只冻结 P1-01 将实现的状态对象形状;本任务不实现该 runtime。
## 1. 版本和边界
| 契约 | 线上的版本标识 | 当前实现边界 |
|---|---|---|
| `sim_task` | `sim_task.v1` | P1-01 authoritative state 预留;本任务只做形状校验 |
| 命令信封 | `command-envelope.v1` | Worker 输入使用 `schema_version: 1` |
| 快照 | `snapshot.v1` | `web/worker/replay.mjs` 的 snapshot 记录 |
| 事件日志 | `event-log.v1` | `web/worker/replay.mjs` 的事件日志 |
| 工作区包 | `workspace-package.v1` | 包 schema 固定;`format_version` 1/2 是同一 envelope 的可验证迁移 |
版本号是整数且不隐式降级。未知版本、缺少必填字段、未知顶层字段、非有限数、哈希或游标不一致都 fail closed。新必填字段或语义变化必须建立新 schema 标识和迁移测试;同一 v1 只允许增加明确标为可选的诊断字段。
## 2. `sim_task.v1`
这是单 Worker authoritative task 的可观察状态,不是 C ABI 结构体。字段顺序在 canonical JSON 中按键名排序,数值使用 JSON 安全整数或有限 IEEE-754 数。
| 字段 | 类型 | 要求 |
|---|---|---|
| `schema` | string | 固定 `sim_task.v1` |
| `context_id`、`session_id` | string | 非空;恢复时必须与锁定 context/session 相符 |
| `state` | enum | `NEW`、`READY`、`RUNNING`、`PAUSED`、`ESTOP`、`FAULT`、`STOPPED`、`DESTROYED` |
| `mode` | enum | `MANUAL`、`MDI`、`AUTO` |
| `program_status` | enum | `idle`、`loaded`、`running`、`paused`、`completed`、`aborted`、`fault` |
| `seq` | positive integer | 最后应用的命令序号 |
| `simulation_tick` | non-negative integer | 逻辑 tick;不使用墙钟 |
| `current_line` | non-negative integer or null | 当前程序行;未知时为 null |
| `state_hash` | string | 对除 hash 外的完整状态做确定性 hash |
P1-01 可以在同一 schema 内增加由契约测试先登记的可选域;改变上述语义或枚举必须升级版本。Task 状态、事件、快照和 operation ledger 必须在相同 tick 边界提交。
## 3. `command-envelope.v1`
命令及其 Worker 响应共享以下信封字段:
| 字段 | 要求 |
|---|---|
| `schema_version` | 固定整数 `1`,对应 C `sim_protocol_accept` 的 schema 参数 |
| `kind` | 非空字符串,长度不超过 128(C `has_text` 边界);命令种类由 capability/Worker 白名单决定 |
| `context_id` | 非空字符串,必须等于 context lock |
| `session_id` | 非空字符串;同一会话不可改变 |
| `seq` | 从 1 开始严格连续递增;重复副作用通过 `operation_id` 对账 |
| `operation_id` | 副作用命令必填的非空字符串,长度不超过 128;只读查询可省略 |
| `simulation_tick` | 可选的非负安全整数;不得小于 Worker 当前 tick |
| `sent_at_monotonic_ms` | 可选有限数,仅用于诊断,绝不参与状态或 hash |
| `payload` | 必填 JSON object;不能是数组、null 或包含非有限数 |
当前 C ABI 的状态与错误保持不变:`SIM_PROTOCOL_ERR_SCHEMA=-100`、`SEQUENCE=-101`、`STATE=-102`、`OPERATION_ID=-103`、`KIND=-104`、`ARGUMENT=-105`、`TICK=-106`。Worker 以稳定的 `protocol_*` 错误键映射这些结果,不能把错误改成成功或静默重排命令。
## 4. `snapshot.v1`
`SnapshotStore` 导出的对象固定为 `{schema, snapshots}`;每条 snapshot 使用:
```json
{
"schema": "snapshot.v1",
"snapshot_id": "snap:<seq>:<state_hash>",
"base_snapshot_id": null,
"seq": 1,
"tick": 0,
"state": {},
"state_hash": "fnv1a64:<16 lowercase hex>"
}
```
`seq` 为正整数且同一序号只能有一个内容,`tick` 不回退;增量 snapshot 的 `base_snapshot_id` 必须引用已导入的 snapshot。`state_hash` 和 `snapshot_id` 必须由同一 canonical state 重算。容量不足、重复序号、缺少 base、哈希不符和非有限 state 均拒绝,导入失败不得替换当前 store。
## 5. `event-log.v1`
日志对象固定为 `{schema: "event-log.v1", cursor, tick, events}`。每条事件固定字段:
```json
{
"seq": 1,
"tick": 0,
"kind": "SESSION_READY",
"payload": {},
"payload_hash": "fnv1a64:<16 lowercase hex>"
}
```
`seq` 从 1 严格连续,`tick` 单调不减,`kind` 非空且最多 64 个字符,payload 必须是 object。C 端保留 `sim_event_record` 的固定宽度布局(`uint32_t seq/tick`、`uint64_t payload_hash`、32 字节 kind),并保留 `SIM_EVENT_CAPACITY=256` 与错误码 `-200..-204`。WASM 和 Worker 对同一输入必须得到相同 cursor/tick/hash;半成品导入不改变当前日志。
## 6. `workspace-package.v1`
包 envelope 的必填字段为 `schema`、`format_version`、`context_id`、`committed_seq`、`checkpoint`、`timeline`、`journal`、`content_hash`、`package_hash`。`format_version: 1` 是当前基线;已实现的 `format_version: 2` 只添加 `migration` 和 `integrity` 元数据,事件、snapshot、checkpoint、journal payload 保持 byte-for-byte v1 兼容。
迁移规则:
1. v1→v2 必须标记 `lossless: true`、源 package hash 和 timeline/journal/checkpoint integrity hash。
2. v2→v1 只有在源 hash 对账成功时允许;原包不可变,回滚只生成新目标包。
3. 不支持的版本、context、提交序号、timeline/checkpoint、content/package hash 或 journal 顺序均拒绝。
4. 缺失/损坏资源在离线模式返回明确错误;不能用空包或当前内存状态替代已提交包。
## 7. 兼容性决策记录
- **ABI**:保留 `sim_api.h`、`sim_protocol.h`、`sim_event.h` 的函数签名、整数宽度、错误码和容量语义;没有修改锁定 ABI。
- **协议**:Worker 继续传递 `schema_version: 1`,C validator 继续拒绝非 1、序号缺口、tick 回退和副作用命令缺失 `operation_id`。
- **快照/事件**:沿用 `replay.mjs` 的 `schema` 字段和 FNV-1a-64 canonical hash;不把 `snapshot.v1` 或 `event-log.v1` 改成新的顶层结构。
- **工作区**:沿用现有 workspace migration 的 v1/v2 envelope;v2 不是新的 payload schema,不修改已锁定的事件/快照/checkpoint/journal 版本。
- **未知字段**:v1 顶层未知字段和缺失字段 fail closed;仅 `sent_at_monotonic_ms` 这一诊断字段可选且不影响 hash。需要其它字段时先建 v2 schema/迁移测试。
- **排除边界**:真实硬件、宿主路径、实时内核和动态库仍是 `REAL-EXCLUDED`;主轴、编码器、探针、限位、换刀、冷却和 IO 的仿真契约不因此排除。
直接证据:`web/worker/contracts.mjs`、`web/worker/test_contracts.mjs`、`wasm-core/tests/sim_contract_test.c`、`scripts/test_sim_contract.py`、`coverage/sim-contract.report.json`。

View File

@@ -10,8 +10,9 @@
## Required Shape
The input must use schema `owner-decision-intake.v1`, match the locked
`context_id`, and contain exactly one decision for each of the six blocker IDs:
The input must use schema `owner-decision-intake.v1`, provide a non-empty
`decision_set_id`, match the locked `context_id`, and contain exactly one
decision for each of the six blocker IDs:
`manifest_seed_unassigned`, `accepted_entries_missing`,
`official_oracle_missing`, `configuration_resources_missing`,
@@ -19,8 +20,9 @@ The input must use schema `owner-decision-intake.v1`, match the locked
Each decision requires `decision` (`approve`, `reject`, or `defer`), non-empty
`owner`, non-empty `reviewer`, a rationale, an evidence list, and an explicit
`new_context_required` boolean. Evidence entries require a repository-relative
path and SHA-256 hash. The validator checks shape and identity only; it never
`new_context_required` boolean. Evidence entries require an existing
repository-relative path and a lowercase SHA-256 hash matching the referenced
file. The validator checks shape, identity, and evidence integrity; it never
creates a context, changes `context-lock.json`, promotes an entry, or refreshes
the release gate.

View File

@@ -0,0 +1,81 @@
# LinuxCNC Web/WASM 仿真功能补全计划
**版本**:3.1
**范围**:只实现 LinuxCNC 仿真功能,不处理其他项目。
**接续入口**:[`nextTask1.md`](../nextTask1.md)
## 目标
在 Dedicated Worker 中实现可重复的 LinuxCNC 仿真行为,并用 WASM/native/Worker 测试验证:
- INI、HAL、工具表、参数、程序、Python、VCP、ClassicLadder 资源加载。
- rs274 G/M/O 解释、modal、参数、子程序、循环、宏、canned cycle 和错误定位。
- canonical queue、TP、直线/圆弧/同步运动、速度/加速度/jerk、blend、exact-stop。
- Task mode、MDI、run/pause/resume/step/abort/restart、jog、home、override、limits。
- trivkins、gantry/CoreXY、5/6-axis、TRT、机器人、Delta/Tripod/Hexapod/Pentapod、switch/user kins。
- HAL pin/signal/parameter/thread/function、静态 `.comp`、ClassicLadder、PLC、采样和背压。
- spindle、encoder、probe、limit、home、tool、coolant、door、interlock、estop 数字孪生。
- Python `linuxcnc/hal/INI/tool/parameter`、remap、filter、VCP callback 和异常隔离。
- snapshot/event/trace、checkpoint、journal、Worker restart、OPFS、offline、migration、rollback。
- editor、MDI、状态/HAL/IO/Python/PLC/alarm 面板和 pose/toolpath/stock Canvas。
## 不变量
1. Worker 是 authoritative state 唯一写者;UI 只消费 snapshot/event。
2. `sim_step(cycles)` 是唯一改变仿真结果的入口;不使用墙钟或随机数。
3. `seq`、`operation_id`、checkpoint、event、snapshot 和 state hash 全部确定性。
4. 非法路径、缺失资源、非有限值、容量、未知能力和 schema 错误 fail closed。
5. 真实硬件、设备文件、宿主进程、网络和动态库不进入仿真实现。
## 实施阶段
### S1 解释器与运动主链
`S1-01` rs274 完整 word/modal/system parameter;`S1-02` canonical/TP 圆弧、同步运动、accel/jerk 和暂停;`S1-03` motion/kinematics feedback、home/limit、override。
### S2 HAL、PLC、设备
`S2-01` `.clp` ClassicLadder parser/runtime;`S2-02` HAL component runtime batch;`S2-03` encoder/coolant/door/interlock/IO ack;`S2-04` 配置入口资源修复。
### S3 Python、恢复、浏览器
`S3-01` Python API compatibility;`S3-02` remap/filter/VCP;`S3-03` Worker crash/OPFS/offline/recovery;`S3-04` browser simulation compatibility/performance。
### S4 仿真回归
`S4-01` full simulation regression;`S4-02` 1x/fast/step/recover endpoint replay parity。
## 任务队列
| ID | 任务 | 依赖 | 主要输出 |
|---|---|---|---|
| S1-01A | implement rs274 parameter space and modal expansion | 无 | interpreter native/WASM/Worker tests |
| S1-01B | implement rs274 G/M words, canned cycles, coordinates and compensation | S1-01A | interpreter native/WASM/Worker tests |
| S1-02A | implement TP arcs, sync FIFO and accel/jerk bounded profile | S1-01B | TP/motion tests |
| S1-02B | implement pause/resume and canonical multi-segment expansion | S1-02A | TP/motion tests |
| S1-03 | implement motion/kinematics feedback, home/limit and override | S1-02B | motion fault matrix |
| S2-01 | implement `.clp` ClassicLadder parser/runtime | S1-03 | PLC runtime/tests |
| S2-02 | implement HAL component runtime batch | S1-03 | component runtime/tests |
| S2-03 | implement encoder/coolant/door/interlock/IO ack parity | S1-03 | device/IO tests |
| S2-04 | implement blocked sim entrypoint resource batch | S2-02 | startup/runtime tests |
| S3-01 | implement Python API compatibility | S1-01 | Python bridge/session tests |
| S3-02 | implement remap/filter/VCP callback path | S3-01 | callback tests |
| S3-03 | implement Worker/OPFS/offline recovery | S2-03/S3-01 | recovery tests |
| S3-04 | implement browser simulation compatibility/performance | S3-03 | app/Canvas/Worker tests |
| S4-01 | complete simulation regression | S2-04/S3-04 | full simulation report |
| S4-02 | complete endpoint replay parity | S4-01 | determinism/recovery report |
## 当前任务
当前直接执行 `S1-01`。它读取 `linuxcnc/src/emc/rs274ngc`、`linuxcnc/unit_tests/interp`、`wasm-core/src/sim_interpreter.c` 和 `web/worker/program-runner.mjs`,输出代码、native/WASM/Worker 测试和确定性状态报告。
## 验收
每个任务必须有正常、边界、错误、容量、暂停/恢复和非有限样本;必须运行对应 native/WASM/Worker 测试、`scripts/build-wasm.sh`、CTest 和全部 Worker/App 测试。任务报告必须包含输入、输出、测试和 self-hash。
## 停止条件
- 需要修改已冻结 ABI、protocol 或 schema。
- 结果依赖墙钟、随机数、真实设备、宿主路径、动态库或 mock Worker。
- checkpoint/event/hash 不可验证,或恢复会重复副作用。
- 仿真差异未定位到具体 tick、字段、单位或错误位置。

View File

@@ -0,0 +1,45 @@
# LinuxCNC 源测试对标执行计划
本计划只服务于 LinuxCNC 仿真功能对标。LinuxCNC 源程序测试工具是行为来源,WASM/native/Worker 适配器必须保留原测试输入、期望输出、错误语义和资源依赖;不能把自建 smoke test 当作源测试替代品。
## 对标对象
- `linuxcnc/scripts/runtests`:递归发现 `test.hal`、`test.sh`、`test`,执行 `halrun`/shell/executable,并按 `expected` 或 `checkresult` 判定。
- `linuxcnc/tests/**`:HAL regression/functional、interp、remap、IO、motion、tool、startup、经典梯形图、限位和配置测试。
- `linuxcnc/unit_tests/interp`:`test_interp` C++ 单元测试目标。
- `linuxcnc/unit_tests/tp`:`test_blendmath` TP 单元测试目标。
- `linuxcnc/configs/sim/**`:INI/HAL/程序/Python/VCP/CLP 启动闭包和用户工作流入口。
## 适配分类
1. `PURE_REGRESSION`:只依赖 `halrun`/解释器/TP/固定 tick,保留 stdout 与 `expected` 字节对照。
2. `PURE_FUNCTIONAL`:使用 `checkresult`,将检查输入和结果映射成稳定 JSON 状态。
3. `WORKER_SIM_ADAPTER`:需要真实 Worker session、配置启动或数字孪生;输入保持源文件原样。
4. `UNIT_NATIVE_WASM`:unit_tests C/C++ 目标建立 native 与 WASM 双 runner。
5. `HOST_EXCLUDED`:sudo、TCP、真实设备、内核实时、动态模块、GUI/窗口或任意宿主路径;只记录稳定排除原因,不伪造通过。
6. `SOURCE_BLOCKED`:源输入、expected、checkresult 或依赖缺失;保留 source_id 和诊断。
## 执行阶段
| 阶段 | 任务 | 产物 |
|---|---|---|
| S5-01 | 发现并分类源测试,复制 runtests 判定语义 | source-test matrix/report |
| S5-02 | 执行无宿主依赖的 runtests 纯仿真子集 | native/WASM/Worker JSONL diff |
| S5-03 | 迁移 `unit_tests/interp` 与 `unit_tests/tp` | CTest/WASM golden diff |
| S5-04 | 迁移 `tests/interp/**`、remap、O-word、filter | block/error/canonical diff |
| S5-05 | 迁移 HAL regression/functional 和 `.comp` | pin/signal/thread/output diff |
| S5-06 | 迁移 IO/startup/tool/limit/ClassicLadder | device/task/recovery diff |
| S5-07 | 批量执行 `configs/sim/**` 启动和工作流 | 233 entrypoint READY/BLOCKED/diff matrix |
| S5-08 | 汇总差异、重复执行和恢复终点 | full source-test parity report |
## 每个测试的证据
每个 source test 必须记录:`source_id`、路径、来源 hash、runner 命令、输入 fixture hash、expected/checkresult hash、适配分类、状态、stdout/stderr hash、首个差异字段/行、逻辑 tick、state/event hash、失败原因和下一步任务。宿主排除不计入通过率;缺失输入不降级为通过。
## 通过条件
- 源测试发现数与锁定 source index 一致,无孤儿、重复或静默跳过。
- `expected` 测试逐字节一致;`checkresult` 测试使用同一判定条件并输出结构化差异。
- native/WASM/Worker 使用同一输入和命令序列,首个差异可定位到 tick/字段/单位/错误列。
- 1x、fast、single-step、recover 的源测试终点 hash 一致。
- `HOST_EXCLUDED`、`SOURCE_BLOCKED` 独立统计,不伪造为 `PASSED`。

View File

@@ -68,6 +68,7 @@
| `PROJECT-AUDIT-01` | 整体审计确认 K0-K6 运动学实现和 15 项 native CTest 已通过;运动学 `partial/blocked` 仅因锁定来源缺少官方 oracle;当前开发瓶颈转为配置启动闭包,下一任务为 M3-CFG-01,K8 release 六项 blocker/`STOP_RELEASE` 独立保留 | `docs/linuxcnc-web-wasm-next-work.md`, `coverage/kinematics-registry.report.json`, `coverage/kinematics-motion.report.json`, `coverage/kinematics-feedback.report.json`, `coverage/kinematics-home-limit.report.json`, `coverage/configuration-regression.report.json` |
| `PROJECT-AUDIT-02` | 重新梳理任务图确认 M3/FE/REG 实现证据均已 verified;K8-REL-17 owner_inputs=0、gate_refresh=blocked,发现旧 Next 自引用风险;生成 GOV-01 readiness 后进入不自动重试的 WAIT-OWNER-01,六项 blocker 和 `STOP_RELEASE` 保持 verified | `docs/linuxcnc-web-wasm-task-map.md`, `coverage/project-task-readiness.report.json`, `nextTask.md` |
| `OWNER-INTAKE-01` | 建立六项 owner decision 输入模板、结构/identity/context/evidence hash 验证器和 blocked report;当前输入文件缺失,验证结果为 blocked,gate refresh 永远 blocked,不修改 context lock 或 release gate | `coverage/owner-decision-intake.template.json`, `coverage/owner-decision-intake.report.json`, `docs/linuxcnc-web-wasm-owner-decision-intake.md`, `scripts/validate_owner_decision_intake.py`, `scripts/test_owner_decision_intake.py` |
| `GOV-INTAKE-01` | 强化 owner decision intake 的持续接续门禁;非 approve、缺少 decision_set_id、仓库外/缺失证据路径、非十六进制或实际 hash 不匹配均 fail-closed;当前 owner 输入仍缺失,release gate 和 context lock 未修改 | `scripts/validate_owner_decision_intake.py`, `scripts/test_owner_decision_intake.py`, `docs/linuxcnc-web-wasm-continuation-plan.md` |
| `M3-CFG-01` | 确定性配置 resolver 和 Worker preflight 完成;16,093 条资源全部分类,15,112 resolved、981 blocked;显式 `LIB:`、参数尾缀、相对路径、仓库外路径和宿主路径均有明确策略;原始索引 hash、context lock、187 个脚本测试、15 个 native CTest 和 Worker/workspace 测试通过 | `web/workspace/configuration.mjs`, `web/worker/sim-session.mjs`, `coverage/configuration-startup-closure.report.json`, `scripts/generate_configuration_startup_closure.py`, `scripts/test_configuration_startup_closure.py`, `web/workspace/test_configuration.mjs`, `web/worker/test_configuration_preflight.mjs` |
| `M3-RT-02` | 生成 145 个 `.comp` 组件 manifest、1,220 pins、140 params、530 functions 和 193 个 HAL 文件的 4,566 条配置图记录;manifest、容量、资源边和动态加载拒绝检查 verified,29 个 `loadusr` 与 124 个变量化/未声明 `loadrt` 保持 blocked;190 个脚本测试、15 个 native CTest 和 Worker/workspace 测试通过 | `coverage/hal-component-manifest.report.json`, `scripts/generate_hal_component_manifest.py`, `scripts/test_hal_component_manifest.py`, `web/workspace/hal-configuration.mjs`, `web/worker/sim-session.mjs`, `web/worker/test_hal_preflight.mjs` |
| `M3-RT-03` | 虚拟设备故障矩阵完成;26 个 spindle/tool/probe/limit/estop/非有限/恢复场景进入 EventLog,连续执行与 replay state hash 一致,设备 checkpoint 增量恢复通过;192 个脚本测试、15 个 native CTest 和 Worker/workspace 测试通过 | `coverage/virtual-device-fault-matrix.report.json`, `scripts/generate_virtual_device_fault_matrix.py`, `scripts/test_virtual_device_fault_matrix.py`, `web/worker/virtual-devices.mjs`, `web/worker/test_virtual_devices.mjs`, `web/worker/test_device_recovery.mjs` |
@@ -77,6 +78,46 @@
| `FE-M2` | 完成核心 operation controls 和权威 state panel;run/pause/resume/abort/home/estop/recover 控制、operation 去重、错误/报警状态和窄屏布局 smoke 通过;200 个脚本测试、15 个 native CTest 和 Worker/workspace/Python 回归通过 | `coverage/frontend-m2.report.json`, `scripts/generate_frontend_m2.py`, `scripts/test_frontend_m2.py`, `web/app/controls.mjs`, `web/app/state-panel.mjs`, `web/app/test_frontend_m2.mjs` |
| `FE-M3` | 项目/恢复 workflow 完成;journal 导入导出、checkpoint/package、v1↔v2 migration、offline ready 和 half-commit 状态展示 smoke 通过;202 个脚本测试、15 个 native CTest 和 Worker/workspace/Python 回归通过 | `coverage/frontend-m3.report.json`, `scripts/generate_frontend_m3.py`, `scripts/test_frontend_m3.py`, `web/app/project-workflow.mjs`, `web/app/recovery-panel.mjs`, `web/app/test_frontend_m3.mjs` |
| `FE-M4` | 完成 HAL/tool/IO/3D frontend workflows;设备命令、HAL diagnostics、稳定 canvas machine view 和故障状态展示 smoke 通过;204 个脚本测试、15 个 native CTest 和 Worker/workspace/Python 回归通过 | `coverage/frontend-m4.report.json`, `scripts/generate_frontend_m4.py`, `scripts/test_frontend_m4.py`, `web/app/device-panel.mjs`, `web/app/hal-panel.mjs`, `web/app/machine-view.mjs`, `web/app/test_frontend_m4.mjs` |
| `S5-02` | 真实 LinuxCNC `runtests` 代表性纯仿真基线 12/12 native 通过;abort/G64 超时不伪造为回归通过,明确保留 Worker Task/motion 适配边界 | `coverage/linuxcnc-source-test-execution-s5.report.json`, `scripts/test_linuxcnc_source_test_execution.py` |
| `S5-03` | `unit_tests/interp` 与 `unit_tests/tp` 的 9 个可移植源断言由同一 native/WASM adapter 执行,CTest 通过且 JSON golden 字节一致;上游 Meson oracle 缺失标记 `SOURCE_BLOCKED`,G64/abort 保持 `WORKER_TASK_MOTION_PENDING` | `coverage/linuxcnc-source-unit-execution-s5.report.json`, `wasm-core/tests/source_unit_adapter_test.c`, `scripts/test_linuxcnc_source_unit_s5.py` |
| `S5-04` | `tests/interp`、`tests/oword` 与 `tests/remap` 的 8 个真实 fixture 由 WASM-backed Worker 执行;6 项 block/error/canonical/callback 适配通过,DO/G64 2 项明确保持 `WORKER_TASK_MOTION_PENDING`,26 个源/expected/checkresult/config 文件哈希闭合;源 canonical logger 继续 `SOURCE_BLOCKED` | `coverage/linuxcnc-source-interp-s5.report.json`, `web/worker/test_source_interpreter_s5.mjs`, `scripts/test_linuxcnc_source_interpreter_s5.py` |
| `S5-05` | HAL `abs`/`edge` 与 starting-high 边界由 Worker 静态运行时执行通过;native/WASM `sim_hal_test` golden 字节一致;自定义 `.comp`、相对头文件和 userspace/RTAPI 路径分别保留 `SOURCE_BLOCKED`/`HOST_EXCLUDED`,8 个源案例和 23 个 fixture 文件均有哈希 | `coverage/linuxcnc-source-hal-s5.report.json`, `web/worker/test_source_hal_s5.mjs`, `scripts/test_linuxcnc_source_hal_s5.py` |
| `S5-06` | IO/limit/tool ack Worker 适配 3 项通过;native/WASM `sim_io` 与 `sim_device_io` golden 字节一致;startup tool table 2 项 `SOURCE_BLOCKED`、ClassicLadder 1 项 `HOST_EXCLUDED`、motion-logger abort 1 项 `WORKER_TASK_MOTION_PENDING`,30 个 fixture 文件哈希闭合 | `coverage/linuxcnc-source-io-s5.report.json`, `web/worker/test_source_io_s5.mjs`, `scripts/test_linuxcnc_source_io_s5.py` |
| `S5-07` | 批量读取并哈希全部 264 个配置矩阵条目(216 个 `configs/sim`、48 个 tests 配置);56 READY、208 BLOCKED,逐项保留资源/诊断状态;batch checkpoint/restore、native/WASM/Worker startup probes 通过,静态 preflight 不提升为官方 runtime oracle | `coverage/linuxcnc-source-config-s5.report.json`, `web/worker/test_source_config_s5.mjs`, `scripts/test_linuxcnc_source_config_s5.py` |
| `S5-08` | 汇总 S5-01..S5-07 源证据;关键适配器重复运行稳定,native/WASM 静态 golden 全部一致,1x/fast/recovery/trace import 终点一致且 `first_divergence=null`;SOURCE_BLOCKED/HOST_EXCLUDED/WORKER_TASK_MOTION_PENDING 与官方 oracle 阻塞均保留 | `coverage/linuxcnc-source-parity-s5.report.json`, `web/worker/test_source_parity_s5.mjs`, `scripts/test_linuxcnc_source_parity_s5.py` |
| `S6-01` | 对完整仿真计划 P0-P8 的 39 个任务逐项对齐证据;S5 源测试链全部 verified;识别 authoritative sim_task tick integration、官方 native oracle、配置资源、source adapter 和浏览器/OPFS 五类开放 gap;创建下一执行任务 S6-02 | `coverage/full-linuxcnc-simulation-gap-audit.report.json`, `scripts/generate_full_linuxcnc_simulation_gap_audit.py`, `scripts/test_full_linuxcnc_simulation_gap_audit.py`, `nextTask1.md` |
| `S6-02` | 新增 authoritative runtime:程序行在 task phase 执行,XYZ/trivkins planner 在 tp/kinematics phase 更新,motion/HAL/IO 共用固定 tick;state 纳入 snapshot/checkpoint/trace/endpoint,1x/fast、recovery/trace import parity 通过;非 trivkins和完整 canonical oracle 保持后续/blocked | `coverage/authoritative-sim-task-s6.report.json`, `web/worker/authoritative-runtime.mjs`, `web/worker/test_authoritative_sim_task_s6.mjs`, `scripts/test_authoritative_sim_task_s6.py` |
| `S6-03` | authoritative runtime 扩展 CoreXY:XYZ pose `[4,2,3]` 映射到 joints `[6,2,3]`;native/WASM kinematics 与 kinematics-motion golden、1x/fast/recovery endpoint parity 通过;unsupported `puma` 稳定拒绝,其他 families 和官方 oracle 保留后续/blocked | `coverage/authoritative-kinematics-s6.report.json`, `web/worker/test_authoritative_kinematics_s6.mjs`, `scripts/test_authoritative_kinematics_s6.py` |
| `S6-04` | authoritative runtime 接入一个可验证的并联 Tripod family:真实 `tripodkins` 配置/几何 `[0,0],[10,0],[5,7.071]`,pose `[2,3,4]` 逆映射为三支杆 `[5.385164807,9.433981132,6.447715952]`;native/WASM kinematics 与 kinematics-motion golden、1x/fast/recovery endpoint parity 和首差诊断通过;TRT、机器人、Delta/Hexapod/Pentapod、switch/user 与官方 oracle 明确保留 queued/blocked | `coverage/authoritative-kinematics-s6-04.report.json`, `web/worker/test_authoritative_kinematics_s6_04.mjs`, `scripts/test_authoritative_kinematics_s6_04.py`, `web/worker/authoritative-runtime.mjs` |
| `S6-05` | 新增 OPFS Dedicated Worker 探针、逻辑 journal/offline integrity 测试和确定性报告;Playwright headed Chromium 140 两次完成 sync-access-handle 写入/读取/清理并稳定一致,headless timeout 作为边界保留;Safari/Firefox 明确 OUT_OF_SCOPE,物理 crash/restart oracle 和 release/oracle blocker 不被升级为闭合 | `coverage/authoritative-browser-s6-05.report.json`, `web/workspace/opfs-runtime.mjs`, `scripts/test_browser_opfs_playwright_s6_05.mjs`, `web/app/test_opfs_runtime_s6_05.mjs`, `scripts/test_authoritative_browser_s6_05.py` |
| `S6-06` | 使用同一 headed Chromium 140 persistent profile:第一阶段提交 OPFS record 后关闭 browser context,第二阶段重开 profile 读取相同 content hash 并清理;两次运行稳定,profile restart slice verified;真实进程 crash/power-loss oracle 和 release blocker 保留,Safari/Firefox 明确 OUT_OF_SCOPE | `coverage/authoritative-browser-restart-s6-06.report.json`, `scripts/test_browser_opfs_restart_s6_06.mjs`, `scripts/test_authoritative_browser_restart_s6_06.py`, `web/workspace/opfs-runtime.mjs` |
| `S6-07` | 使用 Playwright BrowserServer kill 真实终止 Chromium 进程,再以同一 profile 重开并读取 committed OPFS record;两次运行 process-kill、hash continuity 和 cleanup 均 verified;power-loss/filesystem-corruption 与 release/oracle blocker 保留,Safari/Firefox 明确 OUT_OF_SCOPE | `coverage/authoritative-browser-crash-s6-07.report.json`, `scripts/test_browser_opfs_crash_s6_07.mjs`, `scripts/test_authoritative_browser_crash_s6_07.py`, `web/workspace/opfs-runtime.mjs` |
| `S7-AUDIT` | 重新梳理 LinuxCNC 完整仿真计划、264 配置入口、S5 source parity、S6 authoritative/runtime/browser evidence;确认配置 `56 READY/208 BLOCKED`、DO/ENDDO 与 G64/G61 pending、剩余 kinematics queued、官方 oracle/release blocked;创建并认领 S7-01 | `coverage/simulation-alignment-s7.report.json`, `scripts/generate_simulation_alignment_audit_s7.py`, `scripts/test_simulation_alignment_s7.py` |
| `S7-01` | 接入锁定 `linuxcnc/tests/interp/do-while-break/test.ngc` 的 DO/ENDDO/BREAK 后测循环 slice;嵌套 BREAK、named parameters、pause/resume、malformed ENDDO、depth budget 和 checkpoint recovery parity 通过;上游 canonical expected 保持 `SOURCE_BLOCKED` | `coverage/source-do-s7-01.report.json`, `web/worker/test_source_do_s7_01.mjs`, `scripts/test_source_do_s7_01.py`, `web/worker/program-runner.mjs`, `web/worker/sim-session.mjs` |
| `S7-02` | 接入锁定 `linuxcnc/tests/interp/g6164/test.ngc` 的 G64 continuous/P/Q、G61 exact-path、G61.1 exact-stop modal state;负 tolerance/unsupported code、pause/recovery parity 通过;S5-04 pending 清零,canonical logger 与 TP numeric parity 仍保持明确边界 | `coverage/source-g6164-s7-02.report.json`, `web/worker/test_source_g6164_s7_02.mjs`, `scripts/test_source_g6164_s7_02.py`, `web/worker/program-runner.mjs`, `web/worker/sim-session.mjs` |
| `S7-03` | 选择有真实配置/native-WASM 样本且保持 XYZ/3-joint 形状的 `lineardeltakins`,接入 authoritative fixed tick;pose `[0,0,64.636584194]` 映射三 carriage joints `[300,300,300]`,1x/fast/recovery parity、无解 fail-closed 和 unsupported TRT boundary 通过 | `coverage/authoritative-kinematics-s7-03.report.json`, `web/worker/test_authoritative_kinematics_s7_03.mjs`, `scripts/test_authoritative_kinematics_s7_03.py`, `web/worker/authoritative-runtime.mjs` |
| `S7-04` | 接入 `rotarydeltakins` authoritative fixed tick;pose `[0,0,-3.793360169]` 映射 rotary joints `[10,10,10]`,1x/fast/recovery parity、z=0 singular fail-closed 和 unsupported TRT boundary 通过;缺失 rdelta HAL 与官方 oracle 保持边界 | `coverage/authoritative-kinematics-s7-04.report.json`, `web/worker/test_authoritative_kinematics_s7_04.mjs`, `scripts/test_authoritative_kinematics_s7_04.py`, `web/worker/authoritative-runtime.mjs` |
| `S7-05` | 对齐真实 `corexy_by_kins.ini` 的 LinuxCNC `#INCLUDE`、HAL 变量和反斜杠续行;HAL 72 条 preflight records 全部 ready,但 runtime 正确 BLOCKED 在缺失 `linuxcnc.var/tool.tbl`,未提升 static READY | `coverage/configuration-corexy-s7-05.report.json`, `web/worker/test_configuration_corexy_s7_05.mjs`, `scripts/test_configuration_corexy_s7_05.py`, `web/workspace/ini-parser.mjs`, `web/workspace/hal-configuration.mjs`, `web/workspace/configuration-startup.mjs` |
| `S7-06` | verified:依据 `stepconf/build_INI.py` 的精确 `INTRO_GRAPHIC = linuxcnc.gif` 约定,将 `linuxcnc/linuxcnc.gif` 作为 DISPLAY-only shared simulation asset;同 basename 的 tool/parameter/HAL/program 和非 DISPLAY 键保持 blocked;资源图 state hash、source fixture、self-hash 和 native/Worker/App 全量回归通过。S7 后续技术任务未定义,指针保持 `next_task: none` | `coverage/resource-intro-graphic-s7-06.report.json`, `web/worker/test_resource_intro_graphic_s7_06.mjs`, `scripts/test_resource_intro_graphic_s7_06.py`, `web/workspace/resource-resolver.mjs`, `nextTask1.md` |
| `S8-01` | verified:从真实 `linuxcnc/configs/sim` 生成 235 个 INI 案例和 2,080 个精确文件索引;递归 INI/HAL/resource loader 保留缺失诊断并把 static READY 与 runtime READY 分开;AppShell 提供案例筛选、Worker startup、G-code、MDI、Run/Pause/Step、Home/Jog、倍率、主轴/刀具/探针/急停和 machine view。235 个案例中 4 个 loader-ready、其余保留实际资源/HAL blockers | `coverage/sim-case-catalog.report.json`, `scripts/generate_sim_case_catalog.py`, `scripts/test_sim_case_catalog.py`, `web/workspace/sim-case-catalog.mjs`, `web/workspace/sim-case-loader.mjs`, `web/workspace/test_sim_case_loader.mjs`, `web/app/app.mjs`, `web/app/styles.css` |
| `S8-02` | verified:用户授权从真实 LinuxCNC 仿真执行复制 runtime fixtures;`minimal_xyz` 的 `sim.var`/生成 HAL 和 CoreXY 的 `linuxcnc.var`/`tool.tbl` 均 exact-path hash-lock;预加载 `corexykins/motmod/pid/stepgen` 与虚拟 `hal_manualtoolchange` 适配通过,两个案例 Worker startup 均达到 `TASK_READY`,未知 `loadusr` 仍 blocked | `coverage/sim-case-startup-s8-02.report.json`, `web/worker/test_sim_case_startup_s8_02.mjs`, `scripts/generate_sim_case_startup_s8_02.py`, `scripts/test_sim_case_startup_s8_02.py`, `web/workspace/hal-configuration.mjs`, `web/workspace/sim-case-loader.mjs` |
| `S8-03` | verified:真实执行 `xz.ini`、`xz_both.ini`、`xz_both_auto.ini` 取得 `xz.var` 和三份生成 HAL fixture;同案例 `xz.tbl` 精确复用;三案 Worker startup 均 `TASK_READY`、HAL blocked_count=0,identity/BOTH/AUTO state hash 分别保留 | `coverage/sim-case-batch-s8-03.report.json`, `web/worker/test_sim_case_batch_s8_03.mjs`, `scripts/generate_sim_case_batch_s8_03.py`, `scripts/test_sim_case_batch_s8_03.py` |
| `S8-04` | verified:minimal_xyz 真实 fixture 达到 TASK_READY;固定 tick 覆盖 Home/Jog/override、G-code Run/Pause/Resume/Abort/Restart、MDI、estop/recover 和 checkpoint recovery endpoint parity;前端 AppShell/state panel/machine view 继续消费 Worker 权威状态 | `coverage/minimal-xyz-vertical-s8-04.report.json`, `web/worker/test_minimal_xyz_vertical_s8_04.mjs`, `scripts/generate_minimal_xyz_vertical_s8_04.py`, `scripts/test_minimal_xyz_vertical_s8_04.py` |
| `S8-05` | verified:`corexy_by_kins.ini` 与 `corexy_by_hal.ini` 均使用真实 fixtures 达到 TASK_READY;同一 pose `[4,2,3]` 映射 joints `[6,2,3]`,HAL records 72/100,1x/fast/recovery parity 均通过;kins path 与 HAL-trivkins transform path 保持明确区分,未知 HAL 命令仍 fail-closed | `coverage/corexy-dual-path-s8-05.report.json`, `web/worker/test_corexy_dual_path_s8_05.mjs`, `scripts/generate_corexy_dual_path_s8_05.py`, `scripts/test_corexy_dual_path_s8_05.py`, `web/workspace/hal-configuration.mjs` |
| `S8-06` | verified:235 个真实 `configs/sim` 案例全部执行 exact-path loader/startup 两次;分类为 TASK_READY=7、BLOCKED_RESOURCE=221、BLOCKED_HAL=4、BLOCKED_INI=3;每案保留 fixture、missing、first diagnostic、resource/HAL counts 和 deterministic state hash,不把 blocked 提升为 ready | `coverage/sim-case-matrix-s8-06.report.json`, `web/worker/test_sim_case_matrix_s8_06.mjs`, `scripts/generate_sim_case_matrix_s8_06.py`, `scripts/test_sim_case_matrix_s8_06.py` |
| `S8-07` | verified:从真实 INI/include declarations 生成 235-case display family catalog;Axis 85、QtVCP 61、Gscreen 14、VisMach 21、GladeVCP 6、Touchy 6、PyVCP 5、other 37;AppShell 按案例显示 family capabilities/host plugin boundaries,未改变 Worker 权威状态或 blocked 语义 | `coverage/sim-display-families-s8-07.report.json`, `web/app/sim-display-families.mjs`, `web/app/display-family.mjs`, `web/app/test_display_family_s8_07.mjs`, `scripts/generate_sim_display_families_s8_07.py`, `scripts/test_sim_display_families_s8_07.py` |
| `S8-08` | verified:ldelta/rdelta 真实案例通过 HALLIB exact resolution、sim.var/sim.tbl fixtures、lineardelta/rotarydelta virtual adapters;nominal joints `[300,300,300]`/`[10,10,10]`、1x/fast/recovery parity 和 TASK_READY 通过,official oracle 与其它机床族边界保留 | `coverage/machine-families-s8-08.report.json`, `web/worker/test_machine_families_s8_08.mjs`, `scripts/generate_machine_families_s8_08.py`, `scripts/test_machine_families_s8_08.py` |
| `S8-09` | verified:10 个真实 Worker runtime extension runners 全部通过,覆盖 remap/O-word/filter、Python callbacks、tool/probe/IO ack、virtual devices 和 PLC;固定 tick、能力拒绝和 recovery/ack 边界保留,host Python/dynamic loader 不被误报为浏览器 parity | `coverage/runtime-extensions-s8-09.report.json`, `scripts/generate_runtime_extensions_s8_09.py`, `scripts/test_runtime_extensions_s8_09.py` |
| `S8-10` | blocked(正式停止条件):新增最终 235-case acceptance 聚合;WASM/native/Worker/App 构建与回归 72/72 通过,10 个案例 TASK_READY、225 个案例保留 resource/HAL/INI/STARTUP blockers,display/machine family 与 runtime extension 证据已汇总;official full LinuxCNC oracle 仍 source-gated,Chromium/Firefox/Safari minimums 仍 TBD/Safari unavailable;implementation coverage=verified、acceptance=blocked、`STOP_RELEASE`,不宣称 LinuxCNC 全功能 release | `coverage/full-case-acceptance-s8-10.report.json`, `scripts/generate_full_case_acceptance_s8_10.py`, `scripts/test_full_case_acceptance_s8_10.py`, `nextTask1.md` |
| `FE-M1-REACT` | verified:按技术路线新增 React 19/TypeScript/Vite/Tailwind/Radix/Three.js 前端入口;Dedicated Worker/WASM bundle、protocol.v1 reducer、exact-path `configs/sim` loader、LinuxCNC AXIS source icons 和 Three.js r185 三轴 viewer 通过 typecheck/build/preview;OPFS 仍 Worker-owned | `coverage/react-frontend-m1.report.json`, `web/react`, `scripts/generate_react_frontend_m1.py`, `scripts/test_react_frontend_m1.py` |
| `FE-M4-GUI-01` | verified:扫描 LinuxCNC AXIS/Gmoccapy/Touchy/Gscreen/QtVCP/PyVCP/GladeVCP/Vismach/NGCGUI/QtPlasmaC 等 GUI 源码、Python 库、sim descriptors/assets,1837 条文件记录、12 个 family、source hash/path 通过;341 条 manifest 反向归属缺口保留审计,许可证不阻塞技术移植 | `coverage/gui-source-inventory-fe-m4.report.json`, `scripts/generate_gui_source_inventory.py`, `scripts/test_gui_source_inventory.py`, `nextTask1.md` |
| `FE-M4-GUI-02` | verified:集中 React GUI domain model,定义 12 family、23 个 protocol.v1 Worker command、panel/capability/boundary 映射;PY-WASM、SIM-DEVICE、WEB-EQUIV、REAL-EXCLUDED 和 Worker/OPFS ownership 均有 contract evidence | `coverage/react-gui-domain-fe-m4.report.json`, `web/react/src/gui-domain.ts`, `scripts/generate_react_gui_domain_report.py`, `scripts/test_react_gui_domain_report.py` |
| `FE-M4-GUI-03` | verified:对照 LinuxCNC AXIS/Gremlin/glcanon 完成 React AXIS Web-equivalent workflow;program/MDI/run/pause/step/restart/abort/jog/home/override/spindle/tool/probe/coolant/estop/recover/DRO/Three.js 由 Worker 驱动,minimal_xyz Worker regression 和 React build 通过 | `coverage/axis-web-workflow-fe-m4.report.json`, `web/react/src/App.tsx`, `web/react/src/worker-client.ts`, `scripts/generate_axis_web_workflow_report.py`, `scripts/test_axis_web_workflow_report.py` |
| `FE-M4-GUI-04` | verified:将 Gmoccapy/Touchy/Gscreen/QtVCP/QtDragon/PyVCP/GladeVCP/Vismach/NGCGUI/QtPlasmaC/Plasma 转为 family descriptor;Web Component、Three.js、PY-WASM 和 REAL-EXCLUDED 边界集中定义,12 family contract 通过 | `coverage/gui-family-adapter-fe-m4.report.json`, `web/react/src/gui-family-adapter.ts`, `scripts/generate_gui_family_adapter_report.py`, `scripts/test_gui_family_adapter_report.py` |
| `FE-M4-GUI-05` | verified:建立 vismach/glcanon/NGCGUI/QtPlasmaC 的 Three.js visual workflow mapping;pose/joints/toolpath/stock/material/torch 只读 Worker snapshot,PY-WASM/真实硬件边界保留 | `coverage/gui-visual-workflow-fe-m4.report.json`, `web/react/src/visual-workflow.ts`, `scripts/generate_gui_visual_workflow_report.py`, `scripts/test_gui_visual_workflow_report.py` |
| `FE-M4-GUI-06` | blocked(正式停止条件):现有 Chromium production preview desktop/mobile DOM、截图、Three.js canvas smoke verified;三浏览器 minimum matrix仍 TBD,Safari/Firefox 和 OPFS recovery 保持 blocked/STOP_RELEASE,不把 Chromium smoke 误报为全 GUI release | `coverage/gui-browser-visual-fe-m4.report.json`, `scripts/generate_gui_browser_visual_report.py`, `scripts/test_gui_browser_visual_report.py`, `nextTask1.md` |
| `REAL-CASE-CONDITIONS-01` | 真实 LinuxCNC `linuxcnc -r` 临时目录执行 verified:minimal_xyz 和 CoreXY 均进入真实 TASK tick;当前环境使用 `linuxcnc-uspace 2.10.0~pre1`、非 `PREEMPT_RT` 内核的 POSIX fallback、X11 DISPLAY;CoreXY 缺 tool.tbl 时出现官方 tool-table error,补入临时 linuxcnc.var/tool.tbl 后持续运行;参数文件会在可写目录中生成/更新,临时 fixture 不纳入 source parity | `coverage/native-linuxcnc-case-conditions.report.json`, `scripts/generate_native_linuxcnc_case_conditions.py`, `scripts/test_native_linuxcnc_case_conditions.py`, `linuxcnc/docs/src/getting-started/system-requirements.adoc` |
| `CASE-PARITY-PLAN-01` | 建立以真实 `configs/sim` 案例为中心的 S8-03..S8-10 执行队列;定义每案例 native/Worker/frontend parity contract、资源生成条件、Axis/QtVCP/Gscreen/Touchy/GladeVCP/PyVCP/VisMach 家族和 235-case full acceptance;S8-02 blocker 未被绕过 | `docs/linuxcnc-web-wasm-case-parity-plan.md`, `nextTask1.md` |
## 追溯规则