diff --git a/text18.txt b/text18.txt index 10f1f33..8e61f5a 100644 --- a/text18.txt +++ b/text18.txt @@ -625,3 +625,78 @@ browser diagnostics proof。 main program 执行。 3. 将 macro/load fixture evidence 接入 release diagnostics validation,但不改变当前 inventory baseline。 + +### 四、2026-06-18 Macro Load Non-Main Fixture Evidence + +本批接续 Non-Qt promotion evidence,完成 macro/load non-main fixture report 首批闭环。 + +新增实质能力: + +- 新增 `VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES`; +- 新增 `createVirtualHalSimConfigMacroLoadFixtureReport()`: + - 输出 `linuxcnc-wasm-virtual-hal-sim-config-macro-load-fixture-report`; + - 显式输出 `inventoryBaselineUnchanged === true`; + - 每个 row 必须 `nonMainFixture === true`; + - 每个 row 的 `targetBrowserEvidence` 必须为 + `non-main-fixture-diagnostics`; + - `standaloneMainViolations` 必须为空; + - source manifest 只校验 LinuxCNC source evidence,不把 declared-only fixture path + 误当成 manifest 文件; +- 首批 fixture: + - `rose-engine-rcone-macro-load`: + - `fixturePath` 为 + `linuxcnc/configs/sim/axis/rose_engine/rcone.ngc`; + - source evidence 包含 `rose_engine.ini`、`rcone.ngc`、`rcone_demo.ngc`; + - 与 `rcone_demo.ngc` 配对作为 rose engine non-main macro/load evidence; + - `external-offsets-queuebuster-macro-load`: + - `fixturePath` 为 + `linuxcnc/configs/sim/axis/external_offsets/queuebuster.ngc`; + - source evidence 包含 `eoffsets.ini` 与 `eoffsets.ngc`; + - `declaredOnly === true`,通过 `eoffsets.ini` 的 `NGCGUI_SUBFILE` 声明保留 + fixture path,不声明它是 standalone browser main program; +- `createLinuxCncVirtualHalRuntime()` 新增: + - `getSimConfigMacroLoadFixtureReport()`; +- SDK index、SDK README、browser simulation re-export 同步导出新常量和新 report API; +- real simulation diagnostics artifact 新增: + - `virtualHalSimConfigMacroLoadFixtures`; + - browser API `getVirtualHalSimConfigMacroLoadFixtureReport()`; +- OPFS/session virtual HAL payload 新增: + - `simConfigPromotionCandidates`; + - `simConfigMacroLoadFixtures`; + - saved-session diagnostics nested artifact 同步携带两类 evidence; +- release diagnostics validation 新增 required evidence: + - `hasMacroLoadFixtures`; + - `macroLoadFixturesReady`; + - validation row:`sim-config-macro-load-fixtures`; + - 缺少 `virtualHalSimConfigMacroLoadFixtures` 时 release diagnostics validation 不再 ready; +- coverage matrix 对 `axis/rose_engine/rcone.ngc` 与 + `axis/external_offsets/queuebuster.ngc` 注释更新为 non-main fixture diagnostics evidence; +- promotion analysis 文档新增 Macro/Load Non-Main Fixture Evidence 小节。 + +语义边界: + +- 本批没有降低 inventory skip count; +- 当前 baseline 仍是 `executed=28`、`passed=28`、`skipped=131`、 + `unexpected_fail=0`; +- 本批没有新增 G-code/interpreter/planner/kinematics/remap 语义; +- macro/load fixture evidence 只证明 LinuxCNC-owned source/config declaration 与 + virtual HAL diagnostics readiness; +- `queuebuster.ngc` 只作为 `eoffsets.ini` 的 `NGCGUI_SUBFILE` declared-only fixture path + 记录,不作为 manifest-backed standalone file,也不作为 browser main program 执行; +- virtual HAL 已满足 Web 方式数控系统仿真系统,并在仿真范围内替代 LinuxCNC + realtime HAL、`halcmd`、motion controller; +- virtual HAL 仍不提供 Linux kernel hard-realtime ABI、外部硬件驱动 ABI 或 native + HAL module ABI; +- `L4-PYTHON-REMAP`、`L4-TOOL-DB`、`L4-USER-M-PROCESS`、`UPSTREAM-DEMO` 仍保持 + locked; +- G-code/interpreter/planner/canonical motion 语义仍来自 LinuxCNC-backed WASM。 + +下一步工作建议: + +1. 扩展 macro/load fixture report 到一个 UI-family non-main 案例,优先评估 + `gscreen/silverdragon/macros/tool_sensor.ngc`。 +2. 推进前必须确认 owning machine files、UI process declaration 和 source evidence, + 不能把 Python UI process emulation 纳入 virtual HAL 范围。 +3. 如 UI-family 边界不清晰,先增加 negative fixture gate:证明 + `L4-PYTHON-REMAP` / Python UI process 相关 macro/load 不会被 macro/load fixture + report 误解锁。 diff --git a/wasm-port/docs/sim-config-coverage-promotion-analysis.md b/wasm-port/docs/sim-config-coverage-promotion-analysis.md index eccac81..15678aa 100644 --- a/wasm-port/docs/sim-config-coverage-promotion-analysis.md +++ b/wasm-port/docs/sim-config-coverage-promotion-analysis.md @@ -229,10 +229,34 @@ inventory `PASS` with matrix `INV`; the added value is explicit browser diagnostics evidence and release-gate enforcement that the virtual HAL reports are complete for non-Qt sim-config families. -The next practical promotion slice is to design non-main macro/load fixture -evidence, starting with `axis/rose_engine/rcone.ngc` paired to -`rcone_demo.ngc`, without executing macro/load rows as standalone browser main -programs. +## 2026-06-18 Macro/Load Non-Main Fixture Evidence + +The virtual HAL diagnostics evidence now includes an explicit macro/load +fixture report: + +- `VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES` +- `createVirtualHalSimConfigMacroLoadFixtureReport()` + +The first required non-main fixtures are: + +- `axis/rose_engine/rcone.ngc` +- `axis/external_offsets/queuebuster.ngc` + +The rose-engine fixture is paired with `rcone_demo.ngc` and keeps `rcone.ngc` +as a non-main macro/load asset. The external-offsets fixture records +`queuebuster.ngc` as a declared `NGCGUI_SUBFILE` through `eoffsets.ini`; the +fixture path is preserved for diagnostics, while the manifest-backed source +evidence is the owning INI and paired LinuxCNC program source. This avoids +pretending that `queuebuster.ngc` is a standalone browser main program. + +Release diagnostics validation now requires +`virtualHalSimConfigMacroLoadFixtures` to be present and ready. The report must +keep `inventoryBaselineUnchanged === true`, every row must have +`nonMainFixture === true`, and `standaloneMainViolations` must stay empty. + +The next practical slice is to extend this report with one more non-main family +such as `gscreen/silverdragon/macros/tool_sensor.ngc`, after proving the owning +machine files and UI/process boundary do not cross into Python UI emulation. ## Boundary Statement diff --git a/wasm-port/docs/sim-configs-coverage-matrix.md b/wasm-port/docs/sim-configs-coverage-matrix.md index 15508e9..4fa76b3 100644 --- a/wasm-port/docs/sim-configs-coverage-matrix.md +++ b/wasm-port/docs/sim-configs-coverage-matrix.md @@ -475,7 +475,7 @@ Legend: | `axis/external_offsets/eoffsets.ngc` | `axis/external_offsets` | `main` | `FAIL` | `user-m-code-M111` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 2 expected-fail; M111 runtime edge covered | | `axis/external_offsets/jwp_z.ngc` | `axis/external_offsets` | `main` | `FAIL` | `user-m-code-M111` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 2 expected-fail; M111 runtime edge covered | | `axis/external_offsets/opa_demo.ngc` | `axis/external_offsets` | `main` | `FAIL` | `user-m-code-M111` | `SIM-EOFF` | `REP` | `REP` | `-` | Layer 2 expected-fail; M111 runtime edge covered | -| `axis/external_offsets/queuebuster.ngc` | `axis/external_offsets` | `macro_load` | `PASS` | `-` | `SIM-EOFF` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` | +| `axis/external_offsets/queuebuster.ngc` | `axis/external_offsets` | `macro_load` | `PASS` | `-` | `SIM-EOFF` | `-` | `-` | `-` | non-main macro/load fixture diagnostics evidence is now required by virtual HAL release validation through the owning `eoffsets.ini` NGCGUI declaration; not promoted as a standalone browser main program | | `axis/foam/foam.ngc` | `axis/foam` | `main` | `FAIL` | `ini-axis-mask-UV` | `SIM-FOAM` | `REP` | `REP` | `-` | Layer 2 expected-fail; Layer 3/4 runtime edge covered | | `axis/geometry/xyzc.ngc` | `axis/geometry` | `main` | `FAIL` | `user-m-code-M110` | `SIM-XYZC` | `REP` | `REP` | `-` | Layer 2 expected-fail; M110 runtime edge covered | | `axis/gladevcp/probe.ngc` | `axis/gladevcp` | `main` | `PASS` | `-` | `-` | `REP` | `REP` | `-` | plain INI/tool-table main-program class representative covered in Node and browser through vendored staging inputs | @@ -512,7 +512,7 @@ Legend: | `axis/remap/rack-toolchange/nc_subroutines/tool_getput_move.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | | `axis/remap/rack-toolchange/nc_subroutines/tool_holder_clear_move.ngc` | `axis/remap` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | | `axis/remap/stop-lookahead/nc_files/examples.ngc` | `axis/remap` | `main` | `PASS` | `-` | `-` | `-` | `-` | `L4-PYTHON-REMAP` | native baseline pass, but Layer 4 full inventory is blocked by Python `queuebuster` remap runtime boundaries; remap subroutine assets remain `ASSET-ONLY` | -| `axis/rose_engine/rcone.ngc` | `axis/rose_engine` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | inventory-only macro/load path; macro_load class coverage is represented by `axis/external_offsets/circles.ngc` unless this family is deliberately promoted later | +| `axis/rose_engine/rcone.ngc` | `axis/rose_engine` | `macro_load` | `PASS` | `-` | `-` | `-` | `-` | `-` | non-main macro/load fixture diagnostics evidence is now required by virtual HAL release validation and paired with `rcone_demo.ngc`; not promoted as a standalone browser main program | | `axis/rose_engine/rcone_demo.ngc` | `axis/rose_engine` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | Node inventory coverage uses the native harness-selected `axis/sim.tbl` fallback staged at the INI-declared tool-table path; virtual HAL promotion candidate gate now exports explicit browser diagnostics evidence while inventory baseline remains unchanged | | `axis/vismach/5axis/bridgemill/5axisgui.ngc` | `axis/vismach` | `main` | `FAIL` | `ini-axis-mask-W` | `SIM-BRIDGE,5AX-EXEC` | `REP` | `REP` | `-` | Layer 2 expected-fail; W-axis and remap runtime edge covered | | `axis/vismach/5axis/bridgemill/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `5AX-EXEC` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | diff --git a/wasm-port/runtime/opfs/snapshot-store.js b/wasm-port/runtime/opfs/snapshot-store.js index 4a3c88b..51ea754 100644 --- a/wasm-port/runtime/opfs/snapshot-store.js +++ b/wasm-port/runtime/opfs/snapshot-store.js @@ -8,9 +8,14 @@ import { toolTablePath, } from "./path-model.js"; import { + VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES, + VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES, + VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS, cloneVirtualHalState, createVirtualHalCommandScriptFixtureReport, createVirtualHalMotionControllerMatrixReport, + createVirtualHalSimConfigMacroLoadFixtureReport, + createVirtualHalSimConfigPromotionCandidateReport, createVirtualHalSimConfigSourceCoverageReport, createVirtualHalSimulationReplacementReport, createVirtualHalSourceComplianceReport, @@ -66,6 +71,8 @@ function validateVirtualHalSessionPayload(virtualHal) { assertPlainObject(virtualHal.diagnostics, "virtual HAL session diagnostics"); assertPlainObject(virtualHal.sourceCompliance, "virtual HAL session source compliance"); assertPlainObject(virtualHal.simConfigSourceCoverage, "virtual HAL session sim-config source coverage"); + assertPlainObject(virtualHal.simConfigPromotionCandidates, "virtual HAL session sim-config promotion candidates"); + assertPlainObject(virtualHal.simConfigMacroLoadFixtures, "virtual HAL session sim-config macro/load fixtures"); assertPlainObject(virtualHal.commandScriptFixtures, "virtual HAL session command script fixtures"); assertPlainObject(virtualHal.motionControllerMatrix, "virtual HAL session motion controller matrix"); if (virtualHal.state.source !== "browser-virtual-hal") { @@ -77,6 +84,12 @@ function validateVirtualHalSessionPayload(virtualHal) { if (virtualHal.simConfigSourceCoverage.complete !== true) { throw new Error("virtual HAL sim-config source coverage is incomplete."); } + if (virtualHal.simConfigPromotionCandidates.complete !== true) { + throw new Error("virtual HAL sim-config promotion candidates are incomplete."); + } + if (virtualHal.simConfigMacroLoadFixtures.complete !== true) { + throw new Error("virtual HAL sim-config macro/load fixtures are incomplete."); + } if (virtualHal.commandScriptFixtures.complete !== true) { throw new Error("virtual HAL command script fixtures are incomplete."); } @@ -88,11 +101,44 @@ function validateVirtualHalSessionPayload(virtualHal) { export function createVirtualHalSessionPayload(halState = createVirtualHalState(), options = {}) { const state = cloneVirtualHalState(halState); - const diagnostics = options.diagnostics ?? createVirtualHalSimulationReplacementReport(state); - const sourceCompliance = options.sourceCompliance ?? createVirtualHalSourceComplianceReport({ halState: state }); - const simConfigSourceCoverage = options.simConfigSourceCoverage ?? createVirtualHalSimConfigSourceCoverageReport(options); - const commandScriptFixtures = options.commandScriptFixtures ?? createVirtualHalCommandScriptFixtureReport({ ...options, halState: state }); - const motionControllerMatrix = options.motionControllerMatrix ?? createVirtualHalMotionControllerMatrixReport(options); + const reportOptions = { + ...options, + ...( + options.manifestText === undefined && options.manifestEntries === undefined + ? { + manifestEntries: [ + ...VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS.flatMap((target) => target.sourceFiles ?? []), + ...VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES.flatMap((candidate) => candidate.sourceFiles ?? []), + ...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES.flatMap((fixture) => fixture.sourceFiles ?? []), + ], + } + : {} + ), + }; + const simConfigSourceCoverage = options.simConfigSourceCoverage ?? createVirtualHalSimConfigSourceCoverageReport(reportOptions); + const simConfigMacroLoadFixtures = options.simConfigMacroLoadFixtures ?? createVirtualHalSimConfigMacroLoadFixtureReport(reportOptions); + const commandScriptFixtures = options.commandScriptFixtures ?? createVirtualHalCommandScriptFixtureReport({ ...reportOptions, halState: state }); + const motionControllerMatrix = options.motionControllerMatrix ?? createVirtualHalMotionControllerMatrixReport(reportOptions); + const simConfigPromotionCandidates = options.simConfigPromotionCandidates ?? createVirtualHalSimConfigPromotionCandidateReport({ + ...reportOptions, + simConfigSourceCoverage, + commandScriptFixtures, + motionControllerMatrix, + }); + const sourceCompliance = options.sourceCompliance ?? createVirtualHalSourceComplianceReport({ + ...reportOptions, + halState: state, + simConfigSourceCoverage, + commandScriptFixtures, + motionControllerMatrix, + }); + const diagnostics = options.diagnostics ?? createVirtualHalSimulationReplacementReport(state, { + ...reportOptions, + sourceCompliance, + simConfigSourceCoverage, + commandScriptFixtures, + motionControllerMatrix, + }); return validateVirtualHalSessionPayload({ apiName: "linuxcnc-wasm-virtual-hal-session-payload", payloadVersion: 1, @@ -101,6 +147,8 @@ export function createVirtualHalSessionPayload(halState = createVirtualHalState( diagnostics, sourceCompliance, simConfigSourceCoverage, + simConfigPromotionCandidates, + simConfigMacroLoadFixtures, commandScriptFixtures, motionControllerMatrix, }); diff --git a/wasm-port/runtime/sdk/README.md b/wasm-port/runtime/sdk/README.md index 6f74cd0..a94d89a 100644 --- a/wasm-port/runtime/sdk/README.md +++ b/wasm-port/runtime/sdk/README.md @@ -299,8 +299,8 @@ private page state. `executeHalcmd()`, `stepMotion()`, `stepMotionController()`, `getSimulationRuntimeReport()`, `getSimulationReplacementReport()`, `getSourceComplianceReport()`, `getSimConfigPromotionCandidateReport()`, - `getIntegrityReport()`, `getPinInventory()`, `getProjectReport()`, and - `applyToInterpSdk()`. + `getSimConfigMacroLoadFixtureReport()`, `getIntegrityReport()`, + `getPinInventory()`, `getProjectReport()`, and `applyToInterpSdk()`. - `VIRTUAL_HAL_SIMULATION_RUNTIME_CAPABILITIES`, `VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS`, `VIRTUAL_HAL_SOURCE_DERIVED_CAPABILITIES`, @@ -327,6 +327,13 @@ private page state. files, current Node `PASS` evidence, blocked-family exclusions, target browser diagnostics evidence, and the required virtual HAL reports for QtDragon on-abort, PUMA seam-weld, and rose-engine promotion planning. +- `VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES` and + `createVirtualHalSimConfigMacroLoadFixtureReport()` expose non-main + macro/load fixture evidence for virtual HAL diagnostics. The report keeps + `nonMainFixture === true`, separates fixture paths from manifest-backed + LinuxCNC source files, and prevents macro/load rows such as rose-engine + `rcone.ngc` or external-offsets `queuebuster.ngc` from being promoted as + standalone browser main programs. - `createVirtualHalSourceComplianceReport()` is the machine-readable gate for the virtual HAL source rule. It maps replacement targets, runtime capabilities, and HAL pin families back to LinuxCNC source files such as diff --git a/wasm-port/runtime/sdk/src/index.js b/wasm-port/runtime/sdk/src/index.js index 486056a..788c7bc 100644 --- a/wasm-port/runtime/sdk/src/index.js +++ b/wasm-port/runtime/sdk/src/index.js @@ -7,6 +7,7 @@ export { VIRTUAL_HAL_COVERAGE_STATES, VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES, VIRTUAL_HAL_PROJECT_PIN_GROUPS, + VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES, VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES, VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS, VIRTUAL_HAL_SOURCE_DERIVED_CAPABILITIES, @@ -31,6 +32,7 @@ export { createVirtualHalPinInventory, createVirtualHalPinRegistry, createVirtualHalProjectReport, + createVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalSimConfigPromotionCandidateReport, createVirtualHalSimConfigSourceCoverageReport, createVirtualHalSimulationReplacementReport, diff --git a/wasm-port/runtime/sdk/src/linuxcnc-hal.js b/wasm-port/runtime/sdk/src/linuxcnc-hal.js index 732efd3..d13c24e 100644 --- a/wasm-port/runtime/sdk/src/linuxcnc-hal.js +++ b/wasm-port/runtime/sdk/src/linuxcnc-hal.js @@ -321,6 +321,48 @@ export const VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES = Object.freeze([ }), ]); +export const VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES = Object.freeze([ + Object.freeze({ + id: "rose-engine-rcone-macro-load", + label: "Rose engine rcone macro/load", + fixturePath: "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc", + sourceFiles: Object.freeze([ + "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", + "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc", + "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", + ]), + owningIniPath: "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", + pairedMainProgram: "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", + declarationSource: "NGCGUI_SUBFILE", + currentNodeInventoryStatus: "PASS", + dependencyClass: "macro-load-non-main", + targetBrowserEvidence: "non-main-fixture-diagnostics", + blockedKind: "-", + nonMainFixture: true, + declaredOnly: false, + evidence: "LinuxCNC rose_engine.ini declares rcone.ngc through NGCGUI_SUBFILE; the fixture is validated as a non-main macro/load asset paired with rcone_demo.ngc.", + }), + Object.freeze({ + id: "external-offsets-queuebuster-macro-load", + label: "External offsets queuebuster macro/load declaration", + fixturePath: "linuxcnc/configs/sim/axis/external_offsets/queuebuster.ngc", + sourceFiles: Object.freeze([ + "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini", + "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc", + ]), + owningIniPath: "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini", + pairedMainProgram: "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc", + declarationSource: "NGCGUI_SUBFILE", + currentNodeInventoryStatus: "NON_MAIN_CLASS", + dependencyClass: "macro-load-non-main-declared-only", + targetBrowserEvidence: "non-main-fixture-diagnostics", + blockedKind: "-", + nonMainFixture: true, + declaredOnly: true, + evidence: "LinuxCNC eoffsets.ini declares queuebuster.ngc through NGCGUI_SUBFILE; the fixture records the owning INI declaration without executing it as a standalone browser main program.", + }), +]); + export const VIRTUAL_HAL_COVERAGE_STATES = Object.freeze({ simulated: "simulated", bridgeOnly: "bridge-only", @@ -2808,6 +2850,96 @@ export function createVirtualHalSimConfigPromotionCandidateReport(options = {}) }; } +export function createVirtualHalSimConfigMacroLoadFixtureReport(options = {}) { + const fixtures = options.fixtures ?? VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES; + const manifestProvided = typeof options.manifestText === "string" || Array.isArray(options.manifestEntries); + const manifestSet = new Set([ + ...sourceManifestSetFromText(options.manifestText ?? ""), + ...(options.manifestEntries ?? []).map(normalizeLinuxCncSourcePath), + ]); + const blockedKinds = new Set(options.blockedKinds ?? [ + "L4-PYTHON-REMAP", + "L4-TOOL-DB", + "L4-USER-M-PROCESS", + "UPSTREAM-DEMO", + ]); + const allowedStatuses = new Set(options.allowedStatuses ?? ["PASS", "NON_MAIN_CLASS"]); + const rows = fixtures.map((fixture) => { + const sourceFiles = [...(fixture.sourceFiles ?? [])]; + const normalizedSourceFiles = sourceFiles.map(normalizeLinuxCncSourcePath); + const missingManifestFiles = manifestProvided + ? sourceFiles.filter((file, index) => !manifestSet.has(normalizedSourceFiles[index])) + : []; + const blockedKindExcluded = !blockedKinds.has(fixture.blockedKind); + const statusReady = allowedStatuses.has(fixture.currentNodeInventoryStatus); + const nonMainFixtureReady = fixture.nonMainFixture === true && + fixture.targetBrowserEvidence === "non-main-fixture-diagnostics"; + const complete = sourceFiles.length > 0 && + missingManifestFiles.length === 0 && + blockedKindExcluded && + statusReady && + nonMainFixtureReady; + return { + id: fixture.id, + label: fixture.label, + source: "linuxcnc-configs-sim-source-derived-virtual-hal-macro-load-fixture", + fixturePath: fixture.fixturePath, + sourceFiles, + owningIniPath: fixture.owningIniPath, + pairedMainProgram: fixture.pairedMainProgram, + declarationSource: fixture.declarationSource, + currentNodeInventoryStatus: fixture.currentNodeInventoryStatus, + dependencyClass: fixture.dependencyClass, + targetBrowserEvidence: fixture.targetBrowserEvidence, + blockedKind: fixture.blockedKind, + blockedKindExcluded, + nonMainFixture: fixture.nonMainFixture === true, + declaredOnly: fixture.declaredOnly === true, + statusReady, + manifestChecked: manifestProvided, + missingManifestFiles, + evidence: fixture.evidence, + complete, + }; + }); + const missingFixtures = rows.filter((row) => !row.complete).map((row) => row.id); + const blockedFixtureIds = rows.filter((row) => !row.blockedKindExcluded).map((row) => row.id); + const standaloneMainViolations = rows + .filter((row) => row.nonMainFixture !== true || row.targetBrowserEvidence !== "non-main-fixture-diagnostics") + .map((row) => row.id); + const missingManifestFiles = [...new Set(rows.flatMap((row) => row.missingManifestFiles))]; + const complete = rows.length > 0 && + missingFixtures.length === 0 && + blockedFixtureIds.length === 0 && + standaloneMainViolations.length === 0 && + missingManifestFiles.length === 0; + return { + apiName: "linuxcnc-wasm-virtual-hal-sim-config-macro-load-fixture-report", + reportVersion: 1, + source: "linuxcnc-configs-sim-source-derived-virtual-hal", + phase: complete ? "ready" : "blocked", + complete, + webSimulationSatisfied: complete, + inventoryBaselineUnchanged: true, + manifestChecked: manifestProvided, + fixtureCount: rows.length, + sourceFiles: [...new Set(rows.flatMap((row) => row.sourceFiles))], + fixturePaths: rows.map((row) => row.fixturePath), + missingFixtures, + blockedFixtureIds, + standaloneMainViolations, + missingManifestFiles, + rows, + summaryRows: [ + { id: "fixtures", label: "Macro/load fixtures", value: `${rows.length}` }, + { id: "non-main", label: "Non-main fixture gate", value: standaloneMainViolations.length === 0 ? "passed" : `violations ${standaloneMainViolations.length}` }, + { id: "blocked-family", label: "Blocked-family exclusion", value: blockedFixtureIds.length === 0 ? "passed" : `blocked ${blockedFixtureIds.length}` }, + { id: "manifest", label: "Manifest check", value: manifestProvided ? (missingManifestFiles.length === 0 ? "passed" : "failed") : "not provided" }, + { id: "inventory-baseline", label: "Inventory baseline", value: "unchanged" }, + ], + }; +} + export function createVirtualHalSourceComplianceReport(options = {}) { const halState = options.halState ?? createVirtualHalState(); const snapshot = options.snapshot ?? createVirtualHalWasmBridgeSnapshot(halState); @@ -3024,6 +3156,9 @@ export function createLinuxCncVirtualHalRuntime(initialState = createVirtualHalS getSimConfigPromotionCandidateReport(options = {}) { return createVirtualHalSimConfigPromotionCandidateReport(options); }, + getSimConfigMacroLoadFixtureReport(options = {}) { + return createVirtualHalSimConfigMacroLoadFixtureReport(options); + }, getCommandScriptFixtureReport(options = {}) { return createVirtualHalCommandScriptFixtureReport({ ...options, halState: state }); }, diff --git a/wasm-port/runtime/sdk/src/project-release-readiness.js b/wasm-port/runtime/sdk/src/project-release-readiness.js index e17e2ce..501945f 100644 --- a/wasm-port/runtime/sdk/src/project-release-readiness.js +++ b/wasm-port/runtime/sdk/src/project-release-readiness.js @@ -148,6 +148,26 @@ const REQUIRED_PROMOTION_CANDIDATES = [ }, ]; +const REQUIRED_MACRO_LOAD_FIXTURES = [ + { + id: "rose-engine-rcone-macro-load", + fixturePath: "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc", + sourceFiles: [ + "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", + "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc", + "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", + ], + }, + { + id: "external-offsets-queuebuster-macro-load", + fixturePath: "linuxcnc/configs/sim/axis/external_offsets/queuebuster.ngc", + sourceFiles: [ + "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini", + "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc", + ], + }, +]; + function isVirtualHalSimConfigSourceCoverageReady(report) { const coverage = objectOrEmpty(report); return coverage.apiName === "linuxcnc-wasm-virtual-hal-sim-config-source-coverage-report" && @@ -176,6 +196,29 @@ function hasRequiredPromotionCandidates(rows) { ); } +function isVirtualHalSimConfigMacroLoadFixtureReportReady(report) { + const fixtureReport = objectOrEmpty(report); + const rows = arrayOrEmpty(fixtureReport.rows); + return fixtureReport.apiName === "linuxcnc-wasm-virtual-hal-sim-config-macro-load-fixture-report" && + fixtureReport.complete === true && + fixtureReport.webSimulationSatisfied === true && + fixtureReport.inventoryBaselineUnchanged === true && + arrayOrEmpty(fixtureReport.missingFixtures).length === 0 && + arrayOrEmpty(fixtureReport.blockedFixtureIds).length === 0 && + arrayOrEmpty(fixtureReport.standaloneMainViolations).length === 0 && + arrayOrEmpty(fixtureReport.missingManifestFiles).length === 0 && + REQUIRED_MACRO_LOAD_FIXTURES.every((fixture) => + rows.some((row) => + row.id === fixture.id && + row.complete === true && + row.nonMainFixture === true && + row.targetBrowserEvidence === "non-main-fixture-diagnostics" && + row.fixturePath === fixture.fixturePath && + fixture.sourceFiles.every((file) => arrayOrEmpty(row.sourceFiles).includes(file)) + ) + ); +} + function isVirtualHalMotionControllerMatrixReady(report) { const matrix = objectOrEmpty(report); return matrix.apiName === "linuxcnc-wasm-virtual-hal-motion-controller-matrix-report" && @@ -218,6 +261,7 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac const commandScriptFixtures = objectOrEmpty(artifactObject.virtualHalCommandScriptFixtures); const motionControllerMatrix = objectOrEmpty(artifactObject.virtualHalMotionControllerMatrix); const promotionCandidates = objectOrEmpty(artifactObject.virtualHalSimConfigPromotionCandidates); + const macroLoadFixtures = objectOrEmpty(artifactObject.virtualHalSimConfigMacroLoadFixtures); const sessionDiagnostics = objectOrEmpty(artifactObject.virtualHalSessionDiagnostics); const replacement = objectOrEmpty(artifactObject.virtualHalSimulationReplacement); const virtualHal = objectOrEmpty(artifactObject.virtualHal); @@ -234,6 +278,9 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac const hasPromotionCandidates = artifactObject.virtualHalSimConfigPromotionCandidates !== undefined; const promotionCandidatesReady = !hasPromotionCandidates || isVirtualHalSimConfigPromotionCandidateReportReady(promotionCandidates); + const hasMacroLoadFixtures = artifactObject.virtualHalSimConfigMacroLoadFixtures !== undefined; + const macroLoadFixturesReady = hasMacroLoadFixtures && + isVirtualHalSimConfigMacroLoadFixtureReportReady(macroLoadFixtures); const replacementReady = replacement.ready === true && replacement.replacesHostRuntimeForSimulation === true && objectOrEmpty(replacement.sourceCompliance).webSimulationSatisfied === true && @@ -256,6 +303,7 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac ...(sourceComplianceReady ? [] : ["virtualHalSourceCompliance"]), ...(simConfigSourceCoverageReady ? [] : ["virtualHalSimConfigSourceCoverage"]), ...(promotionCandidatesReady ? [] : ["virtualHalSimConfigPromotionCandidates"]), + ...(macroLoadFixturesReady ? [] : ["virtualHalSimConfigMacroLoadFixtures"]), ...(commandScriptFixturesReady ? [] : ["virtualHalCommandScriptFixtures"]), ...(motionControllerMatrixReady ? [] : ["virtualHalMotionControllerMatrix"]), ...(sessionDiagnosticsReady ? [] : ["virtualHalSessionDiagnostics"]), @@ -273,6 +321,8 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac simConfigSourceCoverageReady, promotionCandidatesReady, hasPromotionCandidates, + macroLoadFixturesReady, + hasMacroLoadFixtures, commandScriptFixturesReady, motionControllerMatrixReady, sessionDiagnosticsReady, @@ -281,6 +331,7 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac ...arrayOrEmpty(sourceCompliance.sourceFiles), ...arrayOrEmpty(simConfigSourceCoverage.sourceFiles), ...arrayOrEmpty(promotionCandidates.sourceFiles), + ...arrayOrEmpty(macroLoadFixtures.sourceFiles), ...arrayOrEmpty(commandScriptFixtures.sourceFiles), ...arrayOrEmpty(motionControllerMatrix.sourceFiles), ...arrayOrEmpty(motionControllerMatrix.simConfigSourceFiles), @@ -311,6 +362,11 @@ export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifac label: "Virtual HAL sim-config promotion candidates", value: hasPromotionCandidates ? (promotionCandidatesReady ? "ready" : "missing") : "not provided", }, + { + id: "sim-config-macro-load-fixtures", + label: "Virtual HAL sim-config macro/load fixtures", + value: hasMacroLoadFixtures ? (macroLoadFixturesReady ? "ready" : "missing") : "not provided", + }, { id: "command-script-fixtures", label: "Virtual HAL command script fixtures", diff --git a/wasm-port/runtime/ui/simulation/index.html b/wasm-port/runtime/ui/simulation/index.html index 372e1e1..26a63d7 100644 --- a/wasm-port/runtime/ui/simulation/index.html +++ b/wasm-port/runtime/ui/simulation/index.html @@ -1805,6 +1805,7 @@ M2 import { DEFAULT_SIMULATION_PROGRAM_ID, VIRTUAL_HAL_AXES as SHARED_VIRTUAL_HAL_AXES, + 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_SOURCE_TARGETS as SHARED_VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS, applyVirtualHalAction as applySharedVirtualHalAction, @@ -1817,6 +1818,7 @@ M2 createVirtualHalMachineStatusState as createSharedVirtualHalMachineStatusState, createVirtualHalMotionControllerMatrixReport as createSharedVirtualHalMotionControllerMatrixReport, createVirtualHalPinRegistry as createSharedVirtualHalPinRegistry, + createVirtualHalSimConfigMacroLoadFixtureReport as createSharedVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalSimConfigPromotionCandidateReport as createSharedVirtualHalSimConfigPromotionCandidateReport, createVirtualHalSimConfigSourceCoverageReport as createSharedVirtualHalSimConfigSourceCoverageReport, createVirtualHalSimulationReplacementReport as createSharedVirtualHalSimulationReplacementReport, @@ -1986,6 +1988,7 @@ M2 }; const statusHistory = []; const VIRTUAL_HAL_AXES = SHARED_VIRTUAL_HAL_AXES; + const VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES = SHARED_VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES; const VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES = SHARED_VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES; const VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES = SHARED_VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS.flatMap((target) => target.sourceFiles ?? []); let virtualHalState = createVirtualHalState(); @@ -2531,6 +2534,15 @@ M2 }); } + function createVirtualHalSimConfigMacroLoadFixtureReport() { + return createSharedVirtualHalSimConfigMacroLoadFixtureReport({ + manifestEntries: [ + ...VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES, + ...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES.flatMap((fixture) => fixture.sourceFiles ?? []), + ], + }); + } + function createVirtualHalCommandScriptFixtureReport() { return createSharedVirtualHalCommandScriptFixtureReport({ halState: virtualHalState }); } @@ -2630,6 +2642,7 @@ M2 virtualHalSourceCompliance: createVirtualHalSourceComplianceReport(), virtualHalSimConfigSourceCoverage: createVirtualHalSimConfigSourceCoverageReport(), virtualHalSimConfigPromotionCandidates: createVirtualHalSimConfigPromotionCandidateReport(), + virtualHalSimConfigMacroLoadFixtures: createVirtualHalSimConfigMacroLoadFixtureReport(), virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport(), virtualHalMotionControllerMatrix: createVirtualHalMotionControllerMatrixReport(), virtualHalSessionDiagnostics: createVirtualHalSessionDiagnosticsArtifact(), @@ -2665,6 +2678,8 @@ M2 virtualHalSimulationReplacement: virtualHal.diagnostics, virtualHalSourceCompliance: virtualHal.sourceCompliance, virtualHalSimConfigSourceCoverage: virtualHal.simConfigSourceCoverage, + virtualHalSimConfigPromotionCandidates: virtualHal.simConfigPromotionCandidates, + virtualHalSimConfigMacroLoadFixtures: virtualHal.simConfigMacroLoadFixtures, virtualHalCommandScriptFixtures: virtualHal.commandScriptFixtures, virtualHalMotionControllerMatrix: virtualHal.motionControllerMatrix, }; @@ -3596,7 +3611,11 @@ M2 async function saveVirtualHalSessionSnapshot(options = {}) { const session = virtualHalSessionOptions(options); const virtualHal = createVirtualHalSessionPayload(virtualHalState, { - manifestEntries: VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES, + manifestEntries: [ + ...VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES, + ...VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES.flatMap((candidate) => candidate.sourceFiles ?? []), + ...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES.flatMap((fixture) => fixture.sourceFiles ?? []), + ], }); const payload = createMachineSessionSnapshotPayload(session.machineId, { ...(session.gcodeFilename ? { gcodeFilename: session.gcodeFilename } : {}), @@ -4062,6 +4081,7 @@ M2 getVirtualHalSourceComplianceReport: () => createVirtualHalSourceComplianceReport(), getVirtualHalSimConfigSourceCoverageReport: () => createVirtualHalSimConfigSourceCoverageReport(), getVirtualHalSimConfigPromotionCandidateReport: () => createVirtualHalSimConfigPromotionCandidateReport(), + getVirtualHalSimConfigMacroLoadFixtureReport: () => createVirtualHalSimConfigMacroLoadFixtureReport(), getVirtualHalCommandScriptFixtureReport: () => createVirtualHalCommandScriptFixtureReport(), getVirtualHalMotionControllerMatrixReport: () => createVirtualHalMotionControllerMatrixReport(), getVirtualRealtimeHalRuntimeReport: () => createVirtualHalSimulationReplacementReport(), diff --git a/wasm-port/runtime/ui/simulation/simulation-app.js b/wasm-port/runtime/ui/simulation/simulation-app.js index 0d6d768..6d670da 100644 --- a/wasm-port/runtime/ui/simulation/simulation-app.js +++ b/wasm-port/runtime/ui/simulation/simulation-app.js @@ -19,6 +19,7 @@ export { VIRTUAL_HAL_AXES, VIRTUAL_HAL_AXISUI_PINS, VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES, + VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES, VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES, VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS, VIRTUAL_HAL_SIMULATION_REPLACEMENT_TARGETS, @@ -34,6 +35,7 @@ export { createVirtualHalLimitsHomeState, createVirtualHalMachineStatusState, createVirtualHalPinRegistry, + createVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalSimConfigPromotionCandidateReport, createVirtualHalSimConfigSourceCoverageReport, createVirtualHalSimulationReplacementReport, diff --git a/wasm-port/tests/browser/ini_panel_workflow_overview_smoke.html b/wasm-port/tests/browser/ini_panel_workflow_overview_smoke.html index 027b81f..f122963 100644 --- a/wasm-port/tests/browser/ini_panel_workflow_overview_smoke.html +++ b/wasm-port/tests/browser/ini_panel_workflow_overview_smoke.html @@ -11,6 +11,7 @@ VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS, createVirtualHalCommandScriptFixtureReport, createVirtualHalMotionControllerMatrixReport, + createVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalSimConfigPromotionCandidateReport, createVirtualHalSimConfigSourceCoverageReport, createVirtualHalSimulationReplacementReport, @@ -380,6 +381,16 @@ manifestEntries: VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES, }), }), + virtualHalSimConfigMacroLoadFixtures: createVirtualHalSimConfigMacroLoadFixtureReport({ + manifestEntries: [ + ...VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES, + "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", + "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc", + "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", + "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini", + "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc", + ], + }), virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport({ halState: diagnosticsVirtualHalState }), virtualHalMotionControllerMatrix: createVirtualHalMotionControllerMatrixReport({ manifestEntries: VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES, diff --git a/wasm-port/tests/browser/real_simulation_page_smoke.html b/wasm-port/tests/browser/real_simulation_page_smoke.html index 3bec56c..bda56b4 100644 --- a/wasm-port/tests/browser/real_simulation_page_smoke.html +++ b/wasm-port/tests/browser/real_simulation_page_smoke.html @@ -244,6 +244,7 @@ !api?.getVirtualHalSourceComplianceReport || !api?.getVirtualHalSimConfigSourceCoverageReport || !api?.getVirtualHalSimConfigPromotionCandidateReport || + !api?.getVirtualHalSimConfigMacroLoadFixtureReport || !api?.getVirtualHalCommandScriptFixtureReport || !api?.getVirtualHalMotionControllerMatrixReport || !api?.getVirtualRealtimeHalRuntimeReport @@ -451,6 +452,23 @@ "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", ], ]; + const expectedMacroLoadFixtures = [ + [ + "rose-engine-rcone-macro-load", + "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc", + false, + "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", + "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc", + "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", + ], + [ + "external-offsets-queuebuster-macro-load", + "linuxcnc/configs/sim/axis/external_offsets/queuebuster.ngc", + true, + "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini", + "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc", + ], + ]; if ( diagnosticsArtifact.apiName !== "real-browser-simulation-diagnostics-artifact" || diagnosticsArtifact.statusHistory.length === 0 || @@ -474,6 +492,18 @@ sourceFiles.every((sourceFile) => row.sourceFiles.includes(sourceFile)) ) ) || + diagnosticsArtifact.virtualHalSimConfigMacroLoadFixtures?.complete !== true || + !expectedMacroLoadFixtures.every(([id, fixturePath, declaredOnly, ...sourceFiles]) => + diagnosticsArtifact.virtualHalSimConfigMacroLoadFixtures?.rows?.some((row) => + row.id === id && + row.complete === true && + row.nonMainFixture === true && + row.targetBrowserEvidence === "non-main-fixture-diagnostics" && + row.fixturePath === fixturePath && + row.declaredOnly === declaredOnly && + sourceFiles.every((sourceFile) => row.sourceFiles.includes(sourceFile)) + ) + ) || diagnosticsArtifact.virtualHalCommandScriptFixtures?.complete !== true || !diagnosticsArtifact.virtualHalCommandScriptFixtures?.coveredActions?.includes("loadusr") || diagnosticsArtifact.virtualHalMotionControllerMatrix?.complete !== true || @@ -894,6 +924,7 @@ } const virtualHalReplacement = api.getVirtualHalSimulationReplacementReport(); const promotionCandidateReport = api.getVirtualHalSimConfigPromotionCandidateReport(); + const macroLoadFixtureReport = api.getVirtualHalSimConfigMacroLoadFixtureReport(); if ( virtualHalReplacement.apiName !== "linuxcnc-wasm-virtual-hal-simulation-replacement-report" || virtualHalReplacement.ready !== true || @@ -921,6 +952,19 @@ sourceFiles.every((sourceFile) => row.sourceFiles.includes(sourceFile)) ) ) || + macroLoadFixtureReport.complete !== true || + macroLoadFixtureReport.inventoryBaselineUnchanged !== true || + macroLoadFixtureReport.standaloneMainViolations.length !== 0 || + !expectedMacroLoadFixtures.every(([id, fixturePath, declaredOnly, ...sourceFiles]) => + macroLoadFixtureReport.rows.some((row) => + row.id === id && + row.complete === true && + row.nonMainFixture === true && + row.fixturePath === fixturePath && + row.declaredOnly === declaredOnly && + sourceFiles.every((sourceFile) => row.sourceFiles.includes(sourceFile)) + ) + ) || api.getVirtualRealtimeHalRuntimeReport().ready !== true || api.getVirtualHalSimulationRuntimeReport().replacesHostRuntimeForSimulation !== true ) { diff --git a/wasm-port/tests/opfs/node/verify_file_service.mjs b/wasm-port/tests/opfs/node/verify_file_service.mjs index 8bfeb2d..9f1ceeb 100644 --- a/wasm-port/tests/opfs/node/verify_file_service.mjs +++ b/wasm-port/tests/opfs/node/verify_file_service.mjs @@ -265,6 +265,8 @@ assert.equal(virtualHalSessionPayload.state.hal.signals["x-pos"].value, 2.25); assert.equal(virtualHalSessionPayload.state.hal.nets["x-pos"].includes("axis.x.pos-cmd"), true); assert.equal(virtualHalSessionPayload.sourceCompliance.complete, true); assert.equal(virtualHalSessionPayload.simConfigSourceCoverage.complete, true); +assert.equal(virtualHalSessionPayload.simConfigPromotionCandidates.complete, true); +assert.equal(virtualHalSessionPayload.simConfigMacroLoadFixtures.complete, true); assert.equal(virtualHalSessionPayload.commandScriptFixtures.complete, true); assert.equal(virtualHalSessionPayload.motionControllerMatrix.complete, true); const virtualHalSnapshotPayload = createMachineSessionSnapshotPayload("virtual-hal-machine", { @@ -272,6 +274,7 @@ const virtualHalSnapshotPayload = createMachineSessionSnapshotPayload("virtual-h virtualHal: virtualHalSessionPayload, }); assert.equal(virtualHalSnapshotPayload.virtualHal.state.hal.signals["x-pos"].value, 2.25); +assert.equal(virtualHalSnapshotPayload.virtualHal.simConfigMacroLoadFixtures.inventoryBaselineUnchanged, true); assert.equal(virtualHalSnapshotPayload.virtualHal.commandScriptFixtures.coveredActions.includes("loadusr"), true); assert.equal(virtualHalSnapshotPayload.virtualHal.motionControllerMatrix.sourceFiles.includes("linuxcnc/src/emc/motion/axis.c"), true); assert.deepEqual( diff --git a/wasm-port/tests/sdk/node/verify_project_release_artifact_url_workflow.mjs b/wasm-port/tests/sdk/node/verify_project_release_artifact_url_workflow.mjs index 2a616cd..625fab6 100644 --- a/wasm-port/tests/sdk/node/verify_project_release_artifact_url_workflow.mjs +++ b/wasm-port/tests/sdk/node/verify_project_release_artifact_url_workflow.mjs @@ -11,6 +11,7 @@ import { createProjectReleaseReadinessReport, createVirtualHalSimConfigSourceCoverageReport, createVirtualHalSimConfigPromotionCandidateReport, + createVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalCommandScriptFixtureReport, createVirtualHalMotionControllerMatrixReport, createVirtualHalSimulationReplacementReport, @@ -30,6 +31,9 @@ const virtualHalSimConfigPromotionCandidates = createVirtualHalSimConfigPromotio simConfigSourceCoverage: virtualHalSimConfigSourceCoverage, motionControllerMatrix: virtualHalMotionControllerMatrix, }); +const virtualHalSimConfigMacroLoadFixtures = createVirtualHalSimConfigMacroLoadFixtureReport({ + manifestText: sourceManifestText, +}); const virtualHalState = createVirtualHalState(); const browserDiagnosticsArtifact = { apiName: "real-browser-simulation-diagnostics-artifact", @@ -39,6 +43,7 @@ const browserDiagnosticsArtifact = { virtualHalSourceCompliance: createVirtualHalSourceComplianceReport({ halState: virtualHalState }), virtualHalSimConfigSourceCoverage, virtualHalSimConfigPromotionCandidates, + virtualHalSimConfigMacroLoadFixtures, virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport({ halState: virtualHalState }), virtualHalMotionControllerMatrix, }; @@ -100,6 +105,8 @@ assert.equal(readyWorkflow.validation.ready, true); assert.equal(readyWorkflow.diagnosticsValidation.ready, true); assert.equal(readyWorkflow.diagnosticsValidation.hasPromotionCandidates, true); assert.equal(readyWorkflow.diagnosticsValidation.promotionCandidatesReady, true); +assert.equal(readyWorkflow.diagnosticsValidation.hasMacroLoadFixtures, true); +assert.equal(readyWorkflow.diagnosticsValidation.macroLoadFixturesReady, true); assert.equal(readyWorkflow.diagnosticsValidation.hasSessionDiagnostics, true); assert.equal(readyWorkflow.diagnosticsValidation.sessionDiagnosticsReady, true); assert.equal(readyWorkflow.diagnosticsFetched, true); diff --git a/wasm-port/tests/sdk/node/verify_sdk_surface.mjs b/wasm-port/tests/sdk/node/verify_sdk_surface.mjs index 80455ed..88c5d55 100644 --- a/wasm-port/tests/sdk/node/verify_sdk_surface.mjs +++ b/wasm-port/tests/sdk/node/verify_sdk_surface.mjs @@ -36,6 +36,7 @@ import { VIRTUAL_HAL_COVERAGE_STATES, VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES, VIRTUAL_HAL_PROJECT_PIN_GROUPS, + VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES, VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES, VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS, VIRTUAL_HAL_SOURCE_DERIVED_CAPABILITIES, @@ -90,6 +91,7 @@ import { createVirtualHalPinInventory, createVirtualHalPinRegistry, createVirtualHalProjectReport, + createVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalSimConfigPromotionCandidateReport, createVirtualHalSimConfigSourceCoverageReport, createVirtualHalSimulationReplacementReport, @@ -241,6 +243,7 @@ const requiredExports = [ ["createVirtualHalPinInventory", createVirtualHalPinInventory], ["createVirtualHalPinRegistry", createVirtualHalPinRegistry], ["createVirtualHalProjectReport", createVirtualHalProjectReport], + ["createVirtualHalSimConfigMacroLoadFixtureReport", createVirtualHalSimConfigMacroLoadFixtureReport], ["createVirtualHalSimConfigPromotionCandidateReport", createVirtualHalSimConfigPromotionCandidateReport], ["createVirtualHalSimConfigSourceCoverageReport", createVirtualHalSimConfigSourceCoverageReport], ["createVirtualHalSimulationReplacementReport", createVirtualHalSimulationReplacementReport], @@ -543,6 +546,10 @@ assert.match(sdkIndexText, /\bVIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES\b/); assert.match(sdkReadmeText, /\bVIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES\b/); assert.match(sdkIndexText, /\bcreateVirtualHalSimConfigPromotionCandidateReport\b/); assert.match(sdkReadmeText, /\bcreateVirtualHalSimConfigPromotionCandidateReport\b/); +assert.match(sdkIndexText, /\bVIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES\b/); +assert.match(sdkReadmeText, /\bVIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES\b/); +assert.match(sdkIndexText, /\bcreateVirtualHalSimConfigMacroLoadFixtureReport\b/); +assert.match(sdkReadmeText, /\bcreateVirtualHalSimConfigMacroLoadFixtureReport\b/); assert.match(sdkIndexText, /\bcreateVirtualHalSourceComplianceReport\b/); assert.match(sdkReadmeText, /\bcreateVirtualHalSourceComplianceReport\b/); assert.match(sdkIndexText, /\bcreateVirtualHalSystemCoverageReport\b/); @@ -835,6 +842,49 @@ assert.equal(virtualHalRuntime.getSimConfigPromotionCandidateReport({ simConfigSourceCoverage: simConfigSourceCoverageReport, motionControllerMatrix: manifestCheckedMotionControllerMatrixReport, }).complete, true); +assert.equal(VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES.length >= 2, true); +const simConfigMacroLoadFixtureReport = createVirtualHalSimConfigMacroLoadFixtureReport({ + manifestText: sourceManifestText, +}); +assert.equal( + simConfigMacroLoadFixtureReport.apiName, + "linuxcnc-wasm-virtual-hal-sim-config-macro-load-fixture-report", +); +assert.equal(simConfigMacroLoadFixtureReport.complete, true); +assert.equal(simConfigMacroLoadFixtureReport.webSimulationSatisfied, true); +assert.equal(simConfigMacroLoadFixtureReport.inventoryBaselineUnchanged, true); +assert.equal(simConfigMacroLoadFixtureReport.manifestChecked, true); +assert.equal(simConfigMacroLoadFixtureReport.missingFixtures.length, 0); +assert.equal(simConfigMacroLoadFixtureReport.blockedFixtureIds.length, 0); +assert.equal(simConfigMacroLoadFixtureReport.standaloneMainViolations.length, 0); +assert.equal(simConfigMacroLoadFixtureReport.missingManifestFiles.length, 0); +assert.equal( + simConfigMacroLoadFixtureReport.rows.some((row) => + row.id === "rose-engine-rcone-macro-load" && + row.complete === true && + row.nonMainFixture === true && + row.targetBrowserEvidence === "non-main-fixture-diagnostics" && + row.fixturePath === "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc" && + row.sourceFiles.includes("linuxcnc/configs/sim/axis/rose_engine/rcone.ngc") && + row.sourceFiles.includes("linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc") + ), + true, +); +assert.equal( + simConfigMacroLoadFixtureReport.rows.some((row) => + row.id === "external-offsets-queuebuster-macro-load" && + row.complete === true && + row.nonMainFixture === true && + row.declaredOnly === true && + row.fixturePath === "linuxcnc/configs/sim/axis/external_offsets/queuebuster.ngc" && + row.sourceFiles.includes("linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini") && + row.sourceFiles.includes("linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc") + ), + true, +); +assert.equal(virtualHalRuntime.getSimConfigMacroLoadFixtureReport({ + manifestText: sourceManifestText, +}).complete, true); const sourceComplianceReport = createVirtualHalSourceComplianceReport({ halState: virtualHalRuntime.getState() }); assert.equal(sourceComplianceReport.apiName, "linuxcnc-wasm-virtual-hal-source-compliance-report"); assert.equal(sourceComplianceReport.complete, true); @@ -860,6 +910,8 @@ assert.equal(virtualHalSessionPayload.apiName, "linuxcnc-wasm-virtual-hal-sessio assert.equal(virtualHalSessionPayload.state.hal.signals["x-pos"].value, 1.25); assert.equal(virtualHalSessionPayload.sourceCompliance.complete, true); assert.equal(virtualHalSessionPayload.simConfigSourceCoverage.complete, true); +assert.equal(virtualHalSessionPayload.simConfigPromotionCandidates.complete, true); +assert.equal(virtualHalSessionPayload.simConfigMacroLoadFixtures.complete, true); assert.equal(virtualHalSessionPayload.commandScriptFixtures.complete, true); assert.equal(virtualHalSessionPayload.motionControllerMatrix.complete, true); const virtualHalSessionSnapshot = createSessionSnapshot( @@ -881,6 +933,7 @@ const browserDiagnosticsArtifact = { virtualHalSourceCompliance: sourceComplianceReport, virtualHalSimConfigSourceCoverage: simConfigSourceCoverageReport, virtualHalSimConfigPromotionCandidates: simConfigPromotionCandidateReport, + virtualHalSimConfigMacroLoadFixtures: simConfigMacroLoadFixtureReport, virtualHalCommandScriptFixtures: commandScriptFixtureReport, virtualHalMotionControllerMatrix: manifestCheckedMotionControllerMatrixReport, }; @@ -906,6 +959,8 @@ assert.equal(browserDiagnosticsArtifactValidation.sourceComplianceReady, true); assert.equal(browserDiagnosticsArtifactValidation.simConfigSourceCoverageReady, true); assert.equal(browserDiagnosticsArtifactValidation.promotionCandidatesReady, true); assert.equal(browserDiagnosticsArtifactValidation.hasPromotionCandidates, true); +assert.equal(browserDiagnosticsArtifactValidation.macroLoadFixturesReady, true); +assert.equal(browserDiagnosticsArtifactValidation.hasMacroLoadFixtures, true); assert.equal(browserDiagnosticsArtifactValidation.commandScriptFixturesReady, true); assert.equal(browserDiagnosticsArtifactValidation.motionControllerMatrixReady, true); assert.equal(browserDiagnosticsArtifactValidation.hasSessionDiagnostics, true); @@ -921,6 +976,9 @@ assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/vismach/puma/puma_seam_weld.ngc"), true); assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini"), true); assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/rose_engine/rcone_demo.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.ngc"), true); const runtimeProjectReport = virtualHalRuntime.getProjectReport({ availableFunctions: VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS }); assert.equal(runtimeProjectReport.simulationRuntime.replacesHostRuntimeForSimulation, true); assert.equal(runtimeProjectReport.systemCoverage.unclassifiedSnapshotPins.length, 0); diff --git a/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs b/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs index 7ceb146..c0e3b75 100644 --- a/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs +++ b/wasm-port/tests/ui/node/verify_ini_panel_ui_shell.mjs @@ -9,6 +9,7 @@ import { VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS, createVirtualHalCommandScriptFixtureReport, createVirtualHalMotionControllerMatrixReport, + createVirtualHalSimConfigMacroLoadFixtureReport, createVirtualHalSimConfigPromotionCandidateReport, createVirtualHalSimConfigSourceCoverageReport, createVirtualHalSimulationReplacementReport, @@ -1391,6 +1392,16 @@ const browserDiagnosticsArtifact = { ], motionControllerMatrix: releaseReadinessMotionControllerMatrix, }), + virtualHalSimConfigMacroLoadFixtures: createVirtualHalSimConfigMacroLoadFixtureReport({ + manifestEntries: [ + ...VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES, + "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", + "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc", + "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", + "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini", + "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc", + ], + }), virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport({ halState: browserDiagnosticsVirtualHalState }), virtualHalMotionControllerMatrix: releaseReadinessMotionControllerMatrix, }; @@ -1790,6 +1801,8 @@ assert.equal(releaseArtifactUrlWorkflow.validation.ready, true); assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.ready, true); assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.hasPromotionCandidates, true); assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.promotionCandidatesReady, true); +assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.hasMacroLoadFixtures, true); +assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.macroLoadFixturesReady, true); assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.hasSessionDiagnostics, true); assert.equal(releaseArtifactUrlWorkflow.diagnosticsValidation.sessionDiagnosticsReady, true); assert.equal(