Enforce complete AXIS control inventory

This commit is contained in:
2026-09-07 15:48:49 +08:00
parent 0a679b5eeb
commit bc69c513e3
12 changed files with 261 additions and 54 deletions

View File

@@ -72,11 +72,11 @@ replaced by a different action.
| Source surface | Source entries | Web treatment |
| --- | --- | --- |
| File menu | Open, Recent Files, Edit, Reload, Save As, Properties, Edit Tool Data, Reload Tool Data, Ladder Editor, Quit | Open/Reload/Load are Worker-backed; editor text is the Web file source; save, external editors, Ladder and Quit are host-boundary status/disabled entries. |
| File menu | Open, Recent Files, Edit, Reload, Save As, Properties, Edit Tool Data, Reload Tool Data, Ladder Editor, Quit | Open and Reload have one visible toolbar entry each. Edit Tool Data and Quit remain visible but disabled with a host-boundary reason. Other desktop-only entries are not rendered. |
| Machine menu | E-stop, Power, Run, Run from selected line, Step, Pause, Resume, Stop, Optional Stop, Block Delete, MDI history, Calibration/HAL tools, Homing, Unhoming, Zero coordinate system, Tool touch-off target | E-stop/Power/Run/Step/Pause/Resume/Stop/Home/Touch Off are represented by documented commands; Run-from-line, MDI clipboard/file actions, calibration/HAL desktop tools and Unhoming are not exposed; Optional Stop, Block Delete, Override Limits and Tool Touch Off remain ABI-blocked. |
| View menu | Six preset views, inches/mm, show program/rapids/live plot/tool/extents/offsets/limits/velocity/DTG, grid, DRO font, PyVCP, commanded/actual, machine/relative, joint/world, clear plot | Preset view/zoom/rotate, units, commanded/actual, machine/relative and supported visual layers are Web projections; unsupported teleop, grid/DTG/font/PyVCP settings are not aliased to motion state. |
| Toolbar | E-stop, Power, Open, Reload, Run, Step, Pause/Resume, Stop, Block Delete, Optional Stop, zoom, six views, rotate, Clear Plot | Same source order and icon assets are retained for supported controls; unsupported controls are disabled with a source/ABI reason. |
| Manual notebook | Axis/joint selector, continuous/increment jog, Home Axis, Touch Off, Tool Touch Off, Override Limits, spindle direction/stop/speed/brake, coolant, tool/probe | XYZAC axis selector, jog, Home Axis, Touch Off, spindle, coolant, tool and probe are represented; joint selector, Tool Touch Off and Override Limits are explicitly bounded by the selected configuration/ABI. |
| Manual notebook | Axis/joint selector, continuous/increment jog, Home Axis, Touch Off, Tool Touch Off, Override Limits, spindle direction/stop/speed/brake and coolant | XYZAC axis selector, jog, Home Axis, Touch Off, spindle and coolant are represented. Joint selection, Tool Touch Off and Override Limits are explicitly bounded by the selected configuration/ABI. Tool and probe state is read-only; Prepare/Change/Arm/Disarm are IO/HAL operations, not AXIS main-panel controls. |
| Web case strip | no AXIS equivalent | `Load exact XYZAC TRT case` is a Web workspace/bootstrap control, not an AXIS source button. It may only call the same documented `LOAD_WORKSPACE` + `PROGRAM_LOAD` transaction and must not introduce a second Run/Power/Home flow. |
| MDI notebook | MDI entry, Go, history selection/double-click, Up/Down history, Ctrl-M/H/Shift-H clipboard operations | Entry, Go and local history are represented; clipboard/file history operations are host/UI-only and are not sent as machine commands. |
| Browser UI persistence | AXIS preferences do not override `[DISPLAY] OPEN_FILE` with executable source text | OPFS may persist presentation preferences such as view, zoom, tabs, units and selected axis. It must not persist or automatically load G-code source/path. |
@@ -127,7 +127,7 @@ command transaction, not a React state assignment.
| Emergency Stop / Cancel | `ESTOP {active}` | `estop_clicked` toggles `STATE_ESTOP` and `STATE_ESTOP_RESET`; active E-stop aborts the interpreter and TP, then keeps the loaded taskfile. |
| Power on / off | `POWER {active}` | `onoff_clicked` toggles `STATE_ON` and `STATE_OFF`; power-off aborts motion but preserves the loaded file. |
| Open G-code file | browser file + `PROGRAM_LOAD` | `open_file_guts`: poll, save mode, enter MANUAL, restore the saved tab mode before `PLAN_OPEN/program_open`, set first line, synchronize, parse/preview, then `set_mode_from_tab` after refresh. |
| Load case / Load editor | `PROGRAM_LOAD` | Same replacement transaction as `open_file_guts`; old preview is cleared before parsing and never reused after a failed replacement. |
| Load case / packaged program / edited source | `LOAD_WORKSPACE` and/or `PROGRAM_LOAD` | The Web case bootstrap and packaged-program selector use the same replacement transaction as `open_file_guts`. Edited text is submitted only through the single toolbar Reload command; the program pane has no duplicate Load/Run/Step buttons. Old preview is cleared before parsing and never reused after a failed replacement. |
| Switchkins Identity / TCP: XYZAC / User K | `KINEMATICS_SELECT {type}` | Selected-case remap equivalent for `M429`/`M428`/`M430` from `xyzac-trt.ini`; requires homed, idle, empty TP queue and canonical HAL switchkins state. |
| Run | `PROGRAM_RUN` | `run_warn`, `ensure_mode(AUTO)`, `AUTO_RUN` from the selected start line, then periodic task/TP ticks. Normal AXIS Run uses line 0. In `emctaskmain.cc`, an ended or aborted task plan is closed; the next `EMC_TASK_PLAN_RUN` reopens the current taskfile and runs from line 0. Therefore Run after `completed` or `aborted` must work directly and must not require a separate Reload/Restart click. |
| Run from selected line | not exposed | AXIS `task_run_line` requires an editor highlight and source `AUTO_RUN` start line. The Web editor has no source-line selection command yet, so no partial/fake button is rendered. |
@@ -151,8 +151,7 @@ command transaction, not a React state assignment.
| Spindle - / + | `SPINDLE_COMMAND {delta}` → `SPINDLE_CONSTANT` on release | AXIS binds Button-1 to `spindle_decrease`/`spindle_increase` and ButtonRelease to `spindle_constant`; Web preserves this press/release sequence. |
| Brake | `SPINDLE_BRAKE` | Source brake command, gated by `manual_ok`. |
| Mist / Flood | `COOLANT_COMMAND` | Independent source coolant toggles; canonical device IO is returned after every edge. |
| Prepare / Change tool | `TOOL_PREPARE` / `TOOL_CHANGE` | Source tool IO authority and acknowledgement path; no simulated completion is reported before the Worker verifies it. |
| Arm / Disarm probe | `PROBE_CONFIG` | Source probe IO authority; faults and E-stop remain Worker-owned. |
| Tool / probe status | read-only | AXIS does not put Prepare/Change/Arm/Disarm buttons in this manual notebook. Tool changes remain interpreter/MDI and IO/HAL operations. Web displays canonical tool/probe state but exposes no extra main-panel command buttons. |
| Jog Speed | `SET_JOG_SCALE` | `update_jog_slider_vel` writes the source linear jog scale. |
| Angular Jog Speed | not exposed | AXIS has a separate `ajogspeed` control for rotary joints; the selected WASM TP exposes one shared jog scale only, so the Web panel does not alias linear Jog Speed to this control. |
| Feed Override | `SET_OVERRIDE` | `set_feedrate` writes the source feed override; updates are debounced but ordered in the Worker queue. |
@@ -160,7 +159,69 @@ command transaction, not a React state assignment.
| Max Velocity | `SET_MAX_VELOCITY` | AXIS `set_maxvel` calls `c.maxvel` and changes the trajectory velocity limit. The selected WASM TP exposes this as its velocity scale. |
| Rapid Override | disabled | AXIS `set_rapidrate` calls `c.rapidrate` and is distinct from Max Velocity. The selected WASM TP has no rapid-scale setter, so the Web control is disabled with `blocked_by_abi_rapidrate`. |
| MDI command/history | `MDI_EXECUTE` | `send_mdi` validates `manual_ok`, enters MDI, de-duplicates adjacent history entries and submits `c.mdi`. |
| File edit/tool data/quit and desktop diagnostics | disabled or status-only | AXIS source launches external editor, tool editor, Ladder, HAL tools, LinuxCNC status and process quit. These are host-boundary operations and are not represented as browser controls. |
| File tool-data editor / Quit | disabled | AXIS launches a host editor or terminates the desktop process. Browser controls remain visibly disabled with `host_boundary_tool_editor` / `host_boundary_process_quit`; clicking them cannot report a false success. |
| About AXIS | local dialog | Mirrors the source `.about` dialog and its OK/close action. It changes no Worker, task, TP or IO state. |
## Complete Web Control Inventory
Every rendered actionable element has a stable `data-axis-control` value. This
table is exhaustive for the selected XYZAC panel. A control may not be added to
React until its ID, source mapping, gate and result are added here. Repeated MDI
history rows intentionally share the family ID `mdi-history-select`.
| Control ID(s) | Source mapping | Operation and gate | Accepted result / disabled behavior |
| --- | --- | --- | --- |
| `menu-file`, `menu-help` | `axis.tcl` File/Help cascades | Local menu disclosure; always available | Opens/closes menu only; no machine state change |
| `menu-file-edit-tool-data`, `menu-file-quit` | `edit_tooltable`, `quit` host process operations | Permanently disabled in a browser | `host_boundary_tool_editor` / `host_boundary_process_quit`; no fake status success |
| `menu-help-about`, `about-close` | `.menu.help` About entry and `.about.ok` | Local modal open/close | About visibility changes only |
| `toolbar-estop` | `.toolbar.machine_estop` -> `estop_clicked` | `ESTOP {active}`; accepted from every task state | Toggle source E-stop edge; active edge aborts interpreter/TP |
| `toolbar-power` | `.toolbar.machine_power` -> `onoff_clicked` | `POWER {active}`; reset E-stop before power-on | Canonical `STATE_ON`/`STATE_OFF`; power-off aborts motion |
| `toolbar-open`, `program-file-input` | `.toolbar.file_open` -> `open_file`/`open_file_guts` | File picker then `PROGRAM_LOAD`; interpreter must be IDLE | One replacement transaction; input itself is hidden and only the toolbar button opens it |
| `toolbar-load-case` | Web workspace boundary; uses INI `DISPLAY`, `HAL`, `KINS` and `OPEN_FILE` inputs | `LOAD_WORKSPACE` then the documented `PROGRAM_LOAD`; IDLE only | Reloads the selected exact case; never adds Power/Home/Run aliases |
| `toolbar-reload` | `.toolbar.reload` -> `reload_file` | `PROGRAM_LOAD` of current editor source/path; IDLE taskfile required | Replaces preview/interpreter at line 0; this is the only visible commit action for edited source |
| `toolbar-run` | `.toolbar.program_run` -> `task_run` | `PROGRAM_RUN`; ON, taskfile, IDLE and task-layer homing gate | AUTO/RUNNING from line 0; completed/aborted taskfile reopens directly |
| `toolbar-step` | `.toolbar.program_step` -> `task_step` | `PROGRAM_STEP`; ON, taskfile and homing gate | AUTO_STEP then PAUSED at the next source boundary |
| `toolbar-pause-resume` | `.toolbar.program_pause` -> `task_pauseresume` | Pause while READING/WAITING; Resume while PAUSED | One source toggle whose icon/label and command follow canonical pause state |
| `toolbar-stop` | `.toolbar.program_stop` -> `task_stop` | `PROGRAM_ABORT`; visible button enabled only for non-IDLE interpreter | Abort, drain/clear TP and retain selected taskfile |
| `toolbar-block-delete`, `toolbar-optional-pause` | Source toolbar toggles | Permanently disabled for selected ABI | `blocked_by_abi`; no React-only toggle |
| `toolbar-zoom-in`, `toolbar-zoom-out` | `zoomin`, `zoomout` | Local preview camera only | Bounded camera zoom; task/TP unchanged |
| `toolbar-view-z`, `toolbar-view-z2`, `toolbar-view-x`, `toolbar-view-y`, `toolbar-view-y2`, `toolbar-view-p` | `set_view_z/z2/x/y/y2/p` | Local source view selection | Exactly one pressed view; opens Preview tab; machine state unchanged |
| `toolbar-rotate` | `.toolbar.rotate` | Local drag/rotate projection | Toggles pressed state and viewer interaction only |
| `toolbar-clear-live-plot` | `clear_live_plot` -> `positionlogger.clear()` | Worker `VISUAL_CLEAR`; always visual-only | Advances `live_path_epoch`, clears Live Plot only and retains static preview |
| `workspace-case-select` | Web selection of the INI/configuration input | Local selection; selected catalog is restricted to supported XYZAC case | Does not load or change machine state until `toolbar-load-case` |
| `workspace-load-3d-chips` | Web packaged-file equivalent of `open_file_guts` | Fetch published `3D_Chips.ngc`, then `PROGRAM_LOAD`; IDLE only | Same canonical file replacement path as Open; no automatic Run/Home |
| `manual-home-all` | Machine Homing menu -> `home_all_joints` | `HOME {all:true}`; `manual_ok`, then MANUAL | First Home homes all; canonical homed mask changes label to Re-home; repeat asks source confirmation |
| `switchkins-0`, `switchkins-1`, `switchkins-2` | `M429`, `M428`, `M430` remaps and `motion.switchkins-type` | `KINEMATICS_SELECT`; ON, homed, IDLE, empty TP | Identity/XYZAC/User K canonical type, or stable gate reason |
| `tab-manual`, `tab-mdi` | AXIS notebook F3/F5 `ensure_manual`/`ensure_mdi` | `SET_MODE`; no active AUTO motion | Tab selection plus acknowledged MANUAL/MDI mode change |
| `tab-diagnostics` | Web diagnostics boundary | Local tab only | Reads Worker state/gates; sends no command |
| `tab-preview`, `tab-dro` | AXIS preview/DRO presentation | Local tab only | Changes visible projection; machine state unchanged |
| `manual-axis-x`, `manual-axis-y`, `manual-axis-z`, `manual-axis-a`, `manual-axis-c` | AXIS axis radio group / `ja_rbutton` | Local axis selection | Supplies the selected axis to Jog/Home/Touch Off; sends no motion by itself |
| `manual-jog-increment` | `jogincrement` combobox | Local choice: Continuous or configured increment | Determines `JOG_CONTINUOUS` versus `JOG_INCREMENT` payload only |
| `manual-jog-negative`, `manual-jog-positive` | `jogminus`, `jogplus` -> `jog_on` | `JOG_START`; visible Manual tab, ON, IDLE, homed | Incremental submits once; Continuous repeats source-rate segments while held |
| `manual-home-axis` | `home_joint` | `HOME {axis}`; `manual_ok`, MANUAL, identity kinematics for coordinate-axis home | Canonical joint home; repeated home asks confirmation |
| `manual-touch-off` | `touch_off_system` | `TOUCH_OFF`; ON, homed, IDLE, MANUAL and valid value/system | MDI `G10 L20`, synchronize, reload and restore saved mode |
| `manual-tool-touch-off` | `touch_off_tool` | Permanently disabled for selected ABI | `blocked_by_abi_tool_offsets`; never approximated with `G92`/fixed `G43` |
| `manual-override-limits` | `toggle_override_limits` | Permanently disabled for selected ABI | No state mutation; explanatory ABI title |
| `manual-spindle-ccw`, `manual-spindle-stop`, `manual-spindle-cw` | spindle radio group -> `spindle` | `SPINDLE_COMMAND`; `manual_ok`, MANUAL | Canonical signed RPM/direction determines pressed state |
| `manual-spindle-decrease`, `manual-spindle-increase` | `spindle_decrease/increase`; ButtonRelease -> `spindle_constant` | Enabled only while spindle direction is nonzero, matching `axis.tcl update_state` | Press sends speed edge without crossing through zero into the opposite direction; release/cancel sends `SPINDLE_CONSTANT` |
| `manual-spindle-brake` | `brake` | `SPINDLE_BRAKE`; same manual source gate | Canonical brake state controls checkbox |
| `manual-coolant-mist`, `manual-coolant-flood` | manual-group `mist`/`flood` controls | `COOLANT_COMMAND`; visible checkboxes require ON and IDLE | Independent canonical coolant bits; disabled during AUTO activity |
| `mdi-command`, `mdi-submit` | MDI entry and `send_mdi` | Local text; submit/Enter sends `MDI_EXECUTE` under `manual_ok`/queue gate | Trimmed nonempty block, MDI mode, canonical interpreter result |
| `mdi-history-select` | AXIS MDI history row selection | Local history selection | Copies selected prior command into entry; does not execute until Submit/Enter |
| `preview-panLeft`, `preview-panRight`, `preview-panUp`, `preview-panDown`, `preview-reset` | Web accessible equivalent of Gremlin mouse pan/reset | Local camera only | Moves/resets camera; no Worker command |
| `dro-coordinate`, `dro-display`, `dro-units` | `coord_type`, `display_type`, `metric` | Local snapshot projection | Machine/Relative, Actual/Commanded and mm/inch display only |
| `override-jog-speed` | `update_jog_slider_vel` | `SET_JOG_SCALE`; source jog gate | Canonical linear jog scale |
| `override-feed` | `set_feedrate` | Debounced `SET_OVERRIDE`; ON | Canonical feed override, including while AUTO where task layer permits |
| `override-spindle` | `set_spindlerate` | `SET_SPINDLE_OVERRIDE`; ON | Canonical spindle override |
| `override-max-velocity` | `set_maxvel` | `SET_MAX_VELOCITY`; ON | Canonical TP velocity limit/scale |
| `override-rapid` | `set_rapidrate` | Permanently disabled for selected ABI | `blocked_by_abi_rapidrate`; never aliases Max Velocity |
| `preview-layer-path`, `preview-layer-live`, `preview-layer-limits`, `preview-layer-velocity`, `preview-layer-offsets`, `preview-layer-extents` | AXIS View visibility variables | Local visibility only | Shows/hides existing snapshot data without deleting or mutating it |
| `program-editor` | Browser replacement for AXIS external Edit boundary | Edits pending source text locally | Does not change loaded interpreter until `toolbar-reload` |
Tool/probe IO operations (`TOOL_PREPARE`, `TOOL_PREPARED`, `TOOL_CHANGE`,
`TOOL_CHANGED`, `PROBE_CONFIG`) remain Worker capabilities for interpreter,
MDI, HAL and focused IO tests. They are deliberately absent from the Web main
panel because no corresponding AXIS main-panel buttons exist.
## Button Dependency Matrix
@@ -188,7 +249,7 @@ React must derive its button gates from that state on the next snapshot.
| `TOUCH_OFF` | Machine on, homed, idle/manual gate and valid dialog value | MDI `G10 L20` updates the selected coordinate system, then the saved mode is restored | Position/DRO and offsets refresh; program run state is unchanged |
| `SET_MAX_VELOCITY` | Machine powered and the override gate permits the update | Source TP velocity limit is changed | Motion duration/velocity changes; jog and feed overrides remain independent |
| Rapid Override control | Not available in the selected WASM TP | No state change | Rapid Override remains disabled; Max Velocity must not be used as a substitute |
| Spindle/Coolant/Tool/Probe | Machine on, idle, source-specific manual gate | Canonical device IO changes only after Worker verification | Their pressed/checked states update from device IO; no React-only optimistic state is allowed |
| Spindle/Coolant | Visible manual controls require machine ON and interpreter IDLE; spindle also requires MANUAL mode | Canonical device IO changes only after Worker verification | Pressed/checked states update from device IO; spindle speed +/- additionally requires a running spindle, matching `axis.tcl update_state` |
### Dependency Flow
@@ -378,6 +439,10 @@ rerun contract is covered by `web/worker/test_xyzac_program_rerun.mjs` and the
published-site execution sequence is covered by
`scripts/test_xyzac_program_execution_browser_strict.mjs`.
The source-surface audit is enforced by `scripts/test_axis_control_contract.mjs`.
The exhaustive control-ID audit is enforced by
`scripts/test_axis_control_inventory.mjs` and
`scripts/test_axis_control_inventory_browser.mjs`; the latter rejects any
rendered actionable element without a documented ID or with a duplicate ID.
When LinuxCNC source behavior or the selected machine configuration changes: