接续上一轮,先做 L4-USER-M-PROCESS,完全接入仿真系统

结论:已将 L4-USER-M-PROCESS 的 millturn M128/M129 受控状态转换接入 virtual HAL、真实 browser simulation、OPFS 会话 payload、SDK API 和 release diagnostics validation;外部 user-M process execution 与 promotion 仍保持 locked,不伪装为 native process 解锁。
This commit is contained in:
2026-06-20 06:33:00 +08:00
parent 15b98c3ecf
commit d0e55ba11e
12 changed files with 676 additions and 7 deletions

View File

@@ -12,8 +12,10 @@ import {
VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES, VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES,
VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES, VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES,
VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS, VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS,
VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY,
cloneVirtualHalState, cloneVirtualHalState,
createVirtualHalCommandScriptFixtureReport, createVirtualHalCommandScriptFixtureReport,
createVirtualHalMillturnUserMProcessBoundaryReport,
createVirtualHalMotionControllerMatrixReport, createVirtualHalMotionControllerMatrixReport,
createVirtualHalSimConfigEvidenceExpansionReport, createVirtualHalSimConfigEvidenceExpansionReport,
createVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalSimConfigMacroLoadFixtureReport,
@@ -74,6 +76,7 @@ function validateVirtualHalSessionPayload(virtualHal) {
assertPlainObject(virtualHal.sourceCompliance, "virtual HAL session source compliance"); assertPlainObject(virtualHal.sourceCompliance, "virtual HAL session source compliance");
assertPlainObject(virtualHal.simConfigSourceCoverage, "virtual HAL session sim-config source coverage"); assertPlainObject(virtualHal.simConfigSourceCoverage, "virtual HAL session sim-config source coverage");
assertPlainObject(virtualHal.simConfigPromotionCandidates, "virtual HAL session sim-config promotion candidates"); assertPlainObject(virtualHal.simConfigPromotionCandidates, "virtual HAL session sim-config promotion candidates");
assertPlainObject(virtualHal.millturnUserMProcessBoundary, "virtual HAL session millturn user-M process boundary");
assertPlainObject(virtualHal.simConfigMacroLoadFixtures, "virtual HAL session sim-config macro/load fixtures"); assertPlainObject(virtualHal.simConfigMacroLoadFixtures, "virtual HAL session sim-config macro/load fixtures");
assertPlainObject(virtualHal.commandScriptFixtures, "virtual HAL session command script fixtures"); assertPlainObject(virtualHal.commandScriptFixtures, "virtual HAL session command script fixtures");
assertPlainObject(virtualHal.motionControllerMatrix, "virtual HAL session motion controller matrix"); assertPlainObject(virtualHal.motionControllerMatrix, "virtual HAL session motion controller matrix");
@@ -89,6 +92,9 @@ function validateVirtualHalSessionPayload(virtualHal) {
if (virtualHal.simConfigPromotionCandidates.complete !== true) { if (virtualHal.simConfigPromotionCandidates.complete !== true) {
throw new Error("virtual HAL sim-config promotion candidates are incomplete."); throw new Error("virtual HAL sim-config promotion candidates are incomplete.");
} }
if (virtualHal.millturnUserMProcessBoundary.complete !== true) {
throw new Error("virtual HAL millturn user-M process boundary is incomplete.");
}
if (virtualHal.simConfigEvidenceExpansion.complete !== true) { if (virtualHal.simConfigEvidenceExpansion.complete !== true) {
throw new Error("virtual HAL sim-config evidence expansion candidates are incomplete."); throw new Error("virtual HAL sim-config evidence expansion candidates are incomplete.");
} }
@@ -116,6 +122,7 @@ export function createVirtualHalSessionPayload(halState = createVirtualHalState(
...VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES.flatMap((candidate) => candidate.sourceFiles ?? []), ...VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES.flatMap((candidate) => candidate.sourceFiles ?? []),
...VIRTUAL_HAL_SIM_CONFIG_EVIDENCE_EXPANSION_CANDIDATES.flatMap((candidate) => candidate.sourceFiles ?? []), ...VIRTUAL_HAL_SIM_CONFIG_EVIDENCE_EXPANSION_CANDIDATES.flatMap((candidate) => candidate.sourceFiles ?? []),
...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES.flatMap((fixture) => fixture.sourceFiles ?? []), ...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES.flatMap((fixture) => fixture.sourceFiles ?? []),
...VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.sourceFiles,
], ],
} }
: {} : {}
@@ -137,6 +144,7 @@ export function createVirtualHalSessionPayload(halState = createVirtualHalState(
commandScriptFixtures, commandScriptFixtures,
motionControllerMatrix, motionControllerMatrix,
}); });
const millturnUserMProcessBoundary = options.millturnUserMProcessBoundary ?? createVirtualHalMillturnUserMProcessBoundaryReport(reportOptions);
const sourceCompliance = options.sourceCompliance ?? createVirtualHalSourceComplianceReport({ const sourceCompliance = options.sourceCompliance ?? createVirtualHalSourceComplianceReport({
...reportOptions, ...reportOptions,
halState: state, halState: state,
@@ -161,6 +169,7 @@ export function createVirtualHalSessionPayload(halState = createVirtualHalState(
simConfigSourceCoverage, simConfigSourceCoverage,
simConfigPromotionCandidates, simConfigPromotionCandidates,
simConfigEvidenceExpansion, simConfigEvidenceExpansion,
millturnUserMProcessBoundary,
simConfigMacroLoadFixtures, simConfigMacroLoadFixtures,
commandScriptFixtures, commandScriptFixtures,
motionControllerMatrix, motionControllerMatrix,

View File

@@ -318,7 +318,9 @@ private page state.
`executeHalcmd()`, `stepMotion()`, `stepMotionController()`, `executeHalcmd()`, `stepMotion()`, `stepMotionController()`,
`getSimulationRuntimeReport()`, `getSimulationReplacementReport()`, `getSimulationRuntimeReport()`, `getSimulationReplacementReport()`,
`getSourceComplianceReport()`, `getSimConfigPromotionCandidateReport()`, `getSourceComplianceReport()`, `getSimConfigPromotionCandidateReport()`,
`getSimConfigMacroLoadFixtureReport()`, `getIntegrityReport()`, `getSimConfigMacroLoadFixtureReport()`,
`getMillturnUserMProcessBoundaryReport()`,
`applyMillturnUserMProcessState()`, `getIntegrityReport()`,
`getPinInventory()`, `getProjectReport()`, and `applyToInterpSdk()`. `getPinInventory()`, `getProjectReport()`, and `applyToInterpSdk()`.
- `VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES`, - `VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES`,
`VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS`, `VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS`,
@@ -339,6 +341,18 @@ private page state.
`manifestEntries`, the matrix report checks those associated sim-config `manifestEntries`, the matrix report checks those associated sim-config
source files against the vendored LinuxCNC manifest and exposes source files against the vendored LinuxCNC manifest and exposes
`manifestChecked` plus `missingManifestFiles`. `manifestChecked` plus `missingManifestFiles`.
- `VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY`,
`createVirtualHalMillturnUserMProcessBoundaryReport()`, and
`applyVirtualHalMillturnUserMProcessState()` expose the controlled
millturn `M128`/`M129` user-M process boundary for browser/Node simulation.
The report names the LinuxCNC `millturn.ini`, `example.ngc`, Tcl M-code
scripts, and remap callers, then lists the source-derived
`motion.switchkins-type`, `kinstype.is-*`, and `ini.[xyz].*` HAL state
targets. `applyVirtualHalMillturnUserMProcessState()` can apply that
controlled state to the virtual HAL for simulation display. It keeps
`executionEnabled === false`, `promotionAllowed === false`, and
`processExecutionReady === false`; it does not execute arbitrary external
user-M processes or unlock `L4-USER-M-PROCESS`.
- `VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES` and - `VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES` and
`createVirtualHalSimConfigPromotionCandidateReport()` expose the current `createVirtualHalSimConfigPromotionCandidateReport()` expose the current
source-derived sim-config promotion candidate set. The first candidates keep source-derived sim-config promotion candidate set. The first candidates keep

View File

@@ -5,6 +5,7 @@ export {
VIRTUAL_HAL_AXISUI_PINS, VIRTUAL_HAL_AXISUI_PINS,
VIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES, VIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES,
VIRTUAL_HAL_COVERAGE_STATES, VIRTUAL_HAL_COVERAGE_STATES,
VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY,
VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES, VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES,
VIRTUAL_HAL_PROJECT_PIN_GROUPS, VIRTUAL_HAL_PROJECT_PIN_GROUPS,
VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_AUDIT_CANDIDATES, VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_AUDIT_CANDIDATES,
@@ -23,6 +24,7 @@ export {
VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS, VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS,
applyVirtualHalToInterpSdk, applyVirtualHalToInterpSdk,
applyVirtualHalAction, applyVirtualHalAction,
applyVirtualHalMillturnUserMProcessState,
applyVirtualHalPinUpdates, applyVirtualHalPinUpdates,
cloneVirtualHalState, cloneVirtualHalState,
createLinuxCncVirtualHalRuntime, createLinuxCncVirtualHalRuntime,
@@ -34,6 +36,7 @@ export {
createVirtualHalLimitsHomeState, createVirtualHalLimitsHomeState,
createVirtualHalMachineStatusState, createVirtualHalMachineStatusState,
createVirtualHalIntegrityReport, createVirtualHalIntegrityReport,
createVirtualHalMillturnUserMProcessBoundaryReport,
createVirtualHalPinInventory, createVirtualHalPinInventory,
createVirtualHalPinRegistry, createVirtualHalPinRegistry,
createVirtualHalProjectReport, createVirtualHalProjectReport,

View File

@@ -32,6 +32,84 @@ export const VIRTUAL_HAL_SOURCE_FILES = Object.freeze({
vendoredMotionHeader: "wasm-port/vendor/linuxcnc/src/emc/motion/motion.h", vendoredMotionHeader: "wasm-port/vendor/linuxcnc/src/emc/motion/motion.h",
}); });
export const VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY = Object.freeze({
id: "millturn-user-m-process",
label: "Millturn M128/M129 user-M process boundary",
boundaryClass: "L4-USER-M-PROCESS",
path: "axis/vismach/millturn/example.ngc",
ini: "axis/vismach/millturn/millturn.ini",
requiredRuntime: "linuxcnc_task_hal_tcl_user_m_process",
sourceFiles: Object.freeze([
"linuxcnc/configs/sim/axis/vismach/millturn/millturn.ini",
"linuxcnc/configs/sim/axis/vismach/millturn/example.ngc",
"linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M128",
"linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M129",
"linuxcnc/configs/sim/axis/vismach/millturn/remap_subs/428remap.ngc",
"linuxcnc/configs/sim/axis/vismach/millturn/remap_subs/429remap.ngc",
]),
manifestSourceFiles: Object.freeze([
"linuxcnc/configs/sim/axis/vismach/millturn/millturn.ini",
"linuxcnc/configs/sim/axis/vismach/millturn/example.ngc",
"linuxcnc/configs/sim/axis/vismach/millturn/remap_subs/428remap.ngc",
"linuxcnc/configs/sim/axis/vismach/millturn/remap_subs/429remap.ngc",
]),
nativeProbe: "ENABLE_MILLTURN_USER_M_RUNTIME_PROBE=1 bash wasm-port/tests/native/probe_millturn_user_m_runtime.sh",
cases: Object.freeze([
Object.freeze({
userMCode: "M128",
remapCode: "M428",
stateMode: "mill",
guardPin: "kinstype.is-0",
switchkinsOutputPin: "motion.analog-out-03",
switchkinsTarget: 0,
activeG5x: "G59.1",
workOffsetPocket: "P7",
workOffsetWords: "X-290 Y0 Z-160 A0",
sourceField: "MIN_LIMIT/MAX_LIMIT",
stateTargets: Object.freeze([
Object.freeze({ pin: "ini.x.min_limit", value: -300, sourceSection: "AXIS_X", sourceField: "MIN_LIMIT" }),
Object.freeze({ pin: "ini.x.max_limit", value: 300, sourceSection: "AXIS_X", sourceField: "MAX_LIMIT" }),
Object.freeze({ pin: "ini.x.min_velocity", value: 60.0, sourceSection: "AXIS_X", sourceField: "MAX_VELOCITY" }),
Object.freeze({ pin: "ini.x.max_acceleration", value: 400.0, sourceSection: "AXIS_X", sourceField: "MAX_ACCELERATION" }),
Object.freeze({ pin: "ini.y.min_limit", value: -100, sourceSection: "AXIS_Y", sourceField: "MIN_LIMIT" }),
Object.freeze({ pin: "ini.y.max_limit", value: 100, sourceSection: "AXIS_Y", sourceField: "MAX_LIMIT" }),
Object.freeze({ pin: "ini.y.min_velocity", value: 60.0, sourceSection: "AXIS_Y", sourceField: "MAX_VELOCITY" }),
Object.freeze({ pin: "ini.y.max_acceleration", value: 400.0, sourceSection: "AXIS_Y", sourceField: "MAX_ACCELERATION" }),
Object.freeze({ pin: "ini.z.min_limit", value: -240, sourceSection: "AXIS_Z", sourceField: "MIN_LIMIT" }),
Object.freeze({ pin: "ini.z.max_limit", value: 0, sourceSection: "AXIS_Z", sourceField: "MAX_LIMIT" }),
Object.freeze({ pin: "ini.z.min_velocity", value: 60.0, sourceSection: "AXIS_Z", sourceField: "MAX_VELOCITY" }),
Object.freeze({ pin: "ini.z.max_acceleration", value: 400.0, sourceSection: "AXIS_Z", sourceField: "MAX_ACCELERATION" }),
]),
}),
Object.freeze({
userMCode: "M129",
remapCode: "M429",
stateMode: "turn",
guardPin: "kinstype.is-1",
switchkinsOutputPin: "motion.analog-out-03",
switchkinsTarget: 1,
activeG5x: "G59.2",
workOffsetPocket: "P8",
workOffsetWords: "X-160 Y0 Z-290 A0",
sourceField: "MIN_LIMIT_TURN/MAX_LIMIT_TURN",
stateTargets: Object.freeze([
Object.freeze({ pin: "ini.x.min_limit", value: -240, sourceSection: "AXIS_X", sourceField: "MIN_LIMIT_TURN" }),
Object.freeze({ pin: "ini.x.max_limit", value: 0, sourceSection: "AXIS_X", sourceField: "MAX_LIMIT_TURN" }),
Object.freeze({ pin: "ini.x.min_velocity", value: 60.0, sourceSection: "AXIS_X", sourceField: "MAX_VELOCITY" }),
Object.freeze({ pin: "ini.x.max_acceleration", value: 400.0, sourceSection: "AXIS_X", sourceField: "MAX_ACCELERATION" }),
Object.freeze({ pin: "ini.y.min_limit", value: -100, sourceSection: "AXIS_Y", sourceField: "MIN_LIMIT_TURN" }),
Object.freeze({ pin: "ini.y.max_limit", value: 100, sourceSection: "AXIS_Y", sourceField: "MAX_LIMIT_TURN" }),
Object.freeze({ pin: "ini.y.min_velocity", value: 60.0, sourceSection: "AXIS_Y", sourceField: "MAX_VELOCITY" }),
Object.freeze({ pin: "ini.y.max_acceleration", value: 400.0, sourceSection: "AXIS_Y", sourceField: "MAX_ACCELERATION" }),
Object.freeze({ pin: "ini.z.min_limit", value: -300, sourceSection: "AXIS_Z", sourceField: "MIN_LIMIT_TURN" }),
Object.freeze({ pin: "ini.z.max_limit", value: 300, sourceSection: "AXIS_Z", sourceField: "MAX_LIMIT_TURN" }),
Object.freeze({ pin: "ini.z.min_velocity", value: 60.0, sourceSection: "AXIS_Z", sourceField: "MAX_VELOCITY" }),
Object.freeze({ pin: "ini.z.max_acceleration", value: 400.0, sourceSection: "AXIS_Z", sourceField: "MAX_ACCELERATION" }),
]),
}),
]),
});
export const VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS = Object.freeze([ export const VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS = Object.freeze([
Object.freeze({ Object.freeze({
id: "axis-foam", id: "axis-foam",
@@ -740,6 +818,31 @@ export const VIRTUAL_HAL_SYSTEM_PIN_FAMILIES = Object.freeze([
{ name: "motion.switchkins-type", type: "HAL_FLOAT", direction: "HAL_IN", conditional: "switchable kinematics" }, { name: "motion.switchkins-type", type: "HAL_FLOAT", direction: "HAL_IN", conditional: "switchable kinematics" },
]), ]),
}, },
{
id: "millturn-user-m-process",
component: "millturn",
label: "Millturn user-M process boundary pins",
sourceFiles: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.sourceFiles,
sourceEvidence: "LinuxCNC millturn M128/M129 Tcl scripts and remap callers set switchkins guard state and ini.[xyz] HAL pins.",
coverage: VIRTUAL_HAL_COVERAGE_STATES.runtimeBoundary,
pins: Object.freeze([
{ name: "motion.analog-out-03", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "kinstype.is-0", type: "HAL_BIT", direction: "HAL_OUT" },
{ name: "kinstype.is-1", type: "HAL_BIT", direction: "HAL_OUT" },
{ name: "ini.x.min_limit", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "ini.x.max_limit", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "ini.x.min_velocity", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "ini.x.max_acceleration", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "ini.y.min_limit", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "ini.y.max_limit", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "ini.y.min_velocity", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "ini.y.max_acceleration", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "ini.z.min_limit", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "ini.z.max_limit", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "ini.z.min_velocity", type: "HAL_FLOAT", direction: "HAL_OUT" },
{ name: "ini.z.max_acceleration", type: "HAL_FLOAT", direction: "HAL_OUT" },
]),
},
{ {
id: "axis-motion", id: "axis-motion",
component: "axis", component: "axis",
@@ -866,6 +969,11 @@ export const VIRTUAL_HAL_PROJECT_PIN_GROUPS = Object.freeze([
label: "Tool pins", label: "Tool pins",
description: "Tool status, tool change, and motion tool-offset pins from HALUI, iocontrol, and motion.", description: "Tool status, tool change, and motion tool-offset pins from HALUI, iocontrol, and motion.",
}, },
{
id: "user-m-process",
label: "User-M process boundary pins",
description: "Controlled millturn M128/M129 state pins sourced from LinuxCNC Tcl user-M scripts and remap callers.",
},
]); ]);
export const VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES = Object.freeze([ export const VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES = Object.freeze([
@@ -879,6 +987,7 @@ export const VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES = Object.freeze([
"axis-joint-position-feedback", "axis-joint-position-feedback",
"spindle-coolant-tool-status", "spindle-coolant-tool-status",
"interpreter-hal-bridge-snapshot", "interpreter-hal-bridge-snapshot",
"controlled-user-m-process-state-boundary",
]); ]);
export const VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS = Object.freeze([ export const VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS = Object.freeze([
@@ -887,6 +996,24 @@ export const VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS = Object.freeze([
"motion-controller", "motion-controller",
]); ]);
const VIRTUAL_HAL_DEFAULT_MILLTURN_USER_M_EXTERNAL_PINS = Object.freeze({
"motion.analog-out-03": Object.freeze({ kind: "pin", name: "motion.analog-out-03", type: "HAL_FLOAT", value: 0, connected: true }),
"kinstype.is-0": Object.freeze({ kind: "pin", name: "kinstype.is-0", type: "HAL_BIT", value: 0, connected: true }),
"kinstype.is-1": Object.freeze({ kind: "pin", name: "kinstype.is-1", type: "HAL_BIT", value: 0, connected: true }),
"ini.x.min_limit": Object.freeze({ kind: "pin", name: "ini.x.min_limit", type: "HAL_FLOAT", value: 0, connected: true }),
"ini.x.max_limit": Object.freeze({ kind: "pin", name: "ini.x.max_limit", type: "HAL_FLOAT", value: 0, connected: true }),
"ini.x.min_velocity": Object.freeze({ kind: "pin", name: "ini.x.min_velocity", type: "HAL_FLOAT", value: 0, connected: true }),
"ini.x.max_acceleration": Object.freeze({ kind: "pin", name: "ini.x.max_acceleration", type: "HAL_FLOAT", value: 0, connected: true }),
"ini.y.min_limit": Object.freeze({ kind: "pin", name: "ini.y.min_limit", type: "HAL_FLOAT", value: 0, connected: true }),
"ini.y.max_limit": Object.freeze({ kind: "pin", name: "ini.y.max_limit", type: "HAL_FLOAT", value: 0, connected: true }),
"ini.y.min_velocity": Object.freeze({ kind: "pin", name: "ini.y.min_velocity", type: "HAL_FLOAT", value: 0, connected: true }),
"ini.y.max_acceleration": Object.freeze({ kind: "pin", name: "ini.y.max_acceleration", type: "HAL_FLOAT", value: 0, connected: true }),
"ini.z.min_limit": Object.freeze({ kind: "pin", name: "ini.z.min_limit", type: "HAL_FLOAT", value: 0, connected: true }),
"ini.z.max_limit": Object.freeze({ kind: "pin", name: "ini.z.max_limit", type: "HAL_FLOAT", value: 0, connected: true }),
"ini.z.min_velocity": Object.freeze({ kind: "pin", name: "ini.z.min_velocity", type: "HAL_FLOAT", value: 0, connected: true }),
"ini.z.max_acceleration": Object.freeze({ kind: "pin", name: "ini.z.max_acceleration", type: "HAL_FLOAT", value: 0, connected: true }),
});
export const VIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES = Object.freeze([ export const VIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES = Object.freeze([
Object.freeze({ Object.freeze({
id: "pin-signal-net-show", id: "pin-signal-net-show",
@@ -1130,6 +1257,11 @@ export const VIRTUAL_HAL_SOURCE_DERIVED_CAPABILITIES = Object.freeze({
]), ]),
evidence: "Bridge snapshots only serialize source-derived virtual HAL pins and values into the LinuxCNC-backed interpreter HAL adapter.", evidence: "Bridge snapshots only serialize source-derived virtual HAL pins and values into the LinuxCNC-backed interpreter HAL adapter.",
}), }),
"controlled-user-m-process-state-boundary": Object.freeze({
label: "Controlled user-M process state boundary",
sourceFiles: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.sourceFiles,
evidence: "Millturn M128/M129 simulation exposes LinuxCNC source-derived Tcl/HAL state targets while keeping external process execution and promotion locked.",
}),
}); });
export function createVirtualHalState(overrides = {}) { export function createVirtualHalState(overrides = {}) {
@@ -1150,7 +1282,7 @@ export function createVirtualHalState(overrides = {}) {
mode: "manual", mode: "manual",
}, },
pins: Object.fromEntries(VIRTUAL_HAL_AXISUI_PINS.pins.map((pin) => [pin.name, pin.type === "HAL_FLOAT" ? 0 : false])), pins: Object.fromEntries(VIRTUAL_HAL_AXISUI_PINS.pins.map((pin) => [pin.name, pin.type === "HAL_FLOAT" ? 0 : false])),
externalPins: {}, externalPins: Object.fromEntries(Object.entries(VIRTUAL_HAL_DEFAULT_MILLTURN_USER_M_EXTERNAL_PINS).map(([name, entry]) => [name, { ...entry }])),
position: Object.fromEntries(VIRTUAL_HAL_AXES.map((axis) => [axis, 0])), position: Object.fromEntries(VIRTUAL_HAL_AXES.map((axis) => [axis, 0])),
homed: Object.fromEntries(VIRTUAL_HAL_AXES.map((axis) => [axis, false])), homed: Object.fromEntries(VIRTUAL_HAL_AXES.map((axis) => [axis, false])),
limits: Object.fromEntries(VIRTUAL_HAL_AXES.map((axis) => [ limits: Object.fromEntries(VIRTUAL_HAL_AXES.map((axis) => [
@@ -2210,6 +2342,12 @@ export function createVirtualHalBridgeReadiness(options = {}) {
"halui.estop.is-activated", "halui.estop.is-activated",
"spindle.0.speed-out", "spindle.0.speed-out",
"iocontrol.0.coolant-flood", "iocontrol.0.coolant-flood",
"motion.switchkins-type",
"motion.analog-out-03",
"kinstype.is-0",
"kinstype.is-1",
"ini.x.min_limit",
"ini.z.max_limit",
]; ];
const snapshotPins = new Set((snapshot.values ?? []).map(({ name }) => name)); const snapshotPins = new Set((snapshot.values ?? []).map(({ name }) => name));
const missingPins = requiredPins.filter((name) => !snapshotPins.has(name)); const missingPins = requiredPins.filter((name) => !snapshotPins.has(name));
@@ -2337,6 +2475,7 @@ export function createVirtualHalProjectReport(options = {}) {
registry: pinRegistry, registry: pinRegistry,
systemCoverage, systemCoverage,
}); });
const userMProcessBoundary = createVirtualHalMillturnUserMProcessBoundaryReport(options);
return { return {
apiName: "linuxcnc-wasm-virtual-hal-project-report", apiName: "linuxcnc-wasm-virtual-hal-project-report",
reportVersion: 1, reportVersion: 1,
@@ -2353,6 +2492,7 @@ export function createVirtualHalProjectReport(options = {}) {
integrity, integrity,
systemCoverage, systemCoverage,
simulationRuntime: createVirtualHalSimulationRuntimeReport(state), simulationRuntime: createVirtualHalSimulationRuntimeReport(state),
userMProcessBoundary,
wasmBridgeSnapshot: snapshot, wasmBridgeSnapshot: snapshot,
bridgeReadiness: readiness, bridgeReadiness: readiness,
bridgeActionPlan: actionPlan, bridgeActionPlan: actionPlan,
@@ -2387,6 +2527,11 @@ export function createVirtualHalProjectReport(options = {}) {
label: "Simulation HAL runtime", label: "Simulation HAL runtime",
value: "ready", value: "ready",
}, },
{
id: "user-m-process-boundary",
label: "User-M process boundary",
value: userMProcessBoundary.phase,
},
], ],
}; };
} }
@@ -3407,6 +3552,177 @@ export function createVirtualHalSimConfigMacroLoadFixtureReport(options = {}) {
}; };
} }
function virtualHalMillturnUserMCaseForCode(code) {
const normalized = String(code ?? "").trim().toUpperCase();
return VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.cases
.find((entry) => entry.userMCode === normalized || entry.remapCode === normalized) ?? null;
}
function createMillturnUserMStateTargetRows(boundaryCase) {
return boundaryCase.stateTargets.map((target) => ({
path: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.path,
ini: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.ini,
blocked: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.boundaryClass,
userMCode: boundaryCase.userMCode,
targetPin: target.pin,
sourceSection: target.sourceSection,
sourceField: target.sourceField,
expectedValue: target.value,
executionEnabled: false,
promotionAllowed: false,
proofStatus: "pending_native_runtime_probe",
notes: "source_derived_virtual_hal_state_target_no_external_process_execution",
}));
}
export function createVirtualHalMillturnUserMProcessBoundaryReport(options = {}) {
const boundary = VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY;
const manifestProvided = typeof options.manifestText === "string" || Array.isArray(options.manifestEntries);
const manifestSet = new Set([
...sourceManifestSetFromText(options.manifestText ?? ""),
...(options.manifestEntries ?? []).map(normalizeLinuxCncSourcePath),
]);
const sourceFiles = [...boundary.sourceFiles];
const manifestSourceFiles = [...boundary.manifestSourceFiles];
const missingManifestFiles = manifestProvided
? manifestSourceFiles.filter((file) => !manifestSet.has(normalizeLinuxCncSourcePath(file)))
: [];
const rows = boundary.cases.map((entry) => {
const stateTargetRows = createMillturnUserMStateTargetRows(entry);
return {
path: boundary.path,
ini: boundary.ini,
blocked: boundary.boundaryClass,
remapCode: entry.remapCode,
userMCode: entry.userMCode,
stateMode: entry.stateMode,
guardPin: entry.guardPin,
switchkinsOutputPin: entry.switchkinsOutputPin,
switchkinsTarget: entry.switchkinsTarget,
activeG5x: entry.activeG5x,
workOffsetPocket: entry.workOffsetPocket,
workOffsetWords: entry.workOffsetWords,
requiredRuntime: boundary.requiredRuntime,
expectedStatePins: stateTargetRows.map((row) => row.targetPin),
expectedStateValues: stateTargetRows.map((row) => `${row.targetPin}=${row.expectedValue}`),
stateTargetCount: stateTargetRows.length,
stateTargetRows,
sourceFiles,
manifestSourceFiles,
sourceDerived: sourceFiles.length > 0,
executionEnabled: false,
promotionAllowed: false,
proofStatus: "pending_native_runtime_probe",
nativeProbe: boundary.nativeProbe,
complete: sourceFiles.length > 0 && missingManifestFiles.length === 0,
notes: "controlled_virtual_hal_state_boundary_keep_user_m_process_blocked",
};
});
const complete = rows.length > 0 &&
rows.every((row) => row.complete) &&
missingManifestFiles.length === 0;
return {
apiName: "linuxcnc-wasm-virtual-hal-millturn-user-m-process-boundary-report",
reportVersion: 1,
source: "linuxcnc-configs-sim-source-derived-user-m-process-boundary",
phase: complete ? "simulation-boundary-ready" : "blocked",
complete,
webSimulationSatisfied: complete,
boundaryClass: boundary.boundaryClass,
path: boundary.path,
ini: boundary.ini,
requiredRuntime: boundary.requiredRuntime,
nativeProbe: boundary.nativeProbe,
nativeRuntimeRequired: true,
processExecutionReady: false,
executionEnabled: false,
promotionAllowed: false,
inventoryBaselineUnchanged: true,
jsCncSemantics: false,
manifestChecked: manifestProvided,
missingManifestFiles,
sourceFiles,
manifestSourceFiles,
caseCount: rows.length,
stateTargetCount: rows.reduce((sum, row) => sum + row.stateTargetCount, 0),
rows,
summaryRows: [
{ id: "boundary", label: "User-M boundary", value: boundary.boundaryClass },
{ id: "cases", label: "M-code cases", value: rows.map((row) => `${row.remapCode}->${row.userMCode}`).join(", ") },
{ id: "state-targets", label: "HAL state targets", value: `${rows.reduce((sum, row) => sum + row.stateTargetCount, 0)}` },
{ id: "execution", label: "External process execution", value: "locked" },
{ id: "promotion", label: "Promotion allowed", value: "0" },
],
};
}
export function applyVirtualHalMillturnUserMProcessState(halState = createVirtualHalState(), codeOrOptions = "M128", options = {}) {
const code = typeof codeOrOptions === "object" && codeOrOptions !== null
? codeOrOptions.code ?? codeOrOptions.userMCode ?? codeOrOptions.remapCode
: codeOrOptions;
const boundaryCase = virtualHalMillturnUserMCaseForCode(code);
if (!boundaryCase) {
throw new Error(`unknown millturn user-M process code: ${code}`);
}
const report = createVirtualHalMillturnUserMProcessBoundaryReport(options);
const row = report.rows.find((entry) => entry.userMCode === boundaryCase.userMCode);
if (!row?.complete) {
throw new Error(`millturn user-M process boundary is not source-complete for ${boundaryCase.userMCode}`);
}
const guardUpdates = VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.cases.map((entry) => ({
name: entry.guardPin,
type: "HAL_BIT",
value: entry.userMCode === boundaryCase.userMCode ? 1 : 0,
}));
const updates = [
{ name: "motion.switchkins-type", type: "HAL_FLOAT", value: boundaryCase.switchkinsTarget },
{ name: boundaryCase.switchkinsOutputPin, type: "HAL_FLOAT", value: boundaryCase.switchkinsTarget },
...guardUpdates,
...boundaryCase.stateTargets.map((target) => ({
name: target.pin,
type: "HAL_FLOAT",
value: target.value,
})),
];
const next = applyVirtualHalPinUpdates(halState, updates, { allowExternal: true });
next.hal.commandLog = [
...(next.hal.commandLog ?? []),
{
source: "virtual-user-m-process-boundary",
action: "millturn-user-m-state",
userMCode: boundaryCase.userMCode,
remapCode: boundaryCase.remapCode,
stateMode: boundaryCase.stateMode,
executionEnabled: false,
promotionAllowed: false,
ok: true,
},
].slice(-200);
next.revision += 1;
return {
apiName: "linuxcnc-wasm-virtual-hal-millturn-user-m-process-state-result",
resultVersion: 1,
source: "linuxcnc-configs-sim-source-derived-user-m-process-state",
ok: true,
boundaryClass: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.boundaryClass,
path: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.path,
ini: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.ini,
userMCode: boundaryCase.userMCode,
remapCode: boundaryCase.remapCode,
stateMode: boundaryCase.stateMode,
switchkinsTarget: boundaryCase.switchkinsTarget,
activeG5x: boundaryCase.activeG5x,
workOffsetPocket: boundaryCase.workOffsetPocket,
appliedPins: updates.map((update) => update.name),
executionEnabled: false,
promotionAllowed: false,
processExecutionReady: false,
state: normalizeVirtualHalState(next),
report,
};
}
export function createVirtualHalSourceComplianceReport(options = {}) { export function createVirtualHalSourceComplianceReport(options = {}) {
const halState = options.halState ?? createVirtualHalState(); const halState = options.halState ?? createVirtualHalState();
const snapshot = options.snapshot ?? createVirtualHalWasmBridgeSnapshot(halState); const snapshot = options.snapshot ?? createVirtualHalWasmBridgeSnapshot(halState);
@@ -3422,6 +3738,7 @@ export function createVirtualHalSourceComplianceReport(options = {}) {
...VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS.flatMap((target) => target.sourceFiles), ...VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS.flatMap((target) => target.sourceFiles),
...VIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES.flatMap((fixture) => fixture.sourceFiles), ...VIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES.flatMap((fixture) => fixture.sourceFiles),
...VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES.flatMap((fixture) => fixture.sourceFiles), ...VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES.flatMap((fixture) => fixture.sourceFiles),
...VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.sourceFiles,
...(options.allowedSourceFiles ?? []), ...(options.allowedSourceFiles ?? []),
]); ]);
const requiredCapabilities = options.requiredCapabilities ?? VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES; const requiredCapabilities = options.requiredCapabilities ?? VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES;
@@ -3629,6 +3946,14 @@ export function createLinuxCncVirtualHalRuntime(initialState = createVirtualHalS
getSimConfigMacroLoadFixtureReport(options = {}) { getSimConfigMacroLoadFixtureReport(options = {}) {
return createVirtualHalSimConfigMacroLoadFixtureReport(options); return createVirtualHalSimConfigMacroLoadFixtureReport(options);
}, },
getMillturnUserMProcessBoundaryReport(options = {}) {
return createVirtualHalMillturnUserMProcessBoundaryReport(options);
},
applyMillturnUserMProcessState(codeOrOptions = "M128", options = {}) {
const result = applyVirtualHalMillturnUserMProcessState(state, codeOrOptions, options);
state = result.state;
return result;
},
getCommandScriptFixtureReport(options = {}) { getCommandScriptFixtureReport(options = {}) {
return createVirtualHalCommandScriptFixtureReport({ ...options, halState: state }); return createVirtualHalCommandScriptFixtureReport({ ...options, halState: state });
}, },
@@ -3826,6 +4151,9 @@ function isVirtualHalPinWritable(name) {
if (/^(axis|joint)\./.test(name) || name.startsWith("spindle.")) { if (/^(axis|joint)\./.test(name) || name.startsWith("spindle.")) {
return true; return true;
} }
if (name.startsWith("ini.") || name.startsWith("kinstype.")) {
return true;
}
return false; return false;
} }
@@ -4014,6 +4342,9 @@ function applyAxisPinWrite(state, name, numeric, enabled) {
} }
function classifyVirtualHalPinGroup(name) { function classifyVirtualHalPinGroup(name) {
if (name.startsWith("ini.") || name.startsWith("kinstype.") || name === "motion.analog-out-03") {
return "user-m-process";
}
if (name.startsWith("axisui.") || name.startsWith("jog.") || name.startsWith("notifications-") || name === "error" || name === "abort") { if (name.startsWith("axisui.") || name.startsWith("jog.") || name.startsWith("notifications-") || name === "error" || name === "abort") {
return "axisui"; return "axisui";
} }

View File

@@ -702,6 +702,38 @@ function isVirtualHalPromotionCandidateSummaryReady(summary) {
arrayOrEmpty(summaryObject.blockedCandidateIds).length === 0; arrayOrEmpty(summaryObject.blockedCandidateIds).length === 0;
} }
function isVirtualHalMillturnUserMProcessBoundaryReady(report) {
const reportObject = objectOrEmpty(report);
const rows = arrayOrEmpty(reportObject.rows);
return reportObject.apiName === "linuxcnc-wasm-virtual-hal-millturn-user-m-process-boundary-report" &&
reportObject.complete === true &&
reportObject.webSimulationSatisfied === true &&
reportObject.boundaryClass === "L4-USER-M-PROCESS" &&
reportObject.path === "axis/vismach/millturn/example.ngc" &&
reportObject.executionEnabled === false &&
reportObject.promotionAllowed === false &&
reportObject.processExecutionReady === false &&
reportObject.stateTargetCount === 24 &&
arrayOrEmpty(reportObject.sourceFiles).includes("linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M128") &&
arrayOrEmpty(reportObject.sourceFiles).includes("linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M129") &&
rows.some((row) =>
row.userMCode === "M128" &&
row.remapCode === "M428" &&
row.stateMode === "mill" &&
row.stateTargetCount === 12 &&
row.executionEnabled === false &&
row.promotionAllowed === false
) &&
rows.some((row) =>
row.userMCode === "M129" &&
row.remapCode === "M429" &&
row.stateMode === "turn" &&
row.stateTargetCount === 12 &&
row.executionEnabled === false &&
row.promotionAllowed === false
);
}
export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifact = {}) { export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifact = {}) {
const artifactObject = objectOrEmpty(artifact); const artifactObject = objectOrEmpty(artifact);
const sourceCompliance = objectOrEmpty(artifactObject.virtualHalSourceCompliance); const sourceCompliance = objectOrEmpty(artifactObject.virtualHalSourceCompliance);
@@ -712,6 +744,7 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac
const evidenceExpansion = objectOrEmpty(artifactObject.virtualHalSimConfigEvidenceExpansion); const evidenceExpansion = objectOrEmpty(artifactObject.virtualHalSimConfigEvidenceExpansion);
const promotionCandidateSummary = objectOrEmpty(artifactObject.virtualHalPromotionCandidateSummary); const promotionCandidateSummary = objectOrEmpty(artifactObject.virtualHalPromotionCandidateSummary);
const macroLoadFixtures = objectOrEmpty(artifactObject.virtualHalSimConfigMacroLoadFixtures); const macroLoadFixtures = objectOrEmpty(artifactObject.virtualHalSimConfigMacroLoadFixtures);
const millturnUserMProcessBoundary = objectOrEmpty(artifactObject.virtualHalMillturnUserMProcessBoundary);
const sessionDiagnostics = objectOrEmpty(artifactObject.virtualHalSessionDiagnostics); const sessionDiagnostics = objectOrEmpty(artifactObject.virtualHalSessionDiagnostics);
const replacement = objectOrEmpty(artifactObject.virtualHalSimulationReplacement); const replacement = objectOrEmpty(artifactObject.virtualHalSimulationReplacement);
const virtualHal = objectOrEmpty(artifactObject.virtualHal); const virtualHal = objectOrEmpty(artifactObject.virtualHal);
@@ -737,6 +770,9 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac
const hasMacroLoadFixtures = artifactObject.virtualHalSimConfigMacroLoadFixtures !== undefined; const hasMacroLoadFixtures = artifactObject.virtualHalSimConfigMacroLoadFixtures !== undefined;
const macroLoadFixturesReady = hasMacroLoadFixtures && const macroLoadFixturesReady = hasMacroLoadFixtures &&
isVirtualHalSimConfigMacroLoadFixtureReportReady(macroLoadFixtures); isVirtualHalSimConfigMacroLoadFixtureReportReady(macroLoadFixtures);
const hasMillturnUserMProcessBoundary = artifactObject.virtualHalMillturnUserMProcessBoundary !== undefined;
const millturnUserMProcessBoundaryReady = hasMillturnUserMProcessBoundary &&
isVirtualHalMillturnUserMProcessBoundaryReady(millturnUserMProcessBoundary);
const replacementReady = replacement.ready === true && const replacementReady = replacement.ready === true &&
replacement.replacesHostRuntimeForSimulation === true && replacement.replacesHostRuntimeForSimulation === true &&
objectOrEmpty(replacement.sourceCompliance).webSimulationSatisfied === true && objectOrEmpty(replacement.sourceCompliance).webSimulationSatisfied === true &&
@@ -750,6 +786,9 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac
objectOrEmpty(sessionDiagnostics.validation).ready === true && objectOrEmpty(sessionDiagnostics.validation).ready === true &&
objectOrEmpty(sessionDiagnostics.diagnosticsArtifact).apiName === "real-browser-simulation-diagnostics-artifact" && objectOrEmpty(sessionDiagnostics.diagnosticsArtifact).apiName === "real-browser-simulation-diagnostics-artifact" &&
objectOrEmpty(sessionDiagnostics.diagnosticsArtifact?.virtualHalSourceCompliance).complete === true && objectOrEmpty(sessionDiagnostics.diagnosticsArtifact?.virtualHalSourceCompliance).complete === true &&
isVirtualHalMillturnUserMProcessBoundaryReady(
objectOrEmpty(sessionDiagnostics.diagnosticsArtifact?.virtualHalMillturnUserMProcessBoundary),
) &&
objectOrEmpty(sessionDiagnostics.diagnosticsArtifact?.virtualHalMotionControllerMatrix).manifestChecked === true objectOrEmpty(sessionDiagnostics.diagnosticsArtifact?.virtualHalMotionControllerMatrix).manifestChecked === true
); );
const missing = [ const missing = [
@@ -762,6 +801,7 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac
...(evidenceExpansionReady ? [] : ["virtualHalSimConfigEvidenceExpansion"]), ...(evidenceExpansionReady ? [] : ["virtualHalSimConfigEvidenceExpansion"]),
...(promotionCandidateSummaryReady ? [] : ["virtualHalPromotionCandidateSummary"]), ...(promotionCandidateSummaryReady ? [] : ["virtualHalPromotionCandidateSummary"]),
...(macroLoadFixturesReady ? [] : ["virtualHalSimConfigMacroLoadFixtures"]), ...(macroLoadFixturesReady ? [] : ["virtualHalSimConfigMacroLoadFixtures"]),
...(millturnUserMProcessBoundaryReady ? [] : ["virtualHalMillturnUserMProcessBoundary"]),
...(commandScriptFixturesReady ? [] : ["virtualHalCommandScriptFixtures"]), ...(commandScriptFixturesReady ? [] : ["virtualHalCommandScriptFixtures"]),
...(motionControllerMatrixReady ? [] : ["virtualHalMotionControllerMatrix"]), ...(motionControllerMatrixReady ? [] : ["virtualHalMotionControllerMatrix"]),
...(sessionDiagnosticsReady ? [] : ["virtualHalSessionDiagnostics"]), ...(sessionDiagnosticsReady ? [] : ["virtualHalSessionDiagnostics"]),
@@ -785,6 +825,8 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac
hasPromotionCandidateSummary, hasPromotionCandidateSummary,
macroLoadFixturesReady, macroLoadFixturesReady,
hasMacroLoadFixtures, hasMacroLoadFixtures,
millturnUserMProcessBoundaryReady,
hasMillturnUserMProcessBoundary,
commandScriptFixturesReady, commandScriptFixturesReady,
motionControllerMatrixReady, motionControllerMatrixReady,
sessionDiagnosticsReady, sessionDiagnosticsReady,
@@ -795,6 +837,7 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac
...arrayOrEmpty(promotionCandidates.sourceFiles), ...arrayOrEmpty(promotionCandidates.sourceFiles),
...arrayOrEmpty(evidenceExpansion.sourceFiles), ...arrayOrEmpty(evidenceExpansion.sourceFiles),
...arrayOrEmpty(macroLoadFixtures.sourceFiles), ...arrayOrEmpty(macroLoadFixtures.sourceFiles),
...arrayOrEmpty(millturnUserMProcessBoundary.sourceFiles),
...arrayOrEmpty(commandScriptFixtures.sourceFiles), ...arrayOrEmpty(commandScriptFixtures.sourceFiles),
...arrayOrEmpty(motionControllerMatrix.sourceFiles), ...arrayOrEmpty(motionControllerMatrix.sourceFiles),
...arrayOrEmpty(motionControllerMatrix.simConfigSourceFiles), ...arrayOrEmpty(motionControllerMatrix.simConfigSourceFiles),
@@ -840,6 +883,11 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac
label: "Virtual HAL sim-config macro/load fixtures", label: "Virtual HAL sim-config macro/load fixtures",
value: hasMacroLoadFixtures ? (macroLoadFixturesReady ? "ready" : "missing") : "not provided", value: hasMacroLoadFixtures ? (macroLoadFixturesReady ? "ready" : "missing") : "not provided",
}, },
{
id: "millturn-user-m-process-boundary",
label: "Millturn user-M process boundary",
value: hasMillturnUserMProcessBoundary ? (millturnUserMProcessBoundaryReady ? "ready" : "missing") : "not provided",
},
{ {
id: "command-script-fixtures", id: "command-script-fixtures",
label: "Virtual HAL command script fixtures", label: "Virtual HAL command script fixtures",

View File

@@ -1732,6 +1732,12 @@ M2
<dd><span data-python-remap-runtime="mode">contract-only</span> | callable <span data-python-remap-runtime="callable">locked</span> | generator <span data-python-remap-runtime="generator">locked</span> | state <span data-python-remap-runtime="interpreter">locked</span></dd> <dd><span data-python-remap-runtime="mode">contract-only</span> | callable <span data-python-remap-runtime="callable">locked</span> | generator <span data-python-remap-runtime="generator">locked</span> | state <span data-python-remap-runtime="interpreter">locked</span></dd>
<dt>Python Promotion</dt> <dt>Python Promotion</dt>
<dd>execution <span data-python-remap-runtime="execution">disabled</span> | promotion <span data-python-remap-runtime="promotion">locked</span></dd> <dd>execution <span data-python-remap-runtime="execution">disabled</span> | promotion <span data-python-remap-runtime="promotion">locked</span></dd>
<dt>User-M Process</dt>
<dd><span data-user-m-process="boundary">L4-USER-M-PROCESS</span> | <span data-user-m-process="path">axis/vismach/millturn/example.ngc</span> | <span data-user-m-process="phase">ready</span></dd>
<dt>Millturn Mode</dt>
<dd><span data-user-m-process="active-code">none</span> | remap <span data-user-m-process="active-remap">none</span> | mode <span data-user-m-process="active-mode">none</span> | switchkins <span data-user-m-process="switchkins">none</span></dd>
<dt>User-M Promotion</dt>
<dd>execution <span data-user-m-process="execution">disabled</span> | promotion <span data-user-m-process="promotion">locked</span></dd>
<dt>Limits/Home</dt> <dt>Limits/Home</dt>
<dd data-limits-home-summary>source unavailable | X home no limit off/off fault none</dd> <dd data-limits-home-summary>source unavailable | X home no limit off/off fault none</dd>
<dt>Overrides</dt> <dt>Overrides</dt>
@@ -1851,7 +1857,9 @@ M2
VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES as SHARED_VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES, VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES as SHARED_VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES,
VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES as SHARED_VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES, VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES as SHARED_VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES,
VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS as SHARED_VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS, VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS as SHARED_VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS,
VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY as SHARED_VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY,
applyVirtualHalAction as applySharedVirtualHalAction, applyVirtualHalAction as applySharedVirtualHalAction,
applyVirtualHalMillturnUserMProcessState as applySharedVirtualHalMillturnUserMProcessState,
applyVirtualHalPinUpdates as applySharedVirtualHalPinUpdates, applyVirtualHalPinUpdates as applySharedVirtualHalPinUpdates,
cloneVirtualHalState as cloneSharedVirtualHalState, cloneVirtualHalState as cloneSharedVirtualHalState,
createVirtualHalCommandScriptFixtureReport as createSharedVirtualHalCommandScriptFixtureReport, createVirtualHalCommandScriptFixtureReport as createSharedVirtualHalCommandScriptFixtureReport,
@@ -1859,6 +1867,7 @@ M2
createVirtualHalIntegrityReport as createSharedVirtualHalIntegrityReport, createVirtualHalIntegrityReport as createSharedVirtualHalIntegrityReport,
createVirtualHalLimitsHomeState as createSharedVirtualHalLimitsHomeState, createVirtualHalLimitsHomeState as createSharedVirtualHalLimitsHomeState,
createVirtualHalMachineStatusState as createSharedVirtualHalMachineStatusState, createVirtualHalMachineStatusState as createSharedVirtualHalMachineStatusState,
createVirtualHalMillturnUserMProcessBoundaryReport as createSharedVirtualHalMillturnUserMProcessBoundaryReport,
createVirtualHalMotionControllerMatrixReport as createSharedVirtualHalMotionControllerMatrixReport, createVirtualHalMotionControllerMatrixReport as createSharedVirtualHalMotionControllerMatrixReport,
createVirtualHalPinRegistry as createSharedVirtualHalPinRegistry, createVirtualHalPinRegistry as createSharedVirtualHalPinRegistry,
createVirtualHalSimConfigEvidenceExpansionReport as createSharedVirtualHalSimConfigEvidenceExpansionReport, createVirtualHalSimConfigEvidenceExpansionReport as createSharedVirtualHalSimConfigEvidenceExpansionReport,
@@ -2036,7 +2045,22 @@ M2
const VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES = SHARED_VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES; const VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES = SHARED_VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES;
const VIRTUAL_HAL_SIM_CONFIG_EVIDENCE_EXPANSION_CANDIDATES = SHARED_VIRTUAL_HAL_SIM_CONFIG_EVIDENCE_EXPANSION_CANDIDATES; const VIRTUAL_HAL_SIM_CONFIG_EVIDENCE_EXPANSION_CANDIDATES = SHARED_VIRTUAL_HAL_SIM_CONFIG_EVIDENCE_EXPANSION_CANDIDATES;
const VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES = SHARED_VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS.flatMap((target) => target.sourceFiles ?? []); const VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES = SHARED_VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS.flatMap((target) => target.sourceFiles ?? []);
const VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY = SHARED_VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY;
let virtualHalState = createVirtualHalState(); let virtualHalState = createVirtualHalState();
let millturnUserMProcessState = {
apiName: "real-browser-simulation-millturn-user-m-process-state",
stateVersion: 1,
phase: "ready",
boundaryClass: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.boundaryClass,
path: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.path,
activeUserMCode: "none",
activeRemapCode: "none",
activeMode: "none",
switchkinsTarget: "none",
executionEnabled: false,
promotionAllowed: false,
processExecutionReady: false,
};
function setAllText(selector, value) { function setAllText(selector, value) {
document.querySelectorAll(selector).forEach((node) => { document.querySelectorAll(selector).forEach((node) => {
@@ -2562,6 +2586,67 @@ M2
return createSharedVirtualHalSimulationReplacementReport(virtualHalState); return createSharedVirtualHalSimulationReplacementReport(virtualHalState);
} }
function createVirtualHalMillturnUserMProcessBoundaryReport() {
return createSharedVirtualHalMillturnUserMProcessBoundaryReport({
manifestEntries: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.sourceFiles,
});
}
function renderMillturnUserMProcessState(state = millturnUserMProcessState) {
const nextState = {
apiName: "real-browser-simulation-millturn-user-m-process-state",
stateVersion: 1,
phase: state.phase ?? "ready",
boundaryClass: state.boundaryClass ?? VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.boundaryClass,
path: state.path ?? VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.path,
activeUserMCode: state.activeUserMCode ?? "none",
activeRemapCode: state.activeRemapCode ?? "none",
activeMode: state.activeMode ?? "none",
switchkinsTarget: state.switchkinsTarget ?? "none",
executionEnabled: state.executionEnabled === true,
promotionAllowed: state.promotionAllowed === true,
processExecutionReady: state.processExecutionReady === true,
};
millturnUserMProcessState = nextState;
document.body.dataset.userMProcessPhase = nextState.phase;
document.body.dataset.userMProcessActiveCode = nextState.activeUserMCode;
document.body.dataset.userMProcessActiveMode = nextState.activeMode;
setAllText("[data-user-m-process=\"boundary\"]", nextState.boundaryClass);
setAllText("[data-user-m-process=\"path\"]", nextState.path);
setAllText("[data-user-m-process=\"phase\"]", nextState.phase);
setAllText("[data-user-m-process=\"active-code\"]", nextState.activeUserMCode);
setAllText("[data-user-m-process=\"active-remap\"]", nextState.activeRemapCode);
setAllText("[data-user-m-process=\"active-mode\"]", nextState.activeMode);
setAllText("[data-user-m-process=\"switchkins\"]", String(nextState.switchkinsTarget));
setAllText("[data-user-m-process=\"execution\"]", nextState.executionEnabled ? "enabled" : "disabled");
setAllText("[data-user-m-process=\"promotion\"]", nextState.promotionAllowed ? "allowed" : "locked");
return { ...nextState };
}
function applyMillturnUserMProcessState(codeOrOptions = "M128", options = {}) {
const result = applySharedVirtualHalMillturnUserMProcessState(virtualHalState, codeOrOptions, {
manifestEntries: VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.sourceFiles,
...options,
});
virtualHalState = result.state;
renderVirtualHalState();
renderMillturnUserMProcessState({
phase: "applied",
boundaryClass: result.boundaryClass,
path: result.path,
activeUserMCode: result.userMCode,
activeRemapCode: result.remapCode,
activeMode: result.stateMode,
switchkinsTarget: result.switchkinsTarget,
executionEnabled: result.executionEnabled,
promotionAllowed: result.promotionAllowed,
processExecutionReady: result.processExecutionReady,
});
pushStatusHistory("user-m-process", `${result.remapCode}->${result.userMCode} ${result.stateMode}`);
renderAxisStatusbar();
return result;
}
function createVirtualHalSourceComplianceReport() { function createVirtualHalSourceComplianceReport() {
return createSharedVirtualHalSourceComplianceReport({ halState: virtualHalState }); return createSharedVirtualHalSourceComplianceReport({ halState: virtualHalState });
} }
@@ -2741,6 +2826,7 @@ M2
renderVirtualHalDro(); renderVirtualHalDro();
} }
renderLimitsHomeState(createVirtualHalLimitsHomeState()); renderLimitsHomeState(createVirtualHalLimitsHomeState());
renderMillturnUserMProcessState();
const promotionCandidateReport = createVirtualHalSimConfigPromotionCandidateReport(); const promotionCandidateReport = createVirtualHalSimConfigPromotionCandidateReport();
renderPromotionFamilyRows(promotionCandidateReport); renderPromotionFamilyRows(promotionCandidateReport);
renderPromotionCandidateSummary(createVirtualHalPromotionCandidateSummary(promotionCandidateReport)); renderPromotionCandidateSummary(createVirtualHalPromotionCandidateSummary(promotionCandidateReport));
@@ -2793,6 +2879,8 @@ M2
virtualHal: cloneVirtualHalState(), virtualHal: cloneVirtualHalState(),
virtualHalSimulationReplacement: createVirtualHalSimulationReplacementReport(), virtualHalSimulationReplacement: createVirtualHalSimulationReplacementReport(),
virtualHalSourceCompliance: createVirtualHalSourceComplianceReport(), virtualHalSourceCompliance: createVirtualHalSourceComplianceReport(),
virtualHalMillturnUserMProcessBoundary: createVirtualHalMillturnUserMProcessBoundaryReport(),
virtualHalMillturnUserMProcessState: renderMillturnUserMProcessState(),
virtualHalSimConfigSourceCoverage: createVirtualHalSimConfigSourceCoverageReport(), virtualHalSimConfigSourceCoverage: createVirtualHalSimConfigSourceCoverageReport(),
virtualHalSimConfigPromotionCandidates: createVirtualHalSimConfigPromotionCandidateReport(), virtualHalSimConfigPromotionCandidates: createVirtualHalSimConfigPromotionCandidateReport(),
virtualHalSimConfigEvidenceExpansion: createVirtualHalSimConfigEvidenceExpansionReport(), virtualHalSimConfigEvidenceExpansion: createVirtualHalSimConfigEvidenceExpansionReport(),
@@ -2833,6 +2921,7 @@ M2
virtualHal: virtualHal.state, virtualHal: virtualHal.state,
virtualHalSimulationReplacement: virtualHal.diagnostics, virtualHalSimulationReplacement: virtualHal.diagnostics,
virtualHalSourceCompliance: virtualHal.sourceCompliance, virtualHalSourceCompliance: virtualHal.sourceCompliance,
virtualHalMillturnUserMProcessBoundary: virtualHal.millturnUserMProcessBoundary,
virtualHalSimConfigSourceCoverage: virtualHal.simConfigSourceCoverage, virtualHalSimConfigSourceCoverage: virtualHal.simConfigSourceCoverage,
virtualHalSimConfigPromotionCandidates: virtualHal.simConfigPromotionCandidates, virtualHalSimConfigPromotionCandidates: virtualHal.simConfigPromotionCandidates,
virtualHalSimConfigEvidenceExpansion: virtualHal.simConfigEvidenceExpansion, virtualHalSimConfigEvidenceExpansion: virtualHal.simConfigEvidenceExpansion,
@@ -3773,6 +3862,7 @@ M2
...VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES.flatMap((candidate) => candidate.sourceFiles ?? []), ...VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES.flatMap((candidate) => candidate.sourceFiles ?? []),
...VIRTUAL_HAL_SIM_CONFIG_EVIDENCE_EXPANSION_CANDIDATES.flatMap((candidate) => candidate.sourceFiles ?? []), ...VIRTUAL_HAL_SIM_CONFIG_EVIDENCE_EXPANSION_CANDIDATES.flatMap((candidate) => candidate.sourceFiles ?? []),
...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES.flatMap((fixture) => fixture.sourceFiles ?? []), ...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES.flatMap((fixture) => fixture.sourceFiles ?? []),
...VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.sourceFiles,
], ],
}); });
const payload = createMachineSessionSnapshotPayload(session.machineId, { const payload = createMachineSessionSnapshotPayload(session.machineId, {
@@ -4236,6 +4326,9 @@ M2
stepVirtualHalMotionController: (options = {}) => stepVirtualHalMotionController(options), stepVirtualHalMotionController: (options = {}) => stepVirtualHalMotionController(options),
getVirtualHalSimulationRuntimeReport: () => createVirtualHalSimulationRuntimeReport(), getVirtualHalSimulationRuntimeReport: () => createVirtualHalSimulationRuntimeReport(),
getVirtualHalSimulationReplacementReport: () => createVirtualHalSimulationReplacementReport(), getVirtualHalSimulationReplacementReport: () => createVirtualHalSimulationReplacementReport(),
getVirtualHalMillturnUserMProcessBoundaryReport: () => createVirtualHalMillturnUserMProcessBoundaryReport(),
getMillturnUserMProcessState: () => renderMillturnUserMProcessState(),
applyMillturnUserMProcessState: (codeOrOptions = "M128", options = {}) => applyMillturnUserMProcessState(codeOrOptions, options),
getVirtualHalSourceComplianceReport: () => createVirtualHalSourceComplianceReport(), getVirtualHalSourceComplianceReport: () => createVirtualHalSourceComplianceReport(),
getVirtualHalSimConfigSourceCoverageReport: () => createVirtualHalSimConfigSourceCoverageReport(), getVirtualHalSimConfigSourceCoverageReport: () => createVirtualHalSimConfigSourceCoverageReport(),
getVirtualHalSimConfigPromotionCandidateReport: () => createVirtualHalSimConfigPromotionCandidateReport(), getVirtualHalSimConfigPromotionCandidateReport: () => createVirtualHalSimConfigPromotionCandidateReport(),

View File

@@ -22,6 +22,7 @@ export {
export { export {
VIRTUAL_HAL_AXES, VIRTUAL_HAL_AXES,
VIRTUAL_HAL_AXISUI_PINS, VIRTUAL_HAL_AXISUI_PINS,
VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY,
VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES, VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES,
VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_AUDIT_CANDIDATES, VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_AUDIT_CANDIDATES,
VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_BLOCKED_FIXTURES, VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_BLOCKED_FIXTURES,
@@ -32,6 +33,7 @@ export {
VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS, VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS,
VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES, VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES,
applyVirtualHalAction, applyVirtualHalAction,
applyVirtualHalMillturnUserMProcessState,
applyVirtualHalPinUpdates, applyVirtualHalPinUpdates,
cloneVirtualHalState, cloneVirtualHalState,
createLinuxCncVirtualHalRuntime, createLinuxCncVirtualHalRuntime,
@@ -41,6 +43,7 @@ export {
createVirtualHalIntegrityReport, createVirtualHalIntegrityReport,
createVirtualHalLimitsHomeState, createVirtualHalLimitsHomeState,
createVirtualHalMachineStatusState, createVirtualHalMachineStatusState,
createVirtualHalMillturnUserMProcessBoundaryReport,
createVirtualHalPinRegistry, createVirtualHalPinRegistry,
createVirtualHalSimConfigEvidenceExpansionReport, createVirtualHalSimConfigEvidenceExpansionReport,
createVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalSimConfigMacroLoadFixtureReport,

View File

@@ -10,6 +10,7 @@
import { import {
VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS, VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS,
createVirtualHalCommandScriptFixtureReport, createVirtualHalCommandScriptFixtureReport,
createVirtualHalMillturnUserMProcessBoundaryReport,
createVirtualHalMotionControllerMatrixReport, createVirtualHalMotionControllerMatrixReport,
createVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalSimConfigMacroLoadFixtureReport,
createVirtualHalSimConfigEvidenceExpansionReport, createVirtualHalSimConfigEvidenceExpansionReport,
@@ -433,6 +434,16 @@
"linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc", "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc",
], ],
}), }),
virtualHalMillturnUserMProcessBoundary: createVirtualHalMillturnUserMProcessBoundaryReport({
manifestEntries: [
"linuxcnc/configs/sim/axis/vismach/millturn/millturn.ini",
"linuxcnc/configs/sim/axis/vismach/millturn/example.ngc",
"linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M128",
"linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M129",
"linuxcnc/configs/sim/axis/vismach/millturn/remap_subs/428remap.ngc",
"linuxcnc/configs/sim/axis/vismach/millturn/remap_subs/429remap.ngc",
],
}),
virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport({ halState: diagnosticsVirtualHalState }), virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport({ halState: diagnosticsVirtualHalState }),
virtualHalMotionControllerMatrix: diagnosticsMotionControllerMatrix, virtualHalMotionControllerMatrix: diagnosticsMotionControllerMatrix,
}; };

View File

@@ -241,6 +241,9 @@
!api?.stepVirtualHalMotionController || !api?.stepVirtualHalMotionController ||
!api?.getVirtualHalSimulationRuntimeReport || !api?.getVirtualHalSimulationRuntimeReport ||
!api?.getVirtualHalSimulationReplacementReport || !api?.getVirtualHalSimulationReplacementReport ||
!api?.getVirtualHalMillturnUserMProcessBoundaryReport ||
!api?.getMillturnUserMProcessState ||
!api?.applyMillturnUserMProcessState ||
!api?.getVirtualHalSourceComplianceReport || !api?.getVirtualHalSourceComplianceReport ||
!api?.getVirtualHalSimConfigSourceCoverageReport || !api?.getVirtualHalSimConfigSourceCoverageReport ||
!api?.getVirtualHalSimConfigPromotionCandidateReport || !api?.getVirtualHalSimConfigPromotionCandidateReport ||
@@ -442,7 +445,66 @@
) { ) {
throw new Error(`simulation virtual HAL registry/integrity drift: ${JSON.stringify(initialVirtualHalRegistry)}`); throw new Error(`simulation virtual HAL registry/integrity drift: ${JSON.stringify(initialVirtualHalRegistry)}`);
} }
const diagnosticsArtifact = api.exportDiagnosticsArtifact(); let diagnosticsArtifact = api.exportDiagnosticsArtifact();
const millturnUserMBoundary = api.getVirtualHalMillturnUserMProcessBoundaryReport();
if (
millturnUserMBoundary.apiName !== "linuxcnc-wasm-virtual-hal-millturn-user-m-process-boundary-report" ||
millturnUserMBoundary.boundaryClass !== "L4-USER-M-PROCESS" ||
millturnUserMBoundary.complete !== true ||
millturnUserMBoundary.webSimulationSatisfied !== true ||
millturnUserMBoundary.executionEnabled !== false ||
millturnUserMBoundary.promotionAllowed !== false ||
millturnUserMBoundary.processExecutionReady !== false ||
millturnUserMBoundary.rows.length !== 2 ||
!millturnUserMBoundary.rows.some(({ userMCode, remapCode, stateTargetCount }) => userMCode === "M128" && remapCode === "M428" && stateTargetCount === 12) ||
!millturnUserMBoundary.rows.some(({ userMCode, remapCode, stateTargetCount }) => userMCode === "M129" && remapCode === "M429" && stateTargetCount === 12) ||
doc.body.dataset.userMProcessPhase !== "ready" ||
doc.querySelector('[data-user-m-process="boundary"]')?.textContent !== "L4-USER-M-PROCESS" ||
doc.querySelector('[data-user-m-process="path"]')?.textContent !== "axis/vismach/millturn/example.ngc" ||
doc.querySelector('[data-user-m-process="execution"]')?.textContent !== "disabled" ||
doc.querySelector('[data-user-m-process="promotion"]')?.textContent !== "locked"
) {
throw new Error(`simulation millturn user-M boundary drift: ${JSON.stringify(millturnUserMBoundary)}`);
}
const millturnM128 = api.applyMillturnUserMProcessState("M128");
if (
millturnM128.apiName !== "linuxcnc-wasm-virtual-hal-millturn-user-m-process-state-result" ||
millturnM128.userMCode !== "M128" ||
millturnM128.remapCode !== "M428" ||
millturnM128.stateMode !== "mill" ||
api.readVirtualHalPin("motion.switchkins-type")?.value !== 0 ||
api.readVirtualHalPin("ini.x.min_limit")?.value !== -300 ||
api.readVirtualHalPin("ini.z.max_limit")?.value !== 0 ||
doc.body.dataset.userMProcessPhase !== "applied" ||
doc.body.dataset.userMProcessActiveCode !== "M128" ||
doc.body.dataset.userMProcessActiveMode !== "mill" ||
doc.querySelector('[data-user-m-process="active-code"]')?.textContent !== "M128" ||
doc.querySelector('[data-user-m-process="active-remap"]')?.textContent !== "M428" ||
doc.querySelector('[data-user-m-process="active-mode"]')?.textContent !== "mill" ||
doc.querySelector('[data-user-m-process="switchkins"]')?.textContent !== "0"
) {
throw new Error(`simulation M128 user-M state did not apply: ${JSON.stringify(millturnM128)}`);
}
const millturnM129 = api.applyMillturnUserMProcessState("M129");
if (
millturnM129.userMCode !== "M129" ||
millturnM129.remapCode !== "M429" ||
millturnM129.stateMode !== "turn" ||
api.readVirtualHalPin("motion.switchkins-type")?.value !== 1 ||
api.readVirtualHalPin("motion.analog-out-03")?.value !== 1 ||
api.readVirtualHalPin("kinstype.is-0")?.value !== 0 ||
api.readVirtualHalPin("kinstype.is-1")?.value !== 1 ||
api.readVirtualHalPin("ini.x.max_limit")?.value !== 0 ||
api.readVirtualHalPin("ini.z.max_limit")?.value !== 300 ||
api.getMillturnUserMProcessState().activeMode !== "turn" ||
doc.querySelector('[data-user-m-process="active-code"]')?.textContent !== "M129" ||
doc.querySelector('[data-user-m-process="active-remap"]')?.textContent !== "M429" ||
doc.querySelector('[data-user-m-process="active-mode"]')?.textContent !== "turn" ||
doc.querySelector('[data-user-m-process="switchkins"]')?.textContent !== "1"
) {
throw new Error(`simulation M129 user-M state did not apply: ${JSON.stringify(millturnM129)}`);
}
diagnosticsArtifact = api.exportDiagnosticsArtifact();
const promotionCandidateSummary = api.getVirtualHalPromotionCandidateSummary(); const promotionCandidateSummary = api.getVirtualHalPromotionCandidateSummary();
const expectedPromotionCandidates = [ const expectedPromotionCandidates = [
[ [
@@ -542,7 +604,14 @@
diagnosticsArtifact.virtualHalSimulationReplacement?.sourceCompliance?.webSimulationSatisfied !== true || diagnosticsArtifact.virtualHalSimulationReplacement?.sourceCompliance?.webSimulationSatisfied !== true ||
diagnosticsArtifact.virtualHalSourceCompliance?.complete !== true || diagnosticsArtifact.virtualHalSourceCompliance?.complete !== true ||
diagnosticsArtifact.virtualHalSourceCompliance?.webSimulationSatisfied !== true || diagnosticsArtifact.virtualHalSourceCompliance?.webSimulationSatisfied !== true ||
!diagnosticsArtifact.virtualHalSourceCompliance?.sourceFiles?.includes("linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M128") ||
!diagnosticsArtifact.virtualHalSourceCompliance?.sourceFiles?.includes("linuxcnc/src/hal/utils/halcmd_commands.cc") || !diagnosticsArtifact.virtualHalSourceCompliance?.sourceFiles?.includes("linuxcnc/src/hal/utils/halcmd_commands.cc") ||
diagnosticsArtifact.virtualHalMillturnUserMProcessBoundary?.complete !== true ||
diagnosticsArtifact.virtualHalMillturnUserMProcessBoundary?.boundaryClass !== "L4-USER-M-PROCESS" ||
diagnosticsArtifact.virtualHalMillturnUserMProcessState?.activeUserMCode !== "M129" ||
diagnosticsArtifact.virtualHalMillturnUserMProcessState?.activeMode !== "turn" ||
diagnosticsArtifact.virtualHalMillturnUserMProcessState?.executionEnabled !== false ||
diagnosticsArtifact.virtualHalMillturnUserMProcessState?.promotionAllowed !== false ||
diagnosticsArtifact.virtualHalSimConfigSourceCoverage?.complete !== true || diagnosticsArtifact.virtualHalSimConfigSourceCoverage?.complete !== true ||
!diagnosticsArtifact.virtualHalSimConfigSourceCoverage?.sourceFiles?.includes("linuxcnc/configs/sim/axis/foam/axis_foam.ini") || !diagnosticsArtifact.virtualHalSimConfigSourceCoverage?.sourceFiles?.includes("linuxcnc/configs/sim/axis/foam/axis_foam.ini") ||
!diagnosticsArtifact.virtualHalSimConfigSourceCoverage?.sourceFiles?.includes("linuxcnc/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini") || !diagnosticsArtifact.virtualHalSimConfigSourceCoverage?.sourceFiles?.includes("linuxcnc/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini") ||
@@ -976,6 +1045,8 @@
savedVirtualHalSession.sessionDiagnostics?.ready !== true || savedVirtualHalSession.sessionDiagnostics?.ready !== true ||
savedVirtualHalSession.sessionDiagnostics?.validation?.ready !== true || savedVirtualHalSession.sessionDiagnostics?.validation?.ready !== true ||
savedVirtualHalSession.sessionDiagnostics?.validation?.motionControllerMatrixReady !== true || savedVirtualHalSession.sessionDiagnostics?.validation?.motionControllerMatrixReady !== true ||
savedVirtualHalSession.snapshot?.payload?.virtualHal?.millturnUserMProcessBoundary?.complete !== true ||
savedVirtualHalSession.sessionDiagnostics?.diagnosticsArtifact?.virtualHalMillturnUserMProcessBoundary?.complete !== true ||
savedVirtualHalSession.sessionDiagnostics?.diagnosticsArtifact?.virtualHalMotionControllerMatrix?.complete !== true || savedVirtualHalSession.sessionDiagnostics?.diagnosticsArtifact?.virtualHalMotionControllerMatrix?.complete !== true ||
doc.body.dataset.virtualHalSessionPhase !== "saved" || doc.body.dataset.virtualHalSessionPhase !== "saved" ||
!doc.querySelector("[data-virtual-hal-session-status]")?.textContent.includes("Saved HAL session") !doc.querySelector("[data-virtual-hal-session-status]")?.textContent.includes("Saved HAL session")
@@ -991,7 +1062,8 @@
savedSessionDiagnosticsArtifact.validation?.ready !== true || savedSessionDiagnosticsArtifact.validation?.ready !== true ||
diagnosticsWithSavedSession.virtualHalSessionDiagnostics?.ready !== true || diagnosticsWithSavedSession.virtualHalSessionDiagnostics?.ready !== true ||
diagnosticsWithSavedSession.virtualHalSessionDiagnostics?.validation?.ready !== true || diagnosticsWithSavedSession.virtualHalSessionDiagnostics?.validation?.ready !== true ||
diagnosticsWithSavedSession.virtualHalSessionDiagnostics?.diagnosticsArtifact?.virtualHalSourceCompliance?.complete !== true diagnosticsWithSavedSession.virtualHalSessionDiagnostics?.diagnosticsArtifact?.virtualHalSourceCompliance?.complete !== true ||
diagnosticsWithSavedSession.virtualHalSessionDiagnostics?.diagnosticsArtifact?.virtualHalMillturnUserMProcessBoundary?.complete !== true
) { ) {
throw new Error(`AXIS-style virtual HAL session diagnostics did not become release-ready: ${JSON.stringify(diagnosticsWithSavedSession.virtualHalSessionDiagnostics)}`); throw new Error(`AXIS-style virtual HAL session diagnostics did not become release-ready: ${JSON.stringify(diagnosticsWithSavedSession.virtualHalSessionDiagnostics)}`);
} }

View File

@@ -13,6 +13,7 @@ import {
createVirtualHalSimConfigPromotionCandidateReport, createVirtualHalSimConfigPromotionCandidateReport,
createVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalSimConfigMacroLoadFixtureReport,
createVirtualHalCommandScriptFixtureReport, createVirtualHalCommandScriptFixtureReport,
createVirtualHalMillturnUserMProcessBoundaryReport,
createVirtualHalMotionControllerMatrixReport, createVirtualHalMotionControllerMatrixReport,
createVirtualHalSimConfigEvidenceExpansionReport, createVirtualHalSimConfigEvidenceExpansionReport,
createVirtualHalSimulationReplacementReport, createVirtualHalSimulationReplacementReport,
@@ -57,6 +58,9 @@ const virtualHalSimConfigEvidenceExpansion = createVirtualHalSimConfigEvidenceEx
const virtualHalSimConfigMacroLoadFixtures = createVirtualHalSimConfigMacroLoadFixtureReport({ const virtualHalSimConfigMacroLoadFixtures = createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText, manifestText: sourceManifestText,
}); });
const virtualHalMillturnUserMProcessBoundary = createVirtualHalMillturnUserMProcessBoundaryReport({
manifestText: sourceManifestText,
});
const virtualHalState = createVirtualHalState(); const virtualHalState = createVirtualHalState();
const pythonRemapRuntimeProof = { const pythonRemapRuntimeProof = {
nativeLifecycleReady: true, nativeLifecycleReady: true,
@@ -97,6 +101,7 @@ const browserDiagnosticsArtifact = {
inventoryBaseline: "executed=82 passed=82 skipped=77 unexpected_fail=0", inventoryBaseline: "executed=82 passed=82 skipped=77 unexpected_fail=0",
}, },
virtualHalSimConfigMacroLoadFixtures, virtualHalSimConfigMacroLoadFixtures,
virtualHalMillturnUserMProcessBoundary,
virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport({ halState: virtualHalState }), virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport({ halState: virtualHalState }),
virtualHalMotionControllerMatrix, virtualHalMotionControllerMatrix,
}; };

View File

@@ -34,6 +34,7 @@ import {
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel, createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel,
VIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES, VIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES,
VIRTUAL_HAL_COVERAGE_STATES, VIRTUAL_HAL_COVERAGE_STATES,
VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY,
VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES, VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES,
VIRTUAL_HAL_PROJECT_PIN_GROUPS, VIRTUAL_HAL_PROJECT_PIN_GROUPS,
VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_AUDIT_CANDIDATES, VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_AUDIT_CANDIDATES,
@@ -51,6 +52,7 @@ import {
VIRTUAL_HAL_SYSTEM_PIN_FAMILIES, VIRTUAL_HAL_SYSTEM_PIN_FAMILIES,
VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS, VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS,
applyVirtualHalAction, applyVirtualHalAction,
applyVirtualHalMillturnUserMProcessState,
applyVirtualHalPinUpdates, applyVirtualHalPinUpdates,
applyVirtualHalToInterpSdk, applyVirtualHalToInterpSdk,
createVirtualHalSimulationRuntimeReport, createVirtualHalSimulationRuntimeReport,
@@ -58,6 +60,7 @@ import {
createLinuxCncInterpSdk, createLinuxCncInterpSdk,
createLinuxCncVirtualHalRuntime, createLinuxCncVirtualHalRuntime,
createVirtualHalIntegrityReport, createVirtualHalIntegrityReport,
createVirtualHalMillturnUserMProcessBoundaryReport,
createVirtualHalMotionControllerMatrixReport, createVirtualHalMotionControllerMatrixReport,
createMachineSessionSnapshotPayload, createMachineSessionSnapshotPayload,
createVirtualHalSessionPayload, createVirtualHalSessionPayload,
@@ -356,6 +359,7 @@ const requiredExports = [
["createProjectReleaseReadinessReport", createProjectReleaseReadinessReport], ["createProjectReleaseReadinessReport", createProjectReleaseReadinessReport],
["createProjectReleaseReadinessSummaryViewModel", createProjectReleaseReadinessSummaryViewModel], ["createProjectReleaseReadinessSummaryViewModel", createProjectReleaseReadinessSummaryViewModel],
["applyVirtualHalAction", applyVirtualHalAction], ["applyVirtualHalAction", applyVirtualHalAction],
["applyVirtualHalMillturnUserMProcessState", applyVirtualHalMillturnUserMProcessState],
["applyVirtualHalPinUpdates", applyVirtualHalPinUpdates], ["applyVirtualHalPinUpdates", applyVirtualHalPinUpdates],
["applyVirtualHalToInterpSdk", applyVirtualHalToInterpSdk], ["applyVirtualHalToInterpSdk", applyVirtualHalToInterpSdk],
["createLinuxCncVirtualHalRuntime", createLinuxCncVirtualHalRuntime], ["createLinuxCncVirtualHalRuntime", createLinuxCncVirtualHalRuntime],
@@ -363,6 +367,7 @@ const requiredExports = [
["createVirtualHalBridgeReadiness", createVirtualHalBridgeReadiness], ["createVirtualHalBridgeReadiness", createVirtualHalBridgeReadiness],
["createVirtualHalCommandScriptFixtureReport", createVirtualHalCommandScriptFixtureReport], ["createVirtualHalCommandScriptFixtureReport", createVirtualHalCommandScriptFixtureReport],
["createVirtualHalIntegrityReport", createVirtualHalIntegrityReport], ["createVirtualHalIntegrityReport", createVirtualHalIntegrityReport],
["createVirtualHalMillturnUserMProcessBoundaryReport", createVirtualHalMillturnUserMProcessBoundaryReport],
["createVirtualHalMotionControllerMatrixReport", createVirtualHalMotionControllerMatrixReport], ["createVirtualHalMotionControllerMatrixReport", createVirtualHalMotionControllerMatrixReport],
["createVirtualHalPinInventory", createVirtualHalPinInventory], ["createVirtualHalPinInventory", createVirtualHalPinInventory],
["createVirtualHalPinRegistry", createVirtualHalPinRegistry], ["createVirtualHalPinRegistry", createVirtualHalPinRegistry],
@@ -648,6 +653,11 @@ assert.equal(VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS
.sourceFiles.includes("linuxcnc/configs/sim/axis/external_offsets/M111"), true); .sourceFiles.includes("linuxcnc/configs/sim/axis/external_offsets/M111"), true);
assert.equal(VIRTUAL_HAL_SOURCE_DERIVED_CAPABILITIES["halcmd-simulation-replacement"].sourceFiles.includes("linuxcnc/src/hal/utils/halcmd_commands.cc"), true); assert.equal(VIRTUAL_HAL_SOURCE_DERIVED_CAPABILITIES["halcmd-simulation-replacement"].sourceFiles.includes("linuxcnc/src/hal/utils/halcmd_commands.cc"), true);
assert.equal(VIRTUAL_HAL_SOURCE_DERIVED_CAPABILITIES["motion-controller-simulation-replacement"].sourceFiles.includes("linuxcnc/src/emc/motion/motion.c"), true); assert.equal(VIRTUAL_HAL_SOURCE_DERIVED_CAPABILITIES["motion-controller-simulation-replacement"].sourceFiles.includes("linuxcnc/src/emc/motion/motion.c"), true);
assert.equal(VIRTUAL_HAL_SOURCE_DERIVED_CAPABILITIES["controlled-user-m-process-state-boundary"].sourceFiles.includes("linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M128"), true);
assert.equal(VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.boundaryClass, "L4-USER-M-PROCESS");
assert.equal(VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.cases.length, 2);
assert.equal(VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.cases.some(({ userMCode }) => userMCode === "M128"), true);
assert.equal(VIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY.cases.some(({ userMCode }) => userMCode === "M129"), true);
assert.equal(VIRTUAL_HAL_COVERAGE_STATES.runtimeBoundary, "runtime-boundary"); assert.equal(VIRTUAL_HAL_COVERAGE_STATES.runtimeBoundary, "runtime-boundary");
assert.equal(VIRTUAL_HAL_SOURCE_FILES.halui, "linuxcnc/src/emc/usr_intf/halui.cc"); assert.equal(VIRTUAL_HAL_SOURCE_FILES.halui, "linuxcnc/src/emc/usr_intf/halui.cc");
assert.equal(VIRTUAL_HAL_SYSTEM_PIN_FAMILIES.some(({ id }) => id === "iocontrol"), true); assert.equal(VIRTUAL_HAL_SYSTEM_PIN_FAMILIES.some(({ id }) => id === "iocontrol"), true);
@@ -656,6 +666,8 @@ assert.match(sdkIndexText, /\bVIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS\b/);
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS\b/); assert.match(sdkReadmeText, /\bVIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS\b/);
assert.match(sdkIndexText, /\bVIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES\b/); assert.match(sdkIndexText, /\bVIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES\b/);
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES\b/); assert.match(sdkReadmeText, /\bVIRTUAL_HAL_COMMAND_SCRIPT_FIXTURES\b/);
assert.match(sdkIndexText, /\bVIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY\b/);
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_MILLTURN_USER_M_PROCESS_BOUNDARY\b/);
assert.match(sdkIndexText, /\bVIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES\b/); assert.match(sdkIndexText, /\bVIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES\b/);
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES\b/); assert.match(sdkReadmeText, /\bVIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES\b/);
assert.match(sdkIndexText, /\bVIRTUAL_HAL_PROJECT_PIN_GROUPS\b/); assert.match(sdkIndexText, /\bVIRTUAL_HAL_PROJECT_PIN_GROUPS\b/);
@@ -672,6 +684,10 @@ assert.match(sdkIndexText, /\bVIRTUAL_HAL_SYSTEM_PIN_FAMILIES\b/);
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_SYSTEM_PIN_FAMILIES\b/); assert.match(sdkReadmeText, /\bVIRTUAL_HAL_SYSTEM_PIN_FAMILIES\b/);
assert.match(sdkIndexText, /\bexecuteVirtualHalCommand\b/); assert.match(sdkIndexText, /\bexecuteVirtualHalCommand\b/);
assert.match(sdkReadmeText, /\bexecuteVirtualHalCommand\b/); assert.match(sdkReadmeText, /\bexecuteVirtualHalCommand\b/);
assert.match(sdkIndexText, /\bapplyVirtualHalMillturnUserMProcessState\b/);
assert.match(sdkReadmeText, /\bapplyVirtualHalMillturnUserMProcessState\b/);
assert.match(sdkIndexText, /\bcreateVirtualHalMillturnUserMProcessBoundaryReport\b/);
assert.match(sdkReadmeText, /\bcreateVirtualHalMillturnUserMProcessBoundaryReport\b/);
assert.match(sdkIndexText, /\bexecuteVirtualHalcmd\b/); assert.match(sdkIndexText, /\bexecuteVirtualHalcmd\b/);
assert.match(sdkReadmeText, /\bexecuteVirtualHalcmd\b/); assert.match(sdkReadmeText, /\bexecuteVirtualHalcmd\b/);
assert.match(sdkIndexText, /\bcreateVirtualHalCommandScriptFixtureReport\b/); assert.match(sdkIndexText, /\bcreateVirtualHalCommandScriptFixtureReport\b/);
@@ -781,6 +797,38 @@ assert.equal(virtualHalReport.pinRegistry.byName["spindle.0.speed-out"].value, 1
assert.equal(virtualHalReport.integrity.complete, true); assert.equal(virtualHalReport.integrity.complete, true);
const virtualHalRuntime = createLinuxCncVirtualHalRuntime(sdkVirtualHal); const virtualHalRuntime = createLinuxCncVirtualHalRuntime(sdkVirtualHal);
assert.equal(virtualHalRuntime.getProjectReport({ availableFunctions: VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS }).ready, true); assert.equal(virtualHalRuntime.getProjectReport({ availableFunctions: VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS }).ready, true);
const millturnUserMBoundaryReport = createVirtualHalMillturnUserMProcessBoundaryReport({ manifestText: sourceManifestText });
assert.equal(millturnUserMBoundaryReport.apiName, "linuxcnc-wasm-virtual-hal-millturn-user-m-process-boundary-report");
assert.equal(millturnUserMBoundaryReport.boundaryClass, "L4-USER-M-PROCESS");
assert.equal(millturnUserMBoundaryReport.complete, true);
assert.equal(millturnUserMBoundaryReport.webSimulationSatisfied, true);
assert.equal(millturnUserMBoundaryReport.executionEnabled, false);
assert.equal(millturnUserMBoundaryReport.promotionAllowed, false);
assert.equal(millturnUserMBoundaryReport.processExecutionReady, false);
assert.equal(millturnUserMBoundaryReport.inventoryBaselineUnchanged, true);
assert.equal(millturnUserMBoundaryReport.missingManifestFiles.length, 0);
assert.equal(millturnUserMBoundaryReport.rows.some(({ userMCode, remapCode }) => userMCode === "M128" && remapCode === "M428"), true);
assert.equal(millturnUserMBoundaryReport.rows.some(({ userMCode, remapCode }) => userMCode === "M129" && remapCode === "M429"), true);
assert.equal(millturnUserMBoundaryReport.rows.every(({ stateTargetCount }) => stateTargetCount === 12), true);
assert.equal(millturnUserMBoundaryReport.rows.every(({ executionEnabled, promotionAllowed }) => executionEnabled === false && promotionAllowed === false), true);
let millturnStateResult = applyVirtualHalMillturnUserMProcessState(virtualHalRuntime.getState(), "M128", { manifestText: sourceManifestText });
assert.equal(millturnStateResult.apiName, "linuxcnc-wasm-virtual-hal-millturn-user-m-process-state-result");
assert.equal(millturnStateResult.ok, true);
assert.equal(millturnStateResult.userMCode, "M128");
assert.equal(millturnStateResult.executionEnabled, false);
assert.equal(millturnStateResult.promotionAllowed, false);
assert.equal(readVirtualHalPin(millturnStateResult.state, "motion.switchkins-type").value, 0);
assert.equal(readVirtualHalPin(millturnStateResult.state, "ini.x.min_limit").value, -300);
assert.equal(readVirtualHalPin(millturnStateResult.state, "ini.z.max_limit").value, 0);
millturnStateResult = virtualHalRuntime.applyMillturnUserMProcessState("M129", { manifestText: sourceManifestText });
assert.equal(millturnStateResult.userMCode, "M129");
assert.equal(readVirtualHalPin(virtualHalRuntime.getState(), "motion.switchkins-type").value, 1);
assert.equal(readVirtualHalPin(virtualHalRuntime.getState(), "motion.analog-out-03").value, 1);
assert.equal(readVirtualHalPin(virtualHalRuntime.getState(), "kinstype.is-0").value, 0);
assert.equal(readVirtualHalPin(virtualHalRuntime.getState(), "kinstype.is-1").value, 1);
assert.equal(readVirtualHalPin(virtualHalRuntime.getState(), "ini.x.max_limit").value, 0);
assert.equal(readVirtualHalPin(virtualHalRuntime.getState(), "ini.z.max_limit").value, 300);
assert.equal(virtualHalRuntime.getMillturnUserMProcessBoundaryReport({ manifestText: sourceManifestText }).complete, true);
const virtualHalcmdResult = virtualHalRuntime.executeHalCommand(` const virtualHalcmdResult = virtualHalRuntime.executeHalCommand(`
loadrt trivkins loadrt trivkins
addf motion-controller servo-thread addf motion-controller servo-thread
@@ -1365,6 +1413,8 @@ assert.equal(virtualHalSessionPayload.simConfigSourceCoverage.complete, true);
assert.equal(virtualHalSessionPayload.simConfigPromotionCandidates.complete, true); assert.equal(virtualHalSessionPayload.simConfigPromotionCandidates.complete, true);
assert.equal(virtualHalSessionPayload.simConfigEvidenceExpansion.complete, true); assert.equal(virtualHalSessionPayload.simConfigEvidenceExpansion.complete, true);
assert.equal(virtualHalSessionPayload.simConfigMacroLoadFixtures.complete, true); assert.equal(virtualHalSessionPayload.simConfigMacroLoadFixtures.complete, true);
assert.equal(virtualHalSessionPayload.millturnUserMProcessBoundary.complete, true);
assert.equal(virtualHalSessionPayload.millturnUserMProcessBoundary.boundaryClass, "L4-USER-M-PROCESS");
assert.equal(virtualHalSessionPayload.commandScriptFixtures.complete, true); assert.equal(virtualHalSessionPayload.commandScriptFixtures.complete, true);
assert.equal(virtualHalSessionPayload.motionControllerMatrix.complete, true); assert.equal(virtualHalSessionPayload.motionControllerMatrix.complete, true);
const virtualHalSessionSnapshot = createSessionSnapshot( const virtualHalSessionSnapshot = createSessionSnapshot(
@@ -1404,6 +1454,7 @@ const browserDiagnosticsArtifact = {
inventoryBaseline: "executed=82 passed=82 skipped=77 unexpected_fail=0", inventoryBaseline: "executed=82 passed=82 skipped=77 unexpected_fail=0",
}, },
virtualHalSimConfigMacroLoadFixtures: simConfigMacroLoadFixtureReport, virtualHalSimConfigMacroLoadFixtures: simConfigMacroLoadFixtureReport,
virtualHalMillturnUserMProcessBoundary: millturnUserMBoundaryReport,
virtualHalCommandScriptFixtures: commandScriptFixtureReport, virtualHalCommandScriptFixtures: commandScriptFixtureReport,
virtualHalMotionControllerMatrix: manifestCheckedMotionControllerMatrixReport, virtualHalMotionControllerMatrix: manifestCheckedMotionControllerMatrixReport,
}; };
@@ -1435,6 +1486,8 @@ assert.equal(browserDiagnosticsArtifactValidation.promotionCandidateSummaryReady
assert.equal(browserDiagnosticsArtifactValidation.hasPromotionCandidateSummary, true); assert.equal(browserDiagnosticsArtifactValidation.hasPromotionCandidateSummary, true);
assert.equal(browserDiagnosticsArtifactValidation.macroLoadFixturesReady, true); assert.equal(browserDiagnosticsArtifactValidation.macroLoadFixturesReady, true);
assert.equal(browserDiagnosticsArtifactValidation.hasMacroLoadFixtures, true); assert.equal(browserDiagnosticsArtifactValidation.hasMacroLoadFixtures, true);
assert.equal(browserDiagnosticsArtifactValidation.millturnUserMProcessBoundaryReady, true);
assert.equal(browserDiagnosticsArtifactValidation.hasMillturnUserMProcessBoundary, true);
assert.equal(browserDiagnosticsArtifactValidation.commandScriptFixturesReady, true); assert.equal(browserDiagnosticsArtifactValidation.commandScriptFixturesReady, true);
assert.equal(browserDiagnosticsArtifactValidation.motionControllerMatrixReady, true); assert.equal(browserDiagnosticsArtifactValidation.motionControllerMatrixReady, true);
assert.equal(browserDiagnosticsArtifactValidation.hasSessionDiagnostics, true); assert.equal(browserDiagnosticsArtifactValidation.hasSessionDiagnostics, true);
@@ -1453,6 +1506,19 @@ assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc
assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/rose_engine/rcone.ngc"), true); assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/rose_engine/rcone.ngc"), true);
assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini"), true); assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini"), true);
assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc"), true); assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc"), true);
assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M128"), true);
assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M129"), true);
assert.equal(createProjectReleaseBrowserDiagnosticsArtifactValidation({
...browserDiagnosticsArtifact,
virtualHalMillturnUserMProcessBoundary: undefined,
}).missing.includes("virtualHalMillturnUserMProcessBoundary"), true);
assert.equal(createProjectReleaseBrowserDiagnosticsArtifactValidation({
...browserDiagnosticsArtifact,
virtualHalMillturnUserMProcessBoundary: {
...millturnUserMBoundaryReport,
promotionAllowed: true,
},
}).millturnUserMProcessBoundaryReady, false);
assert.equal(createProjectReleaseBrowserDiagnosticsArtifactValidation({ assert.equal(createProjectReleaseBrowserDiagnosticsArtifactValidation({
...browserDiagnosticsArtifact, ...browserDiagnosticsArtifact,
virtualHalPromotionCandidateSummary: undefined, virtualHalPromotionCandidateSummary: undefined,

View File

@@ -11,6 +11,7 @@ import {
import { import {
VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS, VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS,
createVirtualHalCommandScriptFixtureReport, createVirtualHalCommandScriptFixtureReport,
createVirtualHalMillturnUserMProcessBoundaryReport,
createVirtualHalMotionControllerMatrixReport, createVirtualHalMotionControllerMatrixReport,
createVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalSimConfigMacroLoadFixtureReport,
createVirtualHalSimConfigEvidenceExpansionReport, createVirtualHalSimConfigEvidenceExpansionReport,
@@ -1473,6 +1474,16 @@ const releaseReadinessMacroLoadFixtures = createVirtualHalSimConfigMacroLoadFixt
"linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc", "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc",
], ],
}); });
const releaseReadinessMillturnUserMProcessBoundary = createVirtualHalMillturnUserMProcessBoundaryReport({
manifestEntries: [
"linuxcnc/configs/sim/axis/vismach/millturn/millturn.ini",
"linuxcnc/configs/sim/axis/vismach/millturn/example.ngc",
"linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M128",
"linuxcnc/configs/sim/axis/vismach/millturn/mcodes/M129",
"linuxcnc/configs/sim/axis/vismach/millturn/remap_subs/428remap.ngc",
"linuxcnc/configs/sim/axis/vismach/millturn/remap_subs/429remap.ngc",
],
});
const pythonRemapRuntimeProof = { const pythonRemapRuntimeProof = {
nativeLifecycleReady: true, nativeLifecycleReady: true,
nativeProbeStatus: "runtime_lifecycle_probe_passed", nativeProbeStatus: "runtime_lifecycle_probe_passed",
@@ -1524,6 +1535,7 @@ const browserDiagnosticsArtifact = {
inventoryBaseline: "executed=82 passed=82 skipped=77 unexpected_fail=0", inventoryBaseline: "executed=82 passed=82 skipped=77 unexpected_fail=0",
}, },
virtualHalSimConfigMacroLoadFixtures: releaseReadinessMacroLoadFixtures, virtualHalSimConfigMacroLoadFixtures: releaseReadinessMacroLoadFixtures,
virtualHalMillturnUserMProcessBoundary: releaseReadinessMillturnUserMProcessBoundary,
virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport({ halState: browserDiagnosticsVirtualHalState }), virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport({ halState: browserDiagnosticsVirtualHalState }),
virtualHalMotionControllerMatrix: releaseReadinessMotionControllerMatrix, virtualHalMotionControllerMatrix: releaseReadinessMotionControllerMatrix,
}; };
@@ -1957,6 +1969,8 @@ assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.hasPromotionCandid
assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.promotionCandidatesReady, true); assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.promotionCandidatesReady, true);
assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.hasMacroLoadFixtures, true); assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.hasMacroLoadFixtures, true);
assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.macroLoadFixturesReady, true); assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.macroLoadFixturesReady, true);
assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.hasMillturnUserMProcessBoundary, true);
assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.millturnUserMProcessBoundaryReady, true);
assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.hasSessionDiagnostics, true); assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.hasSessionDiagnostics, true);
assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.sessionDiagnosticsReady, true); assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.sessionDiagnosticsReady, true);
assert.equal( assert.equal(
@@ -2111,7 +2125,7 @@ assert.equal(
); );
assert.equal( assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "hard-block-runtime-locked-preview")?.value, releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "hard-block-runtime-locked-preview")?.value,
"L4-PYTHON-REMAP:axis/laser/raster_test.ngc, L4-PYTHON-REMAP:axis/laser/vector_test.ngc, L4-PYTHON-REMAP:axis/laser/vector_test2.ngc", "L4-USER-M-PROCESS:axis/vismach/millturn/example.ngc",
); );
assert.equal( assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "hard-block-runtime-promotion-allowed")?.value, releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "hard-block-runtime-promotion-allowed")?.value,
@@ -2841,7 +2855,7 @@ const releaseArtifactUrlWorkflowMountResult =
rowsNode: releaseArtifactUrlWorkflowRowsNode, rowsNode: releaseArtifactUrlWorkflowRowsNode,
}); });
assert.equal(releaseArtifactUrlWorkflowRenderResult.rendered, true); assert.equal(releaseArtifactUrlWorkflowRenderResult.rendered, true);
assert.equal(releaseArtifactUrlWorkflowRenderResult.rowCount, 57); assert.equal(releaseArtifactUrlWorkflowRenderResult.rowCount, 53);
assert.equal( assert.equal(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("browser-diagnostics"), releaseArtifactUrlWorkflowRenderResult.rowIds.includes("browser-diagnostics"),
true, true,
@@ -2891,7 +2905,7 @@ assert.equal(
true, true,
); );
assert.equal(releaseArtifactUrlWorkflowMountResult.ready, true); assert.equal(releaseArtifactUrlWorkflowMountResult.ready, true);
assert.equal(releaseArtifactUrlWorkflowMountResult.renderResult.rowCount, 57); assert.equal(releaseArtifactUrlWorkflowMountResult.renderResult.rowCount, 53);
const releaseArtifactUrlWorkflowMissingDom = await loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl({ const releaseArtifactUrlWorkflowMissingDom = await loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl({
artifactUrl: "/project-release-readiness.json", artifactUrl: "/project-release-readiness.json",
fetchRef: async () => ({ fetchRef: async () => ({