Files
cnc_wams/wasm-port/docs/full-process-boundary-design.md

26 KiB

Full-Process Runtime Boundary Design

Generated: 2026-06-10 CST

This document records the first design pass for configs/sim rows that are already classified by the Node inventory, but must remain blocked until a LinuxCNC-owned runtime boundary exists. It is a design and accounting artifact, not an execution path.

Scope

  • axis/vismach/millturn/example.ngc, currently L4-USER-M-PROCESS.
  • axis/db_demo/base.ngc, currently L4-TOOL-DB.
  • Python-remap and broader full-process families remain inventoried in build/wasm/sim-configs-inventory/blocked-dependency-summary.tsv; they are not promoted here.

Non-Goals

  • Do not implement HAL, task, HALUI, Tcl, Python, tool-database, or external process semantics in JavaScript.
  • Do not make blocked rows pass by editing upstream G-code, Tcl, Python, INI, or tool-table files.
  • Do not treat native GUI code or config helper scripts as browser UI implementation code.
  • Do not mark a row unblocked until native, Node, and browser validation prove the boundary where that layer is applicable.

External User-M Process Boundary

Current Block

axis/vismach/millturn/example.ngc is blocked because millturn.ini declares:

  • [RS274NGC]USER_M_PATH = ./mcodes;
  • REMAP = M428 ... ngc=428remap;
  • REMAP = M429 ... ngc=429remap;
  • [HAL]HALUI = halui, HALFILE, HALCMD, and POSTGUI_HALFILE;
  • [HALUI]MDI_COMMAND = M128 and M129;
  • [DISPLAY]PYVCP = millturn.xml.

The promoted execution chain reaches remap_subs/428remap.ngc and remap_subs/429remap.ngc. Those LinuxCNC NGC remaps execute M68/M66 switchkins synchronization and then call external user-M process codes M128 or M129.

LinuxCNC Owner Set

  • configs/sim/axis/vismach/millturn/millturn.ini owns the machine declarations and search paths.
  • configs/sim/axis/vismach/millturn/remap_subs/428remap.ngc and 429remap.ngc own the NGC remap call sequence around M128 and M129.
  • configs/sim/axis/vismach/millturn/mcodes/M128 and configs/sim/axis/vismach/millturn/mcodes/M129 own the config side effects.
  • src/emc/task/emctask.cc owns USER_M_PATH search, executable detection, USER_DEFINED_FUNCTION_ADD(), and queuing EMC_SYSTEM_CMD.
  • src/emc/task/emctaskmain.cc owns emcSystemCmd() process spawning and completion tracking for queued system commands.
  • src/emc/usr_intf/halui.cc owns HALUI MDI command queue behavior.
  • The HAL runtime owns hal getp/hal setp state, including the ini.* soft-limit pins used by the scripts.

Native Behavior To Preserve

M128 is a Tcl process script that:

  • requires the LinuxCNC and HAL Tcl packages;
  • calls emc_init -quick;
  • calls parse_ini $::env(INI_FILE_NAME);
  • checks hal getp kinstype.is-0;
  • writes mill limits from [AXIS_X], [AXIS_Y], and [AXIS_Z] into ini.x.*, ini.y.*, and ini.z.* HAL pins.

M129 follows the same process path, but checks kinstype.is-1 and writes the MIN_LIMIT_TURN / MAX_LIMIT_TURN values for X, Y, and Z. Both scripts also restore MAX_VELOCITY and MAX_ACCELERATION.

The NGC remap files own the surrounding interpreter-visible work:

  • set motion.analog-out-03 through M68;
  • force synchronization with M66;
  • set G5x offsets with G10 L2 P7 or G10 L2 P8;
  • activate G59.1 or G59.2;
  • verify _hal[motion.switchkins-type] after the switch.

Boundary Decision

This is not the same boundary as the existing deterministic M110/M111 registration adapter. M110 and M111 can currently be represented as deterministic USER_M_COMMAND canonical events because the promoted tests only need the interpreter to accept and queue the user-M command. M128 and M129 must also prove HAL pin state updates that affect soft limits after a kinematics switch.

The row therefore remains L4-USER-M-PROCESS.

Current Machine-Readable Artifact

user-m-process-boundary-summary.tsv records the current designed-but-blocked state target set for this boundary. It maps M128 to remap_subs/428remap.ngc and M129 to remap_subs/429remap.ngc, records the kinstype.is-0 and kinstype.is-1 guards, and expands the source-traceable ini.[xyz].min_limit, ini.[xyz].max_limit, ini.[xyz].min_velocity, and ini.[xyz].max_acceleration target pins from millturn.ini. user-m-process-state-targets.tsv is the normalized companion table for that same evidence. It has one pending proof row per M128/M129 target pin, including the config script source file, remap caller, mill/turn state mode, guard pin, source INI section/field, and expected value. The current table has 24 target rows plus a header and keeps proof_status=pending, execution_enabled=0, and promotion_allowed=0. user-m-process-transition-plan.tsv records the next non-executing contract for this boundary. It binds M428 to M128 and M429 to M129, records the motion.analog-out-03 switchkins output, target kinstype values 0 and 1, the active G59.1/G59.2 work offsets, P7/P8 offset pockets, guard pins, and the 12 expected ini.[xyz].* state outputs for each user-M code. This is still a pending transition contract only; it does not execute Tcl, start HAL, or permit standalone/browser promotion. user-m-process-native-state-alignment.tsv aligns those 24 generated target rows with the native source probe stdout keys, such as M128_X_AXIS_X.MIN_LIMIT_ok and M129_Z_AXIS_Z.MAX_LIMIT_TURN_ok. This table proves the generated pin targets still match the native LinuxCNC source/state probe output, but it also remains proof_status=pending, execution_enabled=0, and promotion_allowed=0. user-m-process-native-transition-alignment.tsv aligns the two generated transition-plan rows with native source probe stdout for M428 and M429. It verifies the source-owned motion.analog-out-03 switchkins output, target kinstype values 0 and 1, active G59.1/G59.2 offsets, P7/P8 offset pockets, and M428 -> M128 / M429 -> M129 process calls. This is still source-transition alignment only; it does not execute the Tcl user-M processes, start HAL, or allow promotion. user-m-process-native-runtime-state-plan.tsv is the next native runnable probe contract. It records the required LinuxCNC task/HAL/Tcl user-M runtime, the required environment (INI_FILE_NAME, motion.switchkins-type, kinstype.is-0, kinstype.is-1, and ini.[xyz].* pins), the two transition steps, and the exact expected ini.[xyz].* values after each user-M process. It requires the source transition/state alignment artifacts to be complete, but keeps native_runtime_status=pending_native_hal_tcl_process_probe, proof_status=pending, execution_enabled=0, and promotion_allowed=0. user-m-process-native-runtime-readiness.tsv records whether the host has the runtime commands needed to attempt that native probe. It currently checks tclsh, halrun, halcmd, and linuxcnc, records PATH evidence where a command exists, and keeps the boundary blocked with proof_status=pending, execution_enabled=0, and promotion_allowed=0 even if the commands become available. user-m-process-native-runtime-probe-gate.tsv is the generated execution gate for the future runtime probe. It combines source proof readiness with host runtime readiness for M428/M128 and M429/M129, records missing runtime commands, and keeps proof_status=pending, execution_enabled=0, and promotion_allowed=0. tests/native/probe_millturn_user_m_runtime.sh is wired into build_native_probes.sh as linuxcnc_millturn_user_m_runtime_probe. On hosts without halrun, halcmd, or linuxcnc, it exits successfully but reports millturn_user_m_runtime_probe_status=skipped_missing_host_runtime; on a host with the full LinuxCNC runtime it remains disabled by default. If explicitly enabled with ENABLE_MILLTURN_USER_M_RUNTIME_PROBE=1, it starts the vendored millturn.ini, runs the LinuxCNC-owned Tcl M128/M129 scripts, and verifies the resulting ini.[xyz].* HAL state targets before reporting runtime_state_probe_passed.

The artifact keeps execution_enabled=0 and promotion_allowed=0. It is not a standalone Tcl/HAL executor and does not make millturn a Node/browser representative.

linuxcnc_millturn_user_m_boundary_probe is the current native guard for this evidence. It reads the LinuxCNC source millturn.ini, mcodes/M128, mcodes/M129, and the 428remap/429remap callers, then verifies the source-derived guard pins, M428/M429 switchkins transition fields, and ini.[xyz].* target values recorded in the machine-readable tables. This is a source/state-target and source-transition proof only: it does not execute Tcl, start HAL, spawn the external user-M process, or permit promotion.

Candidate Boundary

A valid future boundary would have to be LinuxCNC-owned and state based:

  1. Reuse LinuxCNC task user-M search and registration behavior for discovering M128 and M129.
  2. Reuse a LinuxCNC-owned HAL/INI state boundary for the ini.x.*, ini.y.*, ini.z.*, kinstype.is-*, and motion.switchkins-type pins.
  3. Execute or faithfully host the config-owned side-effect source without translating it into JavaScript CNC semantics. If the Tcl scripts cannot be executed in the target layer, the boundary must be narrowed to a documented LinuxCNC-owned state transition with source-traceable inputs and outputs.
  4. Keep browser execution blocked unless the same state transition can be proven without spawning arbitrary host processes.

Required Proof Before Promotion

Native proof:

  • The existing linuxcnc_millturn_user_m_boundary_probe source/state guard must continue to prove that the pending M128/M129 state targets come from LinuxCNC config files rather than project-owned behavior.
  • A LinuxCNC or standalone-native probe runs the M428 -> M129 -> M429 -> M128 relevant switch path and records the ini.[xyz].min_limit, ini.[xyz].max_limit, ini.[xyz].min_velocity, and ini.[xyz].max_acceleration pin values before and after each user-M call.
  • The same probe records the kinstype guard result and the active G5x offset.

Node WASM proof:

  • The SDK stages the same INI, remap, and script assets for dependency accounting.
  • The WASM runtime proves the same state output through a LinuxCNC-owned boundary. A USER_M_COMMAND event alone is not sufficient.

Browser proof:

  • The browser smoke calls the already validated SDK/WASM boundary.
  • The test labels the row as a millturn process-boundary representative only after the state proof exists. It must not claim full LinuxCNC HAL/task/UI process coverage.

Tool Database Boundary

Current Block

axis/db_demo/base.ngc is blocked because db_nonran.ini declares:

[EMCIO]
RANDOM_TOOLCHANGER = 0
DB_PROGRAM = ./db_nonran.py

The INI explicitly notes that TOOL_TABLE is not used with DB_PROGRAM. Standalone interpreter file execution would therefore bypass the tool database startup, command/reply protocol, and persistent database state.

LinuxCNC Owner Set

  • configs/sim/axis/db_demo/db_nonran.ini owns the DB program declaration.
  • configs/sim/axis/db_demo/db.py owns the demo database behavior.
  • src/emc/task/taskclass.cc owns reading [EMCIO]DB_PROGRAM, enabling DB mode, calling tooldata_db_init(), loading tooldata, and notifying DB state changes during tool load/unload paths.
  • src/emc/tooldata/tooldata_db.cc owns child process startup, pipe setup, version handshake, g get-all requests, and l/u/p notifications.
  • src/emc/tooldata/tooldata_common.cc owns common tooldata storage and DB refresh behavior.

Native Behavior To Preserve

tooldata_db_init() splits DB_PROGRAM into argv, verifies that the program is executable, forks it, connects stdin/stdout pipes, and waits for the version reply v2.1. tooldata_db_getall() sends g, resets local tooldata, reads tool lines until FINI, and calls tooldata_read_entry() for each line.

tooldata_db_notify() sends:

  • l ... for SPINDLE_LOAD;
  • u ... for SPINDLE_UNLOAD;
  • p ... for TOOL_OFFSET.

The demo db.py uses LinuxCNC's tooldb module with callbacks for:

  • user_get_tool;
  • user_put_tool;
  • user_load_spindle_nonran_tc or user_load_spindle_ran_tc;
  • user_unload_spindle_nonran_tc or user_unload_spindle_ran_tc.

It maintains a persistent flat-file database, updates tool usage minutes, and can call linuxcnc.command().load_tool_table to synchronize changes back to LinuxCNC. Those details are DB process behavior, not interpreter file execution behavior.

Boundary Decision

This row remains L4-TOOL-DB. A standalone adapter that merely loads a fallback .tbl file would be wrong for this config because DB mode explicitly replaces the tool table file path.

Current Machine-Readable Artifact

tool-db-process-boundary-summary.tsv records the current designed-but-blocked protocol and state target set for this boundary. It records DB_PROGRAM = ./db_nonran.py, the LinuxCNC tooldata protocol messages v2.1, g, l, u, and p, the demo DB callbacks user_get_tool, user_put_tool, user_load_spindle_nonran_tc, and user_unload_spindle_nonran_tc, and the nonrandom database state targets such as T10..T19, /tmp/db_nonran_file, tno+100 startup pockets, and pocket-0 spindle load/unload behavior. tool-db-process-protocol-gates.tsv is the normalized companion table for that evidence. It splits the blocked DB boundary into pending protocol-message, DB-program-callback, and state-target gates, including the v2.1 startup reply, g get-all through FINI, l/u/p notifications, demo callback registration, ignored TOOL_TABLE, startup tools, nonrandom pocket mapping, and persistence/sync targets. The current table keeps proof_status=pending, execution_enabled=0, and promotion_allowed=0. tool-db-process-transaction-plan.tsv records the next non-executing contract for this boundary. It orders the pending DB protocol into startup handshake, initial get-all, spindle load notify, tool offset notify, and spindle unload notify steps. Each step binds one LinuxCNC protocol message to the expected db.py callback, required native/Node/browser proof, and source-traceable state targets. This is still a transaction contract only; it does not start DB_PROGRAM, run Python, mutate /tmp/db_nonran_file, fall back to a tool table, or permit standalone/browser promotion. tool-db-process-native-protocol-alignment.tsv aligns those generated gates with the native source probe stdout keys, such as tool_db_v2_1_handshake, tool_db_getall_g_until_fini, tool_db_notify_l_u_p_protocol, and tool_db_program_nonran_state_targets. This table proves the generated gates still match LinuxCNC-owned task/tooldata/config evidence, but it also remains proof_status=pending, execution_enabled=0, and promotion_allowed=0. tool-db-process-native-runtime-readiness.tsv records whether the host has the runtime pieces needed to attempt a DB process protocol probe. It checks python3, linuxcnc, milltask, halcmd, the configured axis/db_demo/db_nonran.py program, and the LinuxCNC Python linuxcnc.so and tooldb.py modules. It records PATH/source evidence where available and keeps the DB boundary blocked with proof_status=pending, execution_enabled=0, and promotion_allowed=0. tests/native/probe_tool_db_runtime.sh is wired into build_native_probes.sh as linuxcnc_tool_db_runtime_probe. On hosts without the required DB runtime commands it exits successfully with tool_db_runtime_probe_status = skipped_missing_host_runtime; on a ready host it remains disabled by default. If explicitly enabled with ENABLE_TOOL_DB_RUNTIME_PROBE=1, it starts the vendored DB_PROGRAM, drives the LinuxCNC tooldb.py v2.1/g/p/l/u protocol over stdin/stdout, verifies nonrandom T10..T19 startup state, tool update, spindle load/unload, and flat-file persistence, then reports runtime_protocol_probe_passed.

The artifact keeps execution_enabled=0 and promotion_allowed=0. It is not a standalone tool database executor, does not replace DB_PROGRAM with a fallback .tbl, and does not make axis/db_demo/base.ngc a Node/browser representative.

linuxcnc_tool_db_boundary_probe is the current native guard for this evidence. It reads the LinuxCNC source db_nonran.ini, db.py, src/emc/task/taskclass.cc, and src/emc/tooldata/tooldata_db.cc, then verifies the DB mode owner path, child-process protocol, v2.1 startup handshake, g/FINI get-all path, l/u/p notifications, demo DB callbacks, and nonrandom state targets. This is a source/protocol-target proof only: it does not start DB_PROGRAM, run the Python tooldb loop, mutate the flat-file database, or permit promotion.

Candidate Boundary

A valid future boundary should be a narrow tool-database host adapter:

  1. Reuse tooldata_db.cc and tooldata_common.cc for DB mode behavior.
  2. Isolate the process-spawn edge behind a host abstraction so native can spawn the configured DB program, while WASM/browser use an explicitly designed equivalent only if it preserves the LinuxCNC protocol.
  3. Preserve the v2.1, g, l, u, and p command/reply protocol rather than parsing or inventing tool semantics in JavaScript.
  4. Treat db.py as a config-owned process dependency. If it is not executable in a target layer, that layer remains blocked.

Required Proof Before Promotion

Native proof:

  • The existing linuxcnc_tool_db_boundary_probe source/protocol guard must continue to prove that the pending DB gates come from LinuxCNC task/tooldata and demo DB sources rather than project-owned behavior.
  • A probe starts db_nonran.py through the LinuxCNC DB path and verifies the v2.1 handshake.
  • A get-all request returns the expected nonrandom startup tools.
  • A load/unload or update path changes DB state through l, u, or p and is reflected by a subsequent get-all.

Node WASM proof:

  • The same protocol is visible through the SDK boundary.
  • Tool lookup/update behavior matches the native proof without staging a fake .tbl replacement.

Browser proof:

  • Browser validation calls the Node-proven SDK/WASM boundary.
  • OPFS may store DB files only as host persistence. It must not implement DB command semantics.

Python-Remap Inventory Boundary

Python-remap rows remain inventory-only. The current blocked-dependency-summary.tsv records Python modules, remap/prolog/epilog functions, NGC-only subpaths, and HAL/UI/HALUI declarations. python-remap-boundary-summary.tsv preserves the same evidence per blocked path and records LinuxCNC Python runtime owner evidence from src/emc/rs274ngc/interp_python.cc and src/emc/pythonplugin/python_plugin.cc. python-remap-family-summary.tsv aggregates it by runtime family so mixed Python/NGC-only subpaths remain visible without promoting execution. No Python-remap row should be promoted until a separate LinuxCNC-owned Python runtime boundary exists and has native plus Node/browser proof appropriate to the target layer. python-remap-runtime-gates.tsv expands each blocked path into Python module, remap/prolog/epilog callable, NGC-only subpath, process-assumption, and runtime-owner gates. python-remap-native-runtime-alignment.tsv aligns those generated gates with the current native source probe stdout. Runtime owner gates map to exact LinuxCNC runtime proof keys such as python_runtime_pycall_dispatch and python_plugin_callable_invoke; dependency inventory gates map to representative family inventory proof or the aggregate python_remap_native_source_inventory_proof. Both tables remain proof_status=pending, execution_enabled=0, and promotion_allowed=0. python-remap-runtime-contract.tsv records the next non-executing family-level contract. It keeps one row per blocked Python-remap family, records the LinuxCNC-owned Python runtime phases (initialize_python, apply_ini_python_path, execute_toplevel, callable lookup/invoke, remap-phase dispatch, generator finish, execute-string/file, and reload), aggregates Python modules/callables/NGC-only subpaths, carries HAL/UI/HALUI process assumptions, and binds each family to native, Node, and browser proof requirements. It is a runtime contract only: it does not initialize Python, import modules, execute callbacks, or permit promotion. python-remap-native-runtime-readiness.tsv records the current host/source readiness for future native Python-remap runtime probes. It checks python3, linuxcnc, the LinuxCNC interpreter/plugin owner source files, and each configured Python module by blocked runtime family. The artifact remains a gate only: every row stays proof_status=pending, execution_enabled=0, and promotion_allowed=0. python-remap-native-runtime-state-plan.tsv records the non-executing runtime state plan for those future probes. It binds each blocked Python-remap family to the required LinuxCNC Python phases, configured modules, callables, NGC-only subpaths, process assumptions, readiness counts, source-alignment artifacts, and future native proof targets. It does not initialize Python, import modules, execute callbacks, or permit promotion. python-remap-native-runtime-fixture-plan.tsv selects the first native runtime fixture target, axis/remap/stop-lookahead/nc_files. That family is the smallest current Python runtime lifecycle candidate because it needs the LinuxCNC Python initialization/path/toplevel/runtime phases and configured modules but avoids Python callable and NGC-only subpath complexity. The fixture plan is still non-executing: it records the proof target only and keeps proof_status=pending, execution_enabled=0, and promotion_allowed=0. tests/native/probe_python_remap_runtime.sh is wired into build_native_probes.sh as linuxcnc_python_remap_runtime_probe. It records the stop-lookahead fixture identity, configured Python modules, required LinuxCNC Python runtime phases, host command readiness, and source/module availability. On hosts without linuxcnc, it exits successfully but reports python_remap_runtime_probe_status=skipped_missing_host_runtime; on hosts with the runtime available it remains disabled by default. If explicitly enabled with ENABLE_PYTHON_REMAP_RUNTIME_PROBE=1, it follows the demo.ini [PYTHON] path/toplevel declarations, imports the vendored stop-lookahead modules, verifies queuebuster callable lookup, confirms the callable returns a generator, and checks that the first yield is the LinuxCNC INTERP_EXECUTE_FINISH value from interp_return.hh before reporting runtime_lifecycle_probe_passed.

linuxcnc_python_remap_boundary_probe is the current native guard for this inventory. It reads the LinuxCNC Python runtime owners and representative config families (axis/laser, axis/remap/cycle, TWP nutating, and gmoccapy stdglue), then verifies the runtime dispatch/phase/callable owner evidence plus representative Python modules, remap callables, prolog/epilog callables, and Python path declarations. This is source inventory only: it does not initialize Python, import modules, execute remap callbacks, or permit promotion.

Next Boundary Worklist

next-boundary-worklist.tsv is the machine-readable handoff for the next runtime-boundary design phase. It is a planning artifact only: every row keeps execution_enabled=0 and promotion_allowed=0, records the LinuxCNC owner set, records runtime owner evidence, records required native, Node, and browser proof, and names the next boundary-design action before promotion.

boundary-proof-gates.tsv is the machine-readable proof checklist derived from that worklist. It expands every target into native, Node, and browser proof rows and keeps each row at proof_status=pending, execution_enabled=0, and promotion_allowed=0. It must fail validation if a future edit tries to promote a target without first replacing the pending gate with LinuxCNC-owned proof for that layer. For the current blockers, event-only USER_M_COMMAND coverage is insufficient for millturn, .tbl fallback coverage is insufficient for db_demo, and JavaScript-owned behavior is insufficient for Python runtime families.

native-proof-alignment-summary.tsv records whether the native source proof summary, when present, is consumed by generated worklist and native proof-gate rows. It currently aligns the millturn user-M source-state proof, db_demo tool database protocol source proof, and Python runtime source-inventory proof without enabling execution or promotion. runtime-boundary-native-alignment-summary.tsv is the aggregate guard for the detailed native alignment artifacts. It requires every user-M, tool DB, and Python alignment row to have native stdout evidence, alignment_ok=1, proof_status=pending, execution_enabled=0, and promotion_allowed=0. build/native/native-runtime-probe-summary.tsv is the native companion for the disabled runtime probe entry points. It summarizes the current runtime readiness for millturn user-M, db_demo tool DB, and the Python stop-lookahead fixture, records the missing host runtime requirements, points back to each probe stdout log, and keeps every row at execution_enabled=0 and promotion_allowed=0. runtime-boundary-contract-summary.tsv is the aggregate guard for the non-executing runtime contracts. It ties the millturn user-M transition contract, db_demo tool DB transaction contract, and Python-remap family runtime contract to their native-alignment artifacts, and requires every contract row to remain pending with execution and promotion disabled. blocked-runtime-promotion-lock.tsv is the final machine-readable lock for this phase. It combines the worklist, native/Node/browser proof gates, and runtime alignment summary so every blocked target has lock_active=1 until a LinuxCNC-owned runtime boundary replaces the pending gates.

The first two priorities are the current designed-but-disabled full-process blocks:

  1. external_user_m_process for axis/vismach/millturn/example.ngc;
  2. tool_database_process for axis/db_demo/base.ngc.

Python runtime family rows follow as inventory-only targets. They must remain behind a LinuxCNC-owned Python runtime boundary and must not be used to vendor or execute gmoccapy, axis/laser, TWP nutating, or other Python-remap families by path alone.

Current Validation

These commands must continue to pass after any change to this document or to the inventory code:

wasm-port/tests/wasm/node/verify_sim_configs_wasm.sh
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
wasm-port/tests/browser/verify_interp_browser.sh
wasm-port/tests/host/verify_host_smokes.sh
wasm-port/tools/verify_vendor_sync.sh
wasm-port/tools/verify_no_standalone_cnc_semantics.sh