推进非Qt虚拟HAL诊断证据

This commit is contained in:
2026-06-18 04:58:18 +08:00
parent 3bc3b453c4
commit e263387cea
6 changed files with 129 additions and 20 deletions

View File

@@ -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。

View File

@@ -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

View File

@@ -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 |

View File

@@ -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 = {}) {

View File

@@ -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 ||

View File

@@ -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);