diff --git a/text18.txt b/text18.txt index fe1cad5..10f1f33 100644 --- a/text18.txt +++ b/text18.txt @@ -574,3 +574,54 @@ git diff --check ok gate,形成非 Qt、非 on-abort family 的 promotion proof。 3. 之后再设计 macro/load non-main fixture report,不把 macro/load 误作为 standalone browser main program 执行。 + +### 三、2026-06-18 Non-Qt Virtual HAL Promotion Evidence + +本批接续 QtDragon family promotion,将非 QtDragon Tier 1 candidate 纳入 release +diagnostics required candidate gate,形成非 Qt、非 on-abort family 的 virtual HAL +browser diagnostics proof。 + +新增实质能力: + +- release diagnostics validation 的 required promotion candidate gate 从 QtDragon 6 项扩展为 + Tier 1 全量 8 项: + - QtDragon family 6 个 on-abort candidate; + - `puma-seam-weld`; + - `rose-engine-rcone-demo`; +- `puma-seam-weld` required evidence 必须包含: + - `linuxcnc/configs/sim/axis/vismach/puma/puma.ini`; + - `linuxcnc/configs/sim/axis/vismach/puma/puma_seam_weld.ngc`; + - `linuxcnc/configs/sim/axis/vismach/puma/remap_subs/428remap.ngc`; +- `rose-engine-rcone-demo` required evidence 必须包含: + - `linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini`; + - `linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc`; +- SDK smoke 与 real browser simulation smoke 同步要求上述 8 个 candidate 全部 ready; +- coverage matrix 对 `puma_seam_weld.ngc` 与 `rcone_demo.ngc` 注释更新为 explicit + browser diagnostics evidence; +- promotion analysis 文档新增 Non-Qt Promotion Evidence 小节。 + +语义边界: + +- 本批没有降低 inventory skip count; +- 当前 baseline 仍是 `executed=28`、`passed=28`、`skipped=131`、 + `unexpected_fail=0`; +- PUMA / rose engine promotion 只推进 source-derived diagnostics evidence,不新增 + G-code/interpreter/planner/kinematics/remap 语义; +- PUMA remap subroutine 作为 LinuxCNC source evidence 引用,不把 ASSET-ONLY subroutine + 当 standalone 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 non-main fixture report,首选 + `axis/rose_engine/rcone.ngc` 与 `axis/external_offsets/queuebuster.ngc`。 +2. gate 必须明确 `nonMainFixture === true`,避免把 macro/load 误作为 standalone browser + main program 执行。 +3. 将 macro/load fixture evidence 接入 release diagnostics validation,但不改变当前 + inventory baseline。 diff --git a/wasm-port/docs/sim-config-coverage-promotion-analysis.md b/wasm-port/docs/sim-config-coverage-promotion-analysis.md index c5c9554..eccac81 100644 --- a/wasm-port/docs/sim-config-coverage-promotion-analysis.md +++ b/wasm-port/docs/sim-config-coverage-promotion-analysis.md @@ -209,9 +209,30 @@ sim_configs_wasm_node_inventory_skipped=131 sim_configs_wasm_node_inventory_unexpected_fail=0 ``` -The next practical promotion slice is to add non-Qt evidence for -`axis/vismach/puma/puma_seam_weld.ngc` and -`axis/rose_engine/rcone_demo.ngc`. +## 2026-06-18 Non-Qt Promotion Evidence + +The promotion-candidate release gate has now been extended beyond QtDragon to +the two Tier 1 non-Qt candidates: + +- `axis/vismach/puma/puma_seam_weld.ngc` +- `axis/rose_engine/rcone_demo.ngc` + +The required candidate set now covers all eight source-derived Tier 1 rows: +the six QtDragon on-abort candidates, PUMA seam weld, and rose-engine cone +demo. Release diagnostics validation requires the PUMA row to include +`puma.ini`, `puma_seam_weld.ngc`, and the LinuxCNC remap subroutine source +`remap_subs/428remap.ngc`. It also requires the rose-engine row to include +`rose_engine.ini` and `rcone_demo.ngc`. + +This still does not change inventory promotion counts. Both rows remain Node +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. ## Boundary Statement diff --git a/wasm-port/docs/sim-configs-coverage-matrix.md b/wasm-port/docs/sim-configs-coverage-matrix.md index aefd555..15508e9 100644 --- a/wasm-port/docs/sim-configs-coverage-matrix.md +++ b/wasm-port/docs/sim-configs-coverage-matrix.md @@ -513,7 +513,7 @@ Legend: | `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_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; browser class coverage is represented by other plain INI/tool-table samples | +| `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 | | `axis/vismach/5axis/bridgemill/remap_subs/429remap.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 | @@ -564,7 +564,7 @@ Legend: | `axis/vismach/millturn/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | | `axis/vismach/millturn/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | | `axis/vismach/puma/puma_cube.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `REP` | `REP` | `-` | PUMA kinematics/remap machine class representative covered in Node and browser through vendored INI, tool-table, and remap-subroutine staging | -| `axis/vismach/puma/puma_seam_weld.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | Node inventory covered with the same vendored puma machine context; browser class coverage is represented by `puma_cube.ngc` | +| `axis/vismach/puma/puma_seam_weld.ngc` | `axis/vismach` | `main` | `PASS` | `-` | `-` | `INV` | `-` | `-` | Node inventory covered with the same vendored puma machine context; virtual HAL promotion candidate gate now exports explicit browser diagnostics evidence paired with the `puma_cube.ngc` representative while inventory baseline remains unchanged | | `axis/vismach/puma/remap_subs/428remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | | `axis/vismach/puma/remap_subs/429remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `N/A` | `N/A` | `ASSET-ONLY` | subroutine asset; validate by parse/remap path rather than standalone main-program execution | | `axis/vismach/puma/remap_subs/430remap.ngc` | `axis/vismach` | `remap_subroutine` | `PASS` | `-` | `-` | `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/sdk/src/project-release-readiness.js b/wasm-port/runtime/sdk/src/project-release-readiness.js index a3eed12..e17e2ce 100644 --- a/wasm-port/runtime/sdk/src/project-release-readiness.js +++ b/wasm-port/runtime/sdk/src/project-release-readiness.js @@ -88,7 +88,7 @@ const BLOCKED_RUNTIME_FAMILIES = [ const PROJECT_RELEASE_READINESS_ARTIFACT_API = "project-release-readiness-report"; const PROJECT_RELEASE_READINESS_ARTIFACT_VERSION = 1; -const REQUIRED_QTDRAGON_PROMOTION_CANDIDATES = [ +const REQUIRED_PROMOTION_CANDIDATES = [ { id: "qtdragon-multi-joint-on-abort", sourceFiles: [ @@ -131,6 +131,21 @@ const REQUIRED_QTDRAGON_PROMOTION_CANDIDATES = [ "linuxcnc/configs/sim/qtvcp_screens/qtdragon/on_abort.ngc", ], }, + { + id: "puma-seam-weld", + sourceFiles: [ + "linuxcnc/configs/sim/axis/vismach/puma/puma.ini", + "linuxcnc/configs/sim/axis/vismach/puma/puma_seam_weld.ngc", + "linuxcnc/configs/sim/axis/vismach/puma/remap_subs/428remap.ngc", + ], + }, + { + id: "rose-engine-rcone-demo", + sourceFiles: [ + "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", + "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", + ], + }, ]; function isVirtualHalSimConfigSourceCoverageReady(report) { @@ -148,8 +163,8 @@ function isVirtualHalSimConfigSourceCoverageReady(report) { ); } -function hasRequiredQtDragonPromotionCandidates(rows) { - return REQUIRED_QTDRAGON_PROMOTION_CANDIDATES.every((candidate) => +function hasRequiredPromotionCandidates(rows) { + return REQUIRED_PROMOTION_CANDIDATES.every((candidate) => rows.some((row) => row.id === candidate.id && row.complete === true && @@ -193,7 +208,7 @@ function isVirtualHalSimConfigPromotionCandidateReportReady(report) { arrayOrEmpty(candidateReport.blockedCandidateIds).length === 0 && arrayOrEmpty(candidateReport.missingManifestFiles).length === 0 && arrayOrEmpty(candidateReport.missingRequiredReports).length === 0 && - hasRequiredQtDragonPromotionCandidates(rows); + hasRequiredPromotionCandidates(rows); } export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifact = {}) { diff --git a/wasm-port/tests/browser/real_simulation_page_smoke.html b/wasm-port/tests/browser/real_simulation_page_smoke.html index 11a56f4..3bec56c 100644 --- a/wasm-port/tests/browser/real_simulation_page_smoke.html +++ b/wasm-port/tests/browser/real_simulation_page_smoke.html @@ -408,7 +408,7 @@ throw new Error(`simulation virtual HAL registry/integrity drift: ${JSON.stringify(initialVirtualHalRegistry)}`); } const diagnosticsArtifact = api.exportDiagnosticsArtifact(); - const expectedQtDragonPromotionCandidates = [ + const expectedPromotionCandidates = [ [ "qtdragon-multi-joint-on-abort", "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini", @@ -439,6 +439,17 @@ "linuxcnc/configs/sim/qtvcp_screens/qtdragon/qtdragon_mpg.ini", "linuxcnc/configs/sim/qtvcp_screens/qtdragon/on_abort.ngc", ], + [ + "puma-seam-weld", + "linuxcnc/configs/sim/axis/vismach/puma/puma.ini", + "linuxcnc/configs/sim/axis/vismach/puma/puma_seam_weld.ngc", + "linuxcnc/configs/sim/axis/vismach/puma/remap_subs/428remap.ngc", + ], + [ + "rose-engine-rcone-demo", + "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", + "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", + ], ]; if ( diagnosticsArtifact.apiName !== "real-browser-simulation-diagnostics-artifact" || @@ -454,14 +465,13 @@ !diagnosticsArtifact.virtualHalSimConfigSourceCoverage?.sourceFiles?.includes("linuxcnc/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini") || !diagnosticsArtifact.virtualHalSimConfigSourceCoverage?.sourceFiles?.includes("linuxcnc/configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/qtdragon_hd_z_compensation.ini") || diagnosticsArtifact.virtualHalSimConfigPromotionCandidates?.complete !== true || - !expectedQtDragonPromotionCandidates.every(([id, iniPath, gcodePath]) => + !expectedPromotionCandidates.every(([id, ...sourceFiles]) => diagnosticsArtifact.virtualHalSimConfigPromotionCandidates?.rows?.some((row) => row.id === id && row.complete === true && row.currentNodeInventoryStatus === "PASS" && row.targetBrowserEvidence === "explicit-browser-diagnostics" && - row.sourceFiles.includes(iniPath) && - row.sourceFiles.includes(gcodePath) + sourceFiles.every((sourceFile) => row.sourceFiles.includes(sourceFile)) ) ) || diagnosticsArtifact.virtualHalCommandScriptFixtures?.complete !== true || @@ -903,13 +913,12 @@ !api.getVirtualHalSimConfigSourceCoverageReport().sourceFiles.includes("linuxcnc/configs/sim/qtdragon/qtdragon_xyz/on_abort.ngc") || promotionCandidateReport.complete !== true || promotionCandidateReport.inventoryBaselineUnchanged !== true || - !expectedQtDragonPromotionCandidates.every(([id, iniPath, gcodePath]) => + !expectedPromotionCandidates.every(([id, ...sourceFiles]) => promotionCandidateReport.rows.some((row) => row.id === id && row.complete === true && row.targetBrowserEvidence === "explicit-browser-diagnostics" && - row.sourceFiles.includes(iniPath) && - row.sourceFiles.includes(gcodePath) + sourceFiles.every((sourceFile) => row.sourceFiles.includes(sourceFile)) ) ) || api.getVirtualRealtimeHalRuntimeReport().ready !== true || diff --git a/wasm-port/tests/sdk/node/verify_sdk_surface.mjs b/wasm-port/tests/sdk/node/verify_sdk_surface.mjs index d336dfc..80455ed 100644 --- a/wasm-port/tests/sdk/node/verify_sdk_surface.mjs +++ b/wasm-port/tests/sdk/node/verify_sdk_surface.mjs @@ -774,7 +774,7 @@ assert.equal(simConfigPromotionCandidateReport.missingCandidates.length, 0); assert.equal(simConfigPromotionCandidateReport.blockedCandidateIds.length, 0); assert.equal(simConfigPromotionCandidateReport.missingManifestFiles.length, 0); assert.equal(simConfigPromotionCandidateReport.missingRequiredReports.length, 0); -const expectedQtDragonPromotionCandidates = [ +const expectedPromotionCandidates = [ [ "qtdragon-multi-joint-on-abort", "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini", @@ -805,16 +805,26 @@ const expectedQtDragonPromotionCandidates = [ "linuxcnc/configs/sim/qtvcp_screens/qtdragon/qtdragon_mpg.ini", "linuxcnc/configs/sim/qtvcp_screens/qtdragon/on_abort.ngc", ], + [ + "puma-seam-weld", + "linuxcnc/configs/sim/axis/vismach/puma/puma.ini", + "linuxcnc/configs/sim/axis/vismach/puma/puma_seam_weld.ngc", + "linuxcnc/configs/sim/axis/vismach/puma/remap_subs/428remap.ngc", + ], + [ + "rose-engine-rcone-demo", + "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", + "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", + ], ]; -for (const [id, iniPath, gcodePath] of expectedQtDragonPromotionCandidates) { +for (const [id, ...sourceFiles] of expectedPromotionCandidates) { assert.equal( simConfigPromotionCandidateReport.rows.some((row) => row.id === id && row.complete === true && row.currentNodeInventoryStatus === "PASS" && row.targetBrowserEvidence === "explicit-browser-diagnostics" && - row.sourceFiles.includes(iniPath) && - row.sourceFiles.includes(gcodePath) + sourceFiles.every((sourceFile) => row.sourceFiles.includes(sourceFile)) ), true, ); @@ -908,6 +918,9 @@ assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini"), true); assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/on_abort.ngc"), true); assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/vismach/puma/puma.ini"), true); +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); const runtimeProjectReport = virtualHalRuntime.getProjectReport({ availableFunctions: VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS }); assert.equal(runtimeProjectReport.simulationRuntime.replacesHostRuntimeForSimulation, true); assert.equal(runtimeProjectReport.systemCoverage.unclassifiedSnapshotPins.length, 0);