按text22收束promotion证据

结论:完成 evidence-ready / inventory-ready 双层 promotion candidate 管理,release/SDK gate 已纳入 virtual HAL promotion summary,baseline 保持 28/28/131/0,Python remap、tool DB、external user-M hard block 继续 locked。
This commit is contained in:
2026-06-18 17:20:29 +08:00
parent 014081f1f9
commit 1c94ea4527
29 changed files with 8500 additions and 121 deletions

View File

@@ -66,6 +66,15 @@
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness ||
!workflowApi?.renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState ||
!workflowApi?.mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState ||
!workflowApi?.getWorkflowOverviewPromotionFamilyRowsRenderState ||
!workflowApi?.getWorkflowOverviewPromotionFamilySourceFilterViewModel ||
!workflowApi?.getWorkflowOverviewPromotionFamilySourceFilterDomContract ||
!workflowApi?.getWorkflowOverviewPromotionFamilySourceFilterDomReadiness ||
!workflowApi?.getWorkflowOverviewPromotionFamilySourceFilterSelectionActionPlan ||
!workflowApi?.handleWorkflowOverviewPromotionFamilySourceFilterSelectionChange ||
!workflowApi?.bindWorkflowOverviewPromotionFamilySourceFilterSelectionControls ||
!workflowApi?.renderWorkflowOverviewPromotionFamilySourceFilterState ||
!workflowApi?.mountWorkflowOverviewPromotionFamilySourceFilterState ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanRenderState ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanDomContract ||
!workflowApi?.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanDomReadiness ||
@@ -381,6 +390,22 @@
manifestEntries: VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES,
}),
}),
virtualHalPromotionCandidateSummary: {
apiName: "real-browser-simulation-promotion-candidate-summary",
summaryVersion: 1,
phase: "ready",
ready: true,
candidateCount: 8,
readyCandidateCount: 8,
familyCount: 3,
sourceFileCount: 17,
preferredCandidateId: "qtdragon-multi-joint-on-abort",
preferredIniPath: "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini",
preferredGcodePath: "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc",
blockedCandidateIds: [],
explicitBrowserDiagnosticsCount: 8,
inventoryBaseline: "executed=28 passed=28 skipped=131 unexpected_fail=0",
},
virtualHalSimConfigMacroLoadFixtures: createVirtualHalSimConfigMacroLoadFixtureReport({
manifestEntries: [
...VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES,
@@ -543,6 +568,11 @@
assertEqual(releaseArtifactUrlWorkflow.httpStatus, 200, "workflow overview release artifact URL workflow status");
assertEqual(releaseArtifactUrlWorkflow.diagnosticsHttpStatus, 200, "workflow overview diagnostics artifact URL workflow status");
assertEqual(releaseArtifactUrlWorkflow.diagnosticsValidation.ready, true, "workflow overview diagnostics artifact validation");
assertEqual(
releaseArtifactUrlWorkflow.diagnosticsArtifact.virtualHalPromotionCandidateSummary.ready,
true,
"workflow overview diagnostics promotion candidate summary",
);
assertEqual(releaseArtifactUrlWorkflow.diagnosticsValidation.hasSessionDiagnostics, true, "workflow overview diagnostics saved-session presence");
assertEqual(releaseArtifactUrlWorkflow.diagnosticsValidation.sessionDiagnosticsReady, true, "workflow overview diagnostics saved-session validation");
assertEqual(
@@ -567,7 +597,7 @@
);
assertEqual(
releaseArtifactUrlWorkflowRenderResult.rowCount,
12,
18,
"workflow overview release artifact URL workflow render rows",
);
assertEqual(
@@ -575,6 +605,36 @@
true,
"workflow overview release artifact URL workflow diagnostics row",
);
assertEqual(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("virtual-hal-promotion-candidate-summary"),
true,
"workflow overview release artifact URL workflow candidate summary row",
);
assertEqual(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate")?.value,
"qtdragon-multi-joint-on-abort",
"workflow overview release artifact URL workflow candidate id",
);
assertEqual(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-ini")?.value,
"linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini",
"workflow overview release artifact URL workflow candidate INI",
);
assertEqual(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-gcode")?.value,
"linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc",
"workflow overview release artifact URL workflow candidate G-code",
);
assertEqual(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-count")?.value,
"8/8 ready",
"workflow overview release artifact URL workflow candidate count",
);
assertEqual(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-baseline")?.value,
"executed=28 passed=28 skipped=131 unexpected_fail=0",
"workflow overview release artifact URL workflow candidate baseline",
);
assertEqual(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("saved-session-diagnostics"),
true,
@@ -626,16 +686,71 @@
true,
"workflow overview fixed URL workflow gate execution summary row",
);
assertEqual(
releaseArtifactUrlFormResult.promotionFamilyRowsRenderState.ready,
true,
"workflow overview fixed URL workflow promotion family rows ready",
);
assertEqual(
releaseArtifactUrlFormResult.promotionFamilyRowsRenderState.sourceFileCount,
17,
"workflow overview fixed URL workflow promotion family source count",
);
assertEqual(
releaseArtifactUrlFormResult.promotionFamilySourceFilter.ready,
true,
"workflow overview fixed URL workflow source filter readiness",
);
assertEqual(
releaseArtifactUrlFormResult.promotionFamilySourceFilter.filteredSourceFileCount,
17,
"workflow overview fixed URL workflow source filter default count",
);
assertEqual(
releaseArtifactUrlFormResult.promotionFamilySourceFilterMountResult.ready,
true,
"workflow overview fixed URL workflow source filter mount readiness",
);
assertEqual(
releaseArtifactUrlFormResult.promotionFamilySourceFilterBinding.ready,
true,
"workflow overview fixed URL workflow source filter binding readiness",
);
assertEqual(
releaseArtifactUrlFormResult.promotionFamilySourceFilterBinding.boundControlCount,
2,
"workflow overview fixed URL workflow source filter bound controls",
);
assertEqual(
workflowDoc.body.dataset.releaseArtifactUrlWorkflowReady,
"true",
"workflow overview fixed URL workflow form body ready",
);
assertEqual(
workflowDoc.body.dataset.promotionFamilySourceFilterReady,
"true",
"workflow overview fixed URL workflow source filter body ready",
);
assertEqual(
workflowDoc.body.dataset.promotionFamilySourceFilterCount,
"17",
"workflow overview fixed URL workflow source filter body default count",
);
assertEqual(
workflowDoc.querySelector('[data-workflow-overview-release-readiness-artifact-url-workflow-value="browser-diagnostics"]').textContent,
"ready",
"workflow overview fixed URL workflow form browser diagnostics row",
);
assertEqual(
workflowDoc.querySelector('[data-workflow-overview-release-readiness-artifact-url-workflow-value="virtual-hal-promotion-candidate"]').textContent,
"qtdragon-multi-joint-on-abort",
"workflow overview fixed URL workflow form candidate row",
);
assertEqual(
workflowDoc.querySelector('[data-workflow-overview-release-readiness-artifact-url-workflow-value="virtual-hal-promotion-candidate-count"]').textContent,
"8/8 ready",
"workflow overview fixed URL workflow form candidate count row",
);
assertEqual(
workflowDoc.querySelector('[data-workflow-overview-release-readiness-artifact-url-workflow-action-plan-value="next-command"]').textContent,
"none",
@@ -646,6 +761,59 @@
true,
"workflow overview fixed URL workflow gate execution summary DOM row",
);
const sourceFilterMount = workflowDoc.querySelector("[data-workflow-overview-promotion-family-source-filter]");
const sourceFilterFamilySelect = workflowDoc.querySelector(
'[data-workflow-overview-promotion-family-source-filter-select="family"]',
);
const sourceFilterKindSelect = workflowDoc.querySelector(
'[data-workflow-overview-promotion-family-source-filter-select="source-kind"]',
);
assertEqual(
sourceFilterMount.dataset.selectedFamilyId,
"all",
"workflow overview source filter default family",
);
assertEqual(
sourceFilterFamilySelect?.value,
"all",
"workflow overview source filter family select default",
);
assertEqual(
sourceFilterKindSelect?.value,
"all",
"workflow overview source filter kind select default",
);
sourceFilterFamilySelect.value = "virtual-hal-promotion-family-rose-engine-rcone-demo";
sourceFilterFamilySelect.dispatchEvent(new Event("change", { bubbles: true }));
assertEqual(
workflowDoc.body.dataset.promotionFamilySourceFilterFamily,
"virtual-hal-promotion-family-rose-engine-rcone-demo",
"workflow overview source filter change body family",
);
assertEqual(
workflowDoc.body.dataset.promotionFamilySourceFilterCount,
"2",
"workflow overview source filter change source count",
);
assertEqual(
sourceFilterMount.dataset.selectedFamilyId,
"virtual-hal-promotion-family-rose-engine-rcone-demo",
"workflow overview source filter changed mount family",
);
assertEqual(
workflowDoc.querySelectorAll(
'[data-workflow-overview-promotion-family-source-filter-type="source-row"]',
).length,
4,
"workflow overview source filter changed source DOM nodes",
);
assertEqual(
workflowDoc.querySelector(
'[data-workflow-overview-promotion-family-source-filter-value="linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc"]',
)?.textContent,
"linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc",
"workflow overview source filter changed rose engine source row",
);
assertEqual(
releaseArtifactJsonWorkflow.statusLine,
"Ready: Artifact JSON workflow complete",

View File

@@ -97,6 +97,7 @@
"native-runtime-probe-summary.tsv",
"next-boundary-recommendations.tsv",
"next-boundary-worklist.tsv",
"promotion-candidates.tsv",
"python-remap-boundary-summary.tsv",
"python-remap-family-summary.tsv",
"python-remap-native-runtime-alignment.tsv",
@@ -150,7 +151,7 @@
"build/native/source-probes.tsv",
];
if (wasmArtifactNames.length !== 54 || new Set(wasmArtifactNames).size !== wasmArtifactNames.length) {
if (wasmArtifactNames.length !== 55 || new Set(wasmArtifactNames).size !== wasmArtifactNames.length) {
throw new Error("browser_generated_artifact_documentation_coverage: WASM artifact list drift");
}
if (nativeArtifactTokens.length !== 8 || new Set(nativeArtifactTokens).size !== nativeArtifactTokens.length) {

View File

@@ -244,6 +244,8 @@
!api?.getVirtualHalSourceComplianceReport ||
!api?.getVirtualHalSimConfigSourceCoverageReport ||
!api?.getVirtualHalSimConfigPromotionCandidateReport ||
!api?.getVirtualHalPromotionCandidateSummary ||
!api?.getVirtualHalPromotionFamilyRows ||
!api?.getVirtualHalSimConfigMacroLoadFixtureReport ||
!api?.getVirtualHalCommandScriptFixtureReport ||
!api?.getVirtualHalMotionControllerMatrixReport ||
@@ -409,6 +411,7 @@
throw new Error(`simulation virtual HAL registry/integrity drift: ${JSON.stringify(initialVirtualHalRegistry)}`);
}
const diagnosticsArtifact = api.exportDiagnosticsArtifact();
const promotionCandidateSummary = api.getVirtualHalPromotionCandidateSummary();
const expectedPromotionCandidates = [
[
"qtdragon-multi-joint-on-abort",
@@ -458,6 +461,9 @@
"linuxcnc/configs/sim/axis/rose_engine/rcone.ngc",
false,
"linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini",
"rcone.ngc",
34,
"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",
],
@@ -466,6 +472,9 @@
"linuxcnc/configs/sim/axis/external_offsets/queuebuster.ngc",
true,
"linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini",
"queuebuster.ngc",
40,
"linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini",
"linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc",
],
];
@@ -481,6 +490,18 @@
"L4-PYTHON-REMAP",
],
];
const expectedMacroLoadAuditCandidates = [
[
"gscreen-industrial-lathe-wear-toolchange-audit",
"linuxcnc/configs/sim/gscreen/industrial_lathe_wear/toolchange.ngc",
"blocked-missing-owning-ini",
],
[
"qtvcp-industrial-lathe-wear-toolchange-audit",
"linuxcnc/configs/sim/qtvcp_screens/industrial_lathe_wear/toolchange.ngc",
"blocked-missing-owning-ini",
],
];
if (
diagnosticsArtifact.apiName !== "real-browser-simulation-diagnostics-artifact" ||
diagnosticsArtifact.statusHistory.length === 0 ||
@@ -495,18 +516,41 @@
!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 ||
diagnosticsArtifact.virtualHalPromotionCandidateSummary?.ready !== true ||
diagnosticsArtifact.virtualHalPromotionCandidateSummary?.preferredCandidateId !== "qtdragon-multi-joint-on-abort" ||
diagnosticsArtifact.virtualHalPromotionCandidateSummary?.candidateCount !== 8 ||
diagnosticsArtifact.virtualHalPromotionCandidateSummary?.readyCandidateCount !== 8 ||
diagnosticsArtifact.virtualHalPromotionCandidateSummary?.sourceFileCount !== 17 ||
diagnosticsArtifact.virtualHalPromotionCandidateSummary?.inventoryBaseline !== "executed=28 passed=28 skipped=131 unexpected_fail=0" ||
promotionCandidateSummary.ready !== true ||
promotionCandidateSummary.preferredIniPath !== "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini" ||
doc.body.dataset.promotionCandidateReady !== "true" ||
doc.body.dataset.promotionCandidatePreferred !== "qtdragon-multi-joint-on-abort" ||
doc.querySelector('[data-promotion-candidate-summary-value="preferred-candidate"]')?.textContent !== "qtdragon-multi-joint-on-abort" ||
doc.querySelector('[data-promotion-candidate-summary-value="inventory-baseline"]')?.textContent !== "28/28 pass; 131 skip unchanged" ||
!diagnosticsArtifact.virtualHalSimConfigPromotionCandidates?.familyRows?.some((row) =>
row.id === "qtdragon-on-abort" &&
row.candidateCount === 6 &&
row.completeCount === 6 &&
row.explicitBrowserDiagnosticsCount === 6 &&
row.explicitBrowserDiagnosticsReady === true &&
row.complete === true
) ||
!expectedPromotionCandidates.every(([id, ...sourceFiles]) =>
diagnosticsArtifact.virtualHalSimConfigPromotionCandidates?.rows?.some((row) =>
row.id === id &&
row.complete === true &&
row.currentNodeInventoryStatus === "PASS" &&
row.currentMatrixBrowserStatus === "explicit-browser-diagnostics" &&
row.targetBrowserEvidence === "explicit-browser-diagnostics" &&
sourceFiles.every((sourceFile) => row.sourceFiles.includes(sourceFile))
)
) ||
diagnosticsArtifact.virtualHalSimConfigMacroLoadFixtures?.complete !== true ||
diagnosticsArtifact.virtualHalSimConfigMacroLoadFixtures?.blockedFixturePromotionViolations?.length !== 0 ||
!expectedMacroLoadFixtures.every(([id, fixturePath, declaredOnly, ...sourceFiles]) =>
diagnosticsArtifact.virtualHalSimConfigMacroLoadFixtures?.blockedBoundaryEvidenceViolations?.length !== 0 ||
diagnosticsArtifact.virtualHalSimConfigMacroLoadFixtures?.auditPromotionViolations?.length !== 0 ||
!expectedMacroLoadFixtures.every(([id, fixturePath, declaredOnly, declarationSourceFile, declarationValue, declarationLine, ...sourceFiles]) =>
diagnosticsArtifact.virtualHalSimConfigMacroLoadFixtures?.rows?.some((row) =>
row.id === id &&
row.complete === true &&
@@ -514,6 +558,12 @@
row.targetBrowserEvidence === "non-main-fixture-diagnostics" &&
row.fixturePath === fixturePath &&
row.declaredOnly === declaredOnly &&
row.requiresDeclarationEvidence === true &&
row.declarationEvidenceReady === true &&
row.declarationEvidence?.sourceFile === declarationSourceFile &&
row.declarationEvidence?.key === "NGCGUI_SUBFILE" &&
row.declarationEvidence?.value === declarationValue &&
row.declarationEvidence?.line === declarationLine &&
sourceFiles.every((sourceFile) => row.sourceFiles.includes(sourceFile))
)
) ||
@@ -523,6 +573,38 @@
row.fixturePath === fixturePath &&
row.blockedKind === blockedKind &&
row.excludedFromPositiveFixtures === true &&
row.boundaryEvidenceReady === true &&
row.boundaryEvidence?.baselineSummary?.executed === 28 &&
row.boundaryEvidence?.baselineSummary?.passed === 28 &&
row.boundaryEvidence?.baselineSummary?.skipped === 131 &&
row.boundaryEvidence?.baselineSummary?.unexpectedFail === 0 &&
row.boundaryEvidence?.sourceArtifactHashes?.["wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv"] === "de6cf57b7c07182e3bcb32e22dbdf202b618cabc14620d6dff1ef815587950b9" &&
row.boundaryEvidence?.sourceArtifactHashes?.["wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv"] === "b0afe27224e97a82fbecbbd75a7c86233c98fe957d9c1ba20f0656f8745a5eae" &&
row.boundaryEvidence?.boundarySummary?.recommendedBlocked === "UNAVAILABLE" &&
row.boundaryEvidence?.boundarySummary?.dependencies?.includes("missing_vendored_ini:") &&
row.boundaryEvidence?.iniBoundarySummary?.vendored === 0 &&
row.boundaryEvidence?.iniBoundarySummary?.reportAvailable === 0 &&
row.complete === true
)
) ||
!expectedMacroLoadAuditCandidates.every(([id, fixturePath, auditStatus]) =>
diagnosticsArtifact.virtualHalSimConfigMacroLoadFixtures?.auditRows?.some((row) =>
row.id === id &&
row.fixturePath === fixturePath &&
row.auditStatus === auditStatus &&
row.promotionAllowed === false &&
row.excludedFromPositiveFixtures === true &&
row.boundaryEvidenceReady === true &&
row.boundaryEvidence?.baselineSummary?.executed === 28 &&
row.boundaryEvidence?.baselineSummary?.passed === 28 &&
row.boundaryEvidence?.baselineSummary?.skipped === 131 &&
row.boundaryEvidence?.baselineSummary?.unexpectedFail === 0 &&
row.boundaryEvidence?.sourceArtifactHashes?.["wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv"] === "de6cf57b7c07182e3bcb32e22dbdf202b618cabc14620d6dff1ef815587950b9" &&
row.boundaryEvidence?.sourceArtifactHashes?.["wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv"] === "b0afe27224e97a82fbecbbd75a7c86233c98fe957d9c1ba20f0656f8745a5eae" &&
row.boundaryEvidence?.boundarySummary?.recommendedBlocked === "UNAVAILABLE" &&
row.boundaryEvidence?.boundarySummary?.dependencies?.includes("missing_vendored_ini:") &&
row.boundaryEvidence?.iniBoundarySummary?.vendored === 0 &&
row.boundaryEvidence?.iniBoundarySummary?.reportAvailable === 0 &&
row.complete === true
)
) ||
@@ -946,6 +1028,7 @@
}
const virtualHalReplacement = api.getVirtualHalSimulationReplacementReport();
const promotionCandidateReport = api.getVirtualHalSimConfigPromotionCandidateReport();
const promotionFamilyRows = api.getVirtualHalPromotionFamilyRows();
const macroLoadFixtureReport = api.getVirtualHalSimConfigMacroLoadFixtureReport();
if (
virtualHalReplacement.apiName !== "linuxcnc-wasm-virtual-hal-simulation-replacement-report" ||
@@ -966,6 +1049,17 @@
!api.getVirtualHalSimConfigSourceCoverageReport().sourceFiles.includes("linuxcnc/configs/sim/qtdragon/qtdragon_xyz/on_abort.ngc") ||
promotionCandidateReport.complete !== true ||
promotionCandidateReport.inventoryBaselineUnchanged !== true ||
doc.body.dataset.promotionFamilyReady !== "true" ||
doc.body.dataset.promotionFamilyCount !== "3" ||
promotionFamilyRows.length !== 3 ||
![
["qtdragon-on-abort", "6/6 ready; sources=12"],
["vismach-remap-sims", "1/1 ready; sources=3"],
["rose-engine-rcone-demo", "1/1 ready; sources=2"],
].every(([id, value]) =>
doc.querySelector(`[data-promotion-family-row="${id}"]`)?.dataset.promotionFamilyReady === "true" &&
doc.querySelector(`[data-promotion-family-value="${id}"]`)?.textContent === value
) ||
!expectedPromotionCandidates.every(([id, ...sourceFiles]) =>
promotionCandidateReport.rows.some((row) =>
row.id === id &&
@@ -978,13 +1072,21 @@
macroLoadFixtureReport.inventoryBaselineUnchanged !== true ||
macroLoadFixtureReport.standaloneMainViolations.length !== 0 ||
macroLoadFixtureReport.blockedFixturePromotionViolations.length !== 0 ||
!expectedMacroLoadFixtures.every(([id, fixturePath, declaredOnly, ...sourceFiles]) =>
macroLoadFixtureReport.blockedBoundaryEvidenceViolations.length !== 0 ||
macroLoadFixtureReport.auditPromotionViolations.length !== 0 ||
!expectedMacroLoadFixtures.every(([id, fixturePath, declaredOnly, declarationSourceFile, declarationValue, declarationLine, ...sourceFiles]) =>
macroLoadFixtureReport.rows.some((row) =>
row.id === id &&
row.complete === true &&
row.nonMainFixture === true &&
row.fixturePath === fixturePath &&
row.declaredOnly === declaredOnly &&
row.requiresDeclarationEvidence === true &&
row.declarationEvidenceReady === true &&
row.declarationEvidence?.sourceFile === declarationSourceFile &&
row.declarationEvidence?.key === "NGCGUI_SUBFILE" &&
row.declarationEvidence?.value === declarationValue &&
row.declarationEvidence?.line === declarationLine &&
sourceFiles.every((sourceFile) => row.sourceFiles.includes(sourceFile))
)
) ||
@@ -994,6 +1096,38 @@
row.fixturePath === fixturePath &&
row.blockedKind === blockedKind &&
row.excludedFromPositiveFixtures === true &&
row.boundaryEvidenceReady === true &&
row.boundaryEvidence?.baselineSummary?.executed === 28 &&
row.boundaryEvidence?.baselineSummary?.passed === 28 &&
row.boundaryEvidence?.baselineSummary?.skipped === 131 &&
row.boundaryEvidence?.baselineSummary?.unexpectedFail === 0 &&
row.boundaryEvidence?.sourceArtifactHashes?.["wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv"] === "de6cf57b7c07182e3bcb32e22dbdf202b618cabc14620d6dff1ef815587950b9" &&
row.boundaryEvidence?.sourceArtifactHashes?.["wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv"] === "b0afe27224e97a82fbecbbd75a7c86233c98fe957d9c1ba20f0656f8745a5eae" &&
row.boundaryEvidence?.boundarySummary?.recommendedBlocked === "UNAVAILABLE" &&
row.boundaryEvidence?.boundarySummary?.dependencies?.includes("missing_vendored_ini:") &&
row.boundaryEvidence?.iniBoundarySummary?.vendored === 0 &&
row.boundaryEvidence?.iniBoundarySummary?.reportAvailable === 0 &&
row.complete === true
)
) ||
!expectedMacroLoadAuditCandidates.every(([id, fixturePath, auditStatus]) =>
macroLoadFixtureReport.auditRows.some((row) =>
row.id === id &&
row.fixturePath === fixturePath &&
row.auditStatus === auditStatus &&
row.promotionAllowed === false &&
row.excludedFromPositiveFixtures === true &&
row.boundaryEvidenceReady === true &&
row.boundaryEvidence?.baselineSummary?.executed === 28 &&
row.boundaryEvidence?.baselineSummary?.passed === 28 &&
row.boundaryEvidence?.baselineSummary?.skipped === 131 &&
row.boundaryEvidence?.baselineSummary?.unexpectedFail === 0 &&
row.boundaryEvidence?.sourceArtifactHashes?.["wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv"] === "de6cf57b7c07182e3bcb32e22dbdf202b618cabc14620d6dff1ef815587950b9" &&
row.boundaryEvidence?.sourceArtifactHashes?.["wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv"] === "b0afe27224e97a82fbecbbd75a7c86233c98fe957d9c1ba20f0656f8745a5eae" &&
row.boundaryEvidence?.boundarySummary?.recommendedBlocked === "UNAVAILABLE" &&
row.boundaryEvidence?.boundarySummary?.dependencies?.includes("missing_vendored_ini:") &&
row.boundaryEvidence?.iniBoundarySummary?.vendored === 0 &&
row.boundaryEvidence?.iniBoundarySummary?.reportAvailable === 0 &&
row.complete === true
)
) ||

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,8 @@ assert.equal(validation.gateExecutionSummaryReady, true);
assert.equal(validation.gateResultMatrixReady, true);
assert.equal(validation.gateActionPlanReady, true);
assert.equal(validation.virtualHalSimConfigSourceCoverageReady, true);
assert.equal(validation.virtualHalSimConfigPromotionCandidatesReady, true);
assert.equal(validation.virtualHalSimConfigMacroLoadFixturesReady, true);
assert.equal(validation.virtualHalMotionControllerMatrixReady, true);
assert.equal(validation.axisScreenshotArtifactSummaryReady, true);
assert.ok(validation.axisScreenshotArtifactCount === 0 || validation.axisScreenshotArtifactCount === 4);
@@ -60,6 +62,105 @@ assert.equal(artifact.virtualHalSimConfigSourceCoverage.webSimulationSatisfied,
assert.equal(artifact.virtualHalSimConfigSourceCoverageReady, true);
assert.equal(artifact.virtualHalSimConfigSourceCoverage.sourceFiles.includes("linuxcnc/configs/sim/axis/foam/axis_foam.ini"), true);
assert.equal(artifact.virtualHalSimConfigSourceCoverage.sourceFiles.includes("linuxcnc/configs/sim/qtdragon/qtdragon_xyz/on_abort.ngc"), true);
assert.equal(artifact.virtualHalSimConfigPromotionCandidates.apiName, "linuxcnc-wasm-virtual-hal-sim-config-promotion-candidate-report");
assert.equal(artifact.virtualHalSimConfigPromotionCandidates.complete, true);
assert.equal(artifact.virtualHalSimConfigPromotionCandidatesReady, true);
assert.equal(
artifact.virtualHalPromotionFamilySummary,
"qtdragon-on-abort: 6/6 ready; vismach-remap-sims: 1/1 ready; rose-engine-rcone-demo: 1/1 ready",
);
assert.deepEqual(
artifact.virtualHalPromotionFamilyRows.map(({ id, value }) => [id, value]),
[
["qtdragon-on-abort", "6/6 ready; sources=12; diagnostics=ready"],
["vismach-remap-sims", "1/1 ready; sources=3; diagnostics=ready"],
["rose-engine-rcone-demo", "1/1 ready; sources=2; diagnostics=ready"],
],
);
assert.equal(
artifact.virtualHalSimConfigPromotionCandidates.familyRows.some((row) =>
row.id === "qtdragon-on-abort" &&
row.candidateCount === 6 &&
row.completeCount === 6 &&
row.explicitBrowserDiagnosticsCount === 6 &&
row.explicitBrowserDiagnosticsReady === true &&
row.complete === true
),
true,
);
assert.equal(
artifact.virtualHalSimConfigPromotionCandidates.rows.some((row) =>
row.id === "rose-engine-rcone-demo" &&
row.currentMatrixBrowserStatus === "explicit-browser-diagnostics" &&
row.sourceFiles.includes("linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc")
),
true,
);
assert.equal(artifact.virtualHalSimConfigMacroLoadFixtures.apiName, "linuxcnc-wasm-virtual-hal-sim-config-macro-load-fixture-report");
assert.equal(artifact.virtualHalSimConfigMacroLoadFixtures.complete, true);
assert.equal(artifact.virtualHalSimConfigMacroLoadFixturesReady, true);
assert.equal(artifact.virtualHalSimConfigMacroLoadFixtures.declarationEvidenceViolations.length, 0);
assert.equal(artifact.virtualHalSimConfigMacroLoadFixtures.missingAuditRows.length, 0);
assert.equal(artifact.virtualHalSimConfigMacroLoadFixtures.blockedBoundaryEvidenceViolations.length, 0);
assert.equal(artifact.virtualHalSimConfigMacroLoadFixtures.auditPromotionViolations.length, 0);
assert.equal(artifact.virtualHalSimConfigMacroLoadFixtures.auditBoundaryEvidenceViolations.length, 0);
assert.equal(artifact.virtualHalSimConfigMacroLoadFixtures.auditPromotionAllowedViolations.length, 0);
assert.equal(
artifact.virtualHalSimConfigMacroLoadFixtures.rows.some((row) =>
row.id === "rose-engine-rcone-macro-load" &&
row.requiresDeclarationEvidence === true &&
row.declarationEvidenceReady === true &&
row.declarationEvidence.sourceFile === "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini" &&
row.declarationEvidence.key === "NGCGUI_SUBFILE" &&
row.declarationEvidence.value === "rcone.ngc" &&
row.declarationEvidence.line === 34
),
true,
);
assert.equal(
artifact.virtualHalSimConfigMacroLoadFixtures.rows.some((row) =>
row.id === "external-offsets-queuebuster-macro-load" &&
row.requiresDeclarationEvidence === true &&
row.declarationEvidenceReady === true &&
row.declarationEvidence.sourceFile === "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini" &&
row.declarationEvidence.key === "NGCGUI_SUBFILE" &&
row.declarationEvidence.value === "queuebuster.ngc" &&
row.declarationEvidence.line === 40
),
true,
);
assert.equal(
artifact.virtualHalSimConfigMacroLoadFixtures.auditRows.some((row) =>
row.id === "gscreen-industrial-lathe-wear-toolchange-audit" &&
row.promotionAllowed === false &&
row.excludedFromPositiveFixtures === true &&
row.boundaryEvidenceReady === true &&
row.boundaryEvidence.baselineSummary.executed === 28 &&
row.boundaryEvidence.baselineSummary.passed === 28 &&
row.boundaryEvidence.baselineSummary.skipped === 131 &&
row.boundaryEvidence.baselineSummary.unexpectedFail === 0 &&
row.boundaryEvidence.sourceArtifactHashes["wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv"] === "de6cf57b7c07182e3bcb32e22dbdf202b618cabc14620d6dff1ef815587950b9" &&
row.boundaryEvidence.sourceArtifactHashes["wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv"] === "b0afe27224e97a82fbecbbd75a7c86233c98fe957d9c1ba20f0656f8745a5eae" &&
row.boundaryEvidence.boundarySummary.dependencies.includes("missing_vendored_ini:configs/sim/gscreen/industrial_lathe_wear/industrial_lathe_wear.ini") &&
row.boundaryEvidence.iniBoundarySummary.vendored === 0
),
true,
);
assert.equal(
artifact.virtualHalSimConfigMacroLoadFixtures.blockedRows.some((row) =>
row.id === "silverdragon-tool-sensor-python-ui-boundary" &&
row.boundaryEvidenceReady === true &&
row.boundaryEvidence.baselineSummary.executed === 28 &&
row.boundaryEvidence.baselineSummary.passed === 28 &&
row.boundaryEvidence.baselineSummary.skipped === 131 &&
row.boundaryEvidence.baselineSummary.unexpectedFail === 0 &&
row.boundaryEvidence.sourceArtifactHashes["wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv"] === "de6cf57b7c07182e3bcb32e22dbdf202b618cabc14620d6dff1ef815587950b9" &&
row.boundaryEvidence.sourceArtifactHashes["wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv"] === "b0afe27224e97a82fbecbbd75a7c86233c98fe957d9c1ba20f0656f8745a5eae" &&
row.boundaryEvidence.boundarySummary.dependencies.includes("missing_vendored_ini:configs/sim/gscreen/silverdragon/silverdragon.ini") &&
row.boundaryEvidence.iniBoundarySummary.vendored === 0
),
true,
);
assert.equal(artifact.virtualHalMotionControllerMatrix.apiName, "linuxcnc-wasm-virtual-hal-motion-controller-matrix-report");
assert.equal(artifact.virtualHalMotionControllerMatrix.complete, true);
assert.equal(artifact.virtualHalMotionControllerMatrix.manifestChecked, true);

View File

@@ -5,6 +5,8 @@ import { fileURLToPath } from "node:url";
import {
createProjectReleaseReadinessReport,
createVirtualHalMotionControllerMatrixReport,
createVirtualHalSimConfigMacroLoadFixtureReport,
createVirtualHalSimConfigPromotionCandidateReport,
createVirtualHalSimConfigSourceCoverageReport,
} from "../../runtime/sdk/src/index.js";
@@ -31,6 +33,13 @@ const passedGateResults = {
"project-release-gate": true,
};
const virtualHalSimConfigSourceCoverage = createVirtualHalSimConfigSourceCoverageReport({
manifestText: sourceManifestText,
});
const virtualHalMotionControllerMatrix = createVirtualHalMotionControllerMatrixReport({
manifestText: sourceManifestText,
});
function loadAxisScreenshotArtifacts(directory) {
if (!directory || !existsSync(directory)) {
return [];
@@ -65,12 +74,16 @@ const report = createProjectReleaseReadinessReport({
"host_wasm_opfs_browser_smokes=ok",
"project_release_gate=ok",
],
virtualHalSimConfigSourceCoverage: createVirtualHalSimConfigSourceCoverageReport({
manifestText: sourceManifestText,
}),
virtualHalMotionControllerMatrix: createVirtualHalMotionControllerMatrixReport({
virtualHalSimConfigSourceCoverage,
virtualHalSimConfigPromotionCandidates: createVirtualHalSimConfigPromotionCandidateReport({
manifestText: sourceManifestText,
simConfigSourceCoverage: virtualHalSimConfigSourceCoverage,
motionControllerMatrix: virtualHalMotionControllerMatrix,
}),
virtualHalSimConfigMacroLoadFixtures: createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
}),
virtualHalMotionControllerMatrix,
axisScreenshotArtifacts: loadAxisScreenshotArtifacts(axisScreenshotArtifactDir),
});

View File

@@ -43,6 +43,22 @@ const browserDiagnosticsArtifact = {
virtualHalSourceCompliance: createVirtualHalSourceComplianceReport({ halState: virtualHalState }),
virtualHalSimConfigSourceCoverage,
virtualHalSimConfigPromotionCandidates,
virtualHalPromotionCandidateSummary: {
apiName: "real-browser-simulation-promotion-candidate-summary",
summaryVersion: 1,
phase: "ready",
ready: true,
candidateCount: 8,
readyCandidateCount: 8,
familyCount: 3,
sourceFileCount: 17,
preferredCandidateId: "qtdragon-multi-joint-on-abort",
preferredIniPath: "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini",
preferredGcodePath: "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc",
blockedCandidateIds: [],
explicitBrowserDiagnosticsCount: 8,
inventoryBaseline: "executed=28 passed=28 skipped=131 unexpected_fail=0",
},
virtualHalSimConfigMacroLoadFixtures,
virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport({ halState: virtualHalState }),
virtualHalMotionControllerMatrix,
@@ -67,6 +83,8 @@ assert.equal(createProjectReleaseBrowserDiagnosticsArtifactValidation(browserDia
const readyArtifactJson = JSON.stringify(createProjectReleaseReadinessReport({
gateResults: Object.fromEntries(manifest.gateIds.map((id) => [id, true])),
virtualHalSimConfigSourceCoverage,
virtualHalSimConfigPromotionCandidates,
virtualHalSimConfigMacroLoadFixtures,
virtualHalMotionControllerMatrix: browserDiagnosticsArtifact.virtualHalMotionControllerMatrix,
}));
@@ -92,6 +110,13 @@ const readyWorkflow = await loadProjectReleaseReadinessArtifactUrlWorkflow({
});
const readySummary = createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel(readyWorkflow);
const readyActionPlan = createProjectReleaseReadinessArtifactUrlWorkflowActionPlan(readyWorkflow);
const expectedPromotionFamilySummary =
"qtdragon-on-abort: 6/6 ready; vismach-remap-sims: 1/1 ready; rose-engine-rcone-demo: 1/1 ready";
const expectedPromotionFamilyRows = [
["virtual-hal-promotion-family-qtdragon-on-abort", "6/6 ready; sources=12; diagnostics=ready"],
["virtual-hal-promotion-family-vismach-remap-sims", "1/1 ready; sources=3; diagnostics=ready"],
["virtual-hal-promotion-family-rose-engine-rcone-demo", "1/1 ready; sources=2; diagnostics=ready"],
];
assert.equal(fetchedUrl, "/real-browser-simulation-diagnostics.json");
assert.equal(readyWorkflow.apiName, "project-release-readiness-artifact-url-workflow");
@@ -103,14 +128,50 @@ assert.equal(readyWorkflow.fetchError, null);
assert.equal(readyWorkflow.jsonWorkflow.ready, true);
assert.equal(readyWorkflow.validation.ready, true);
assert.equal(readyWorkflow.diagnosticsValidation.ready, true);
assert.equal(readyWorkflow.diagnosticsArtifact.virtualHalPromotionCandidateSummary.ready, true);
assert.equal(readyWorkflow.diagnosticsValidation.hasPromotionCandidates, true);
assert.equal(readyWorkflow.diagnosticsValidation.promotionCandidatesReady, true);
assert.equal(readyWorkflow.validation.virtualHalPromotionFamilySummary, expectedPromotionFamilySummary);
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);
assert.equal(readyWorkflow.diagnosticsHttpStatus, 200);
assert.equal(
readySummary.rows.find(({ id }) => id === "virtual-hal-promotion-families")?.value,
expectedPromotionFamilySummary,
);
assert.equal(
readySummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-summary")?.value,
"ready",
);
assert.equal(
readySummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate")?.value,
"qtdragon-multi-joint-on-abort",
);
assert.equal(
readySummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-ini")?.value,
"linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini",
);
assert.equal(
readySummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-gcode")?.value,
"linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc",
);
assert.equal(
readySummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-count")?.value,
"8/8 ready",
);
assert.equal(
readySummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-baseline")?.value,
"executed=28 passed=28 skipped=131 unexpected_fail=0",
);
assert.deepEqual(
readySummary.rows
.filter(({ id }) => id.startsWith("virtual-hal-promotion-family-"))
.map(({ id, value }) => [id, value]),
expectedPromotionFamilyRows,
);
assert.equal(readyWorkflow.actionPlan.ready, true);
assert.equal(readySummary.apiName, "project-release-readiness-artifact-url-workflow-summary-view-model");
assert.equal(readySummary.statusLine, "Ready: Artifact URL workflow complete");
@@ -121,7 +182,15 @@ assert.deepEqual(
["fetch", "ready (200)"],
["json-workflow", "ready"],
["artifact-validation", "ready"],
["virtual-hal-promotion-families", expectedPromotionFamilySummary],
...expectedPromotionFamilyRows,
["browser-diagnostics", "ready"],
["virtual-hal-promotion-candidate-summary", "ready"],
["virtual-hal-promotion-candidate", "qtdragon-multi-joint-on-abort"],
["virtual-hal-promotion-candidate-ini", "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini"],
["virtual-hal-promotion-candidate-gcode", "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc"],
["virtual-hal-promotion-candidate-count", "8/8 ready"],
["virtual-hal-promotion-candidate-baseline", "executed=28 passed=28 skipped=131 unexpected_fail=0"],
["saved-session-diagnostics", "ready"],
["next-command", "none"],
["missing", "none"],
@@ -143,6 +212,33 @@ assert.deepEqual(readyActionPlan, {
rows: [],
});
const missingPromotionCandidateSummaryArtifact = { ...browserDiagnosticsArtifact };
delete missingPromotionCandidateSummaryArtifact.virtualHalPromotionCandidateSummary;
const missingPromotionCandidateSummaryWorkflow = await loadProjectReleaseReadinessArtifactUrlWorkflow({
artifactUrl: "/project-release-readiness.json",
diagnosticsUrl: "/real-browser-simulation-missing-promotion-candidate-summary.json",
fetchRef: async (url) => ({
ok: true,
status: 200,
text: async () => url === "/real-browser-simulation-missing-promotion-candidate-summary.json"
? JSON.stringify(missingPromotionCandidateSummaryArtifact)
: readyArtifactJson,
}),
});
assert.equal(missingPromotionCandidateSummaryWorkflow.ready, false);
assert.equal(missingPromotionCandidateSummaryWorkflow.diagnosticsValidation.ready, false);
assert.equal(missingPromotionCandidateSummaryWorkflow.diagnosticsValidation.hasPromotionCandidateSummary, false);
assert.equal(missingPromotionCandidateSummaryWorkflow.diagnosticsValidation.promotionCandidateSummaryReady, false);
assert.equal(
missingPromotionCandidateSummaryWorkflow.missing.includes("diagnostics.virtualHalPromotionCandidateSummary"),
true,
);
assert.equal(
createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel(missingPromotionCandidateSummaryWorkflow)
.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-summary")?.value,
"not provided",
);
const liveOnlyDiagnosticsArtifact = { ...browserDiagnosticsSessionNestedArtifact };
const liveOnlyDiagnosticsWorkflow = await loadProjectReleaseReadinessArtifactUrlWorkflow({
artifactUrl: "/project-release-readiness.json",

View File

@@ -3,6 +3,8 @@ import assert from "node:assert/strict";
import {
VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS,
createVirtualHalMotionControllerMatrixReport,
createVirtualHalSimConfigMacroLoadFixtureReport,
createVirtualHalSimConfigPromotionCandidateReport,
createVirtualHalSimConfigSourceCoverageReport,
createProjectReleaseGateActionPlan,
createProjectReleaseGateExecutionManifest,
@@ -24,6 +26,11 @@ const virtualHalSimConfigSourceCoverage = createVirtualHalSimConfigSourceCoverag
const virtualHalMotionControllerMatrix = createVirtualHalMotionControllerMatrixReport({
manifestEntries: VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS.flatMap((target) => target.sourceFiles ?? []),
});
const virtualHalSimConfigPromotionCandidates = createVirtualHalSimConfigPromotionCandidateReport({
simConfigSourceCoverage: virtualHalSimConfigSourceCoverage,
motionControllerMatrix: virtualHalMotionControllerMatrix,
});
const virtualHalSimConfigMacroLoadFixtures = createVirtualHalSimConfigMacroLoadFixtureReport();
assert.equal(manifest.apiName, "project-release-gate-manifest");
assert.equal(manifest.manifestVersion, 1);
@@ -209,6 +216,8 @@ assert.match(partialActionPlan.shellScript, /wasm-port\/tests\/host\/verify_proj
const report = createProjectReleaseReadinessReport({
gateResults: Object.fromEntries(manifest.gateIds.map((id) => [id, true])),
virtualHalSimConfigSourceCoverage,
virtualHalSimConfigPromotionCandidates,
virtualHalSimConfigMacroLoadFixtures,
virtualHalMotionControllerMatrix,
});
assert.deepEqual(report.gateManifest, manifest);
@@ -257,6 +266,16 @@ assert.deepEqual(createProjectReleaseReadinessSummaryViewModel(report), {
label: "Virtual HAL sim-config source coverage",
value: "ready",
},
{
id: "virtual-hal-sim-config-promotion-candidates",
label: "Virtual HAL sim-config promotion candidates",
value: "ready",
},
{
id: "virtual-hal-sim-config-macro-load-fixtures",
label: "Virtual HAL sim-config macro/load fixtures",
value: "ready",
},
{
id: "virtual-hal-motion-controller-matrix",
label: "Virtual HAL motion controller matrix",
@@ -281,12 +300,14 @@ assert.deepEqual(createProjectReleaseReadinessSummaryViewModel(report), {
});
assert.equal(
createProjectReleaseReadinessSummaryViewModel(createProjectReleaseReadinessReport()).statusLine,
"Waiting: project-release-gate, virtual-hal-sim-config-source-coverage, virtual-hal-motion-controller-matrix",
"Waiting: project-release-gate, virtual-hal-sim-config-source-coverage, virtual-hal-sim-config-promotion-candidates, virtual-hal-sim-config-macro-load-fixtures, virtual-hal-motion-controller-matrix",
);
assert.equal(
createProjectReleaseReadinessSummaryViewModel(createProjectReleaseReadinessReport({
gateResults: Object.fromEntries(manifest.gateIds.map((id) => [id, true])),
virtualHalSimConfigSourceCoverage,
virtualHalSimConfigPromotionCandidates,
virtualHalSimConfigMacroLoadFixtures,
virtualHalMotionControllerMatrix,
promotedRuntimeFamilies: ["L4-TOOL-DB"],
})).rows.find(({ id }) => id === "blocked-runtime-families")?.value,
@@ -313,6 +334,13 @@ const artifactUrlWorkflow = await loadProjectReleaseReadinessArtifactUrlWorkflow
const artifactUrlWorkflowSummary = createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel(
artifactUrlWorkflow,
);
const expectedPromotionFamilySummary =
"qtdragon-on-abort: 6/6 ready; vismach-remap-sims: 1/1 ready; rose-engine-rcone-demo: 1/1 ready";
const expectedPromotionFamilyRows = [
["virtual-hal-promotion-family-qtdragon-on-abort", "6/6 ready; sources=12; diagnostics=ready"],
["virtual-hal-promotion-family-vismach-remap-sims", "1/1 ready; sources=3; diagnostics=ready"],
["virtual-hal-promotion-family-rose-engine-rcone-demo", "1/1 ready; sources=2; diagnostics=ready"],
];
assert.equal(
artifactValidationSummary.apiName,
"project-release-readiness-artifact-validation-summary-view-model",
@@ -330,6 +358,10 @@ assert.deepEqual(
["gate-result-matrix", "ready"],
["gate-action-plan", "ready"],
["virtual-hal-sim-config-source-coverage", "ready"],
["virtual-hal-sim-config-promotion-candidates", "ready"],
["virtual-hal-promotion-families", expectedPromotionFamilySummary],
...expectedPromotionFamilyRows,
["virtual-hal-sim-config-macro-load-fixtures", "ready"],
["virtual-hal-motion-controller-matrix", "ready"],
["missing", "none"],
],
@@ -417,7 +449,15 @@ assert.deepEqual(
["fetch", "ready (200)"],
["json-workflow", "ready"],
["artifact-validation", "ready"],
["virtual-hal-promotion-families", expectedPromotionFamilySummary],
...expectedPromotionFamilyRows,
["browser-diagnostics", "not requested"],
["virtual-hal-promotion-candidate-summary", "not requested"],
["virtual-hal-promotion-candidate", "not provided"],
["virtual-hal-promotion-candidate-ini", "not provided"],
["virtual-hal-promotion-candidate-gcode", "not provided"],
["virtual-hal-promotion-candidate-count", "not provided"],
["virtual-hal-promotion-candidate-baseline", "not provided"],
["saved-session-diagnostics", "not requested"],
["next-command", "none"],
["missing", "none"],

View File

@@ -36,8 +36,11 @@ import {
VIRTUAL_HAL_COVERAGE_STATES,
VIRTUAL_HAL_MOTION_CONTROLLER_MATRIX_FIXTURES,
VIRTUAL_HAL_PROJECT_PIN_GROUPS,
VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_AUDIT_CANDIDATES,
VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_BLOCKED_FIXTURES,
VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES,
VIRTUAL_HAL_SIM_CONFIG_INVENTORY_ARTIFACT_HASHES,
VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE,
VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES,
VIRTUAL_HAL_SIM_CONFIG_SOURCE_TARGETS,
VIRTUAL_HAL_SOURCE_DERIVED_CAPABILITIES,
@@ -178,6 +181,16 @@ const sdkIndexText = readFileSync(resolve(root, "runtime/sdk/src/index.js"), "ut
const sdkReadmeText = readFileSync(resolve(root, "runtime/sdk/README.md"), "utf8");
const sourceManifestText = readFileSync(resolve(root, "tools/source-manifest.txt"), "utf8");
const trackerText = readFileSync(resolve(root, "../PROJECT_COMPLETION_TRACKER.md"), "utf8");
const expectedPromotionFamilySummary =
"qtdragon-on-abort: 6/6 ready; vismach-remap-sims: 1/1 ready; rose-engine-rcone-demo: 1/1 ready";
const expectedPromotionFamilyRows = [
["virtual-hal-promotion-family-qtdragon-on-abort", "6/6 ready; sources=12; diagnostics=ready"],
["virtual-hal-promotion-family-vismach-remap-sims", "1/1 ready; sources=3; diagnostics=ready"],
["virtual-hal-promotion-family-rose-engine-rcone-demo", "1/1 ready; sources=2; diagnostics=ready"],
];
const hasFreshBoundaryArtifactHashes = (boundaryEvidence) =>
Object.entries(VIRTUAL_HAL_SIM_CONFIG_INVENTORY_ARTIFACT_HASHES)
.every(([artifactPath, expectedHash]) => boundaryEvidence?.sourceArtifactHashes?.[artifactPath] === expectedHash);
const requiredExports = [
["createLinuxCncIniSdk", createLinuxCncIniSdk],
@@ -551,6 +564,10 @@ 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, /\bVIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_BLOCKED_FIXTURES\b/);
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_BLOCKED_FIXTURES\b/);
assert.match(sdkIndexText, /\bVIRTUAL_HAL_SIM_CONFIG_INVENTORY_ARTIFACT_HASHES\b/);
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_SIM_CONFIG_INVENTORY_ARTIFACT_HASHES\b/);
assert.match(sdkIndexText, /\bVIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE\b/);
assert.match(sdkReadmeText, /\bVIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE\b/);
assert.match(sdkIndexText, /\bcreateVirtualHalSimConfigMacroLoadFixtureReport\b/);
assert.match(sdkReadmeText, /\bcreateVirtualHalSimConfigMacroLoadFixtureReport\b/);
assert.match(sdkIndexText, /\bcreateVirtualHalSourceComplianceReport\b/);
@@ -784,6 +801,39 @@ assert.equal(simConfigPromotionCandidateReport.missingCandidates.length, 0);
assert.equal(simConfigPromotionCandidateReport.blockedCandidateIds.length, 0);
assert.equal(simConfigPromotionCandidateReport.missingManifestFiles.length, 0);
assert.equal(simConfigPromotionCandidateReport.missingRequiredReports.length, 0);
assert.equal(
simConfigPromotionCandidateReport.familyRows.some((row) =>
row.id === "qtdragon-on-abort" &&
row.candidateCount === 6 &&
row.completeCount === 6 &&
row.explicitBrowserDiagnosticsCount === 6 &&
row.explicitBrowserDiagnosticsReady === true &&
row.complete === true &&
row.sourceFiles.includes("linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini") &&
row.sourceFiles.includes("linuxcnc/configs/sim/qtvcp_screens/qtdragon/on_abort.ngc")
),
true,
);
assert.equal(
simConfigPromotionCandidateReport.familyRows.some((row) =>
row.id === "vismach-remap-sims" &&
row.candidateCount === 1 &&
row.complete === true &&
row.explicitBrowserDiagnosticsReady === true &&
row.sourceFiles.includes("linuxcnc/configs/sim/axis/vismach/puma/puma_seam_weld.ngc")
),
true,
);
assert.equal(
simConfigPromotionCandidateReport.familyRows.some((row) =>
row.id === "rose-engine-rcone-demo" &&
row.candidateCount === 1 &&
row.complete === true &&
row.explicitBrowserDiagnosticsReady === true &&
row.sourceFiles.includes("linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc")
),
true,
);
const expectedPromotionCandidates = [
[
"qtdragon-multi-joint-on-abort",
@@ -833,6 +883,7 @@ for (const [id, ...sourceFiles] of expectedPromotionCandidates) {
row.id === id &&
row.complete === true &&
row.currentNodeInventoryStatus === "PASS" &&
row.currentMatrixBrowserStatus === "explicit-browser-diagnostics" &&
row.targetBrowserEvidence === "explicit-browser-diagnostics" &&
sourceFiles.every((sourceFile) => row.sourceFiles.includes(sourceFile))
),
@@ -847,6 +898,19 @@ assert.equal(virtualHalRuntime.getSimConfigPromotionCandidateReport({
}).complete, true);
assert.equal(VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES.length >= 2, true);
assert.equal(VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_BLOCKED_FIXTURES.length >= 2, true);
assert.equal(VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_AUDIT_CANDIDATES.length >= 2, true);
assert.deepEqual(VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE, {
executed: 28,
passed: 28,
skipped: 131,
unexpectedFail: 0,
});
assert.deepEqual(VIRTUAL_HAL_SIM_CONFIG_INVENTORY_ARTIFACT_HASHES, {
"wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv":
"de6cf57b7c07182e3bcb32e22dbdf202b618cabc14620d6dff1ef815587950b9",
"wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv":
"b0afe27224e97a82fbecbbd75a7c86233c98fe957d9c1ba20f0656f8745a5eae",
});
const simConfigMacroLoadFixtureReport = createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
});
@@ -862,7 +926,13 @@ assert.equal(simConfigMacroLoadFixtureReport.missingFixtures.length, 0);
assert.equal(simConfigMacroLoadFixtureReport.blockedFixtureIds.length, 0);
assert.equal(simConfigMacroLoadFixtureReport.standaloneMainViolations.length, 0);
assert.equal(simConfigMacroLoadFixtureReport.blockedFixturePromotionViolations.length, 0);
assert.equal(simConfigMacroLoadFixtureReport.blockedBoundaryEvidenceViolations.length, 0);
assert.equal(simConfigMacroLoadFixtureReport.missingAuditRows.length, 0);
assert.equal(simConfigMacroLoadFixtureReport.auditPromotionViolations.length, 0);
assert.equal(simConfigMacroLoadFixtureReport.auditBoundaryEvidenceViolations.length, 0);
assert.equal(simConfigMacroLoadFixtureReport.auditPromotionAllowedViolations.length, 0);
assert.equal(simConfigMacroLoadFixtureReport.missingManifestFiles.length, 0);
assert.equal(simConfigMacroLoadFixtureReport.declarationEvidenceViolations.length, 0);
assert.equal(
simConfigMacroLoadFixtureReport.rows.some((row) =>
row.id === "rose-engine-rcone-macro-load" &&
@@ -870,6 +940,12 @@ assert.equal(
row.nonMainFixture === true &&
row.targetBrowserEvidence === "non-main-fixture-diagnostics" &&
row.fixturePath === "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc" &&
row.requiresDeclarationEvidence === true &&
row.declarationEvidenceReady === true &&
row.declarationEvidence.sourceFile === "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini" &&
row.declarationEvidence.key === "NGCGUI_SUBFILE" &&
row.declarationEvidence.value === "rcone.ngc" &&
row.declarationEvidence.line === 34 &&
row.sourceFiles.includes("linuxcnc/configs/sim/axis/rose_engine/rcone.ngc") &&
row.sourceFiles.includes("linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc")
),
@@ -881,18 +957,50 @@ assert.equal(
row.complete === true &&
row.nonMainFixture === true &&
row.declaredOnly === true &&
row.declarationEvidenceReady === true &&
row.declarationEvidence.sourceFile === "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini" &&
row.declarationEvidence.key === "NGCGUI_SUBFILE" &&
row.declarationEvidence.value === "queuebuster.ngc" &&
row.declarationEvidence.line === 40 &&
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(createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
fixtures: [
{
...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES.find(({ id }) => id === "external-offsets-queuebuster-macro-load"),
declarationEvidence: null,
},
],
}).declarationEvidenceViolations.includes("external-offsets-queuebuster-macro-load"), true);
assert.equal(createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
fixtures: [
{
...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES.find(({ id }) => id === "rose-engine-rcone-macro-load"),
declarationEvidence: null,
},
],
}).declarationEvidenceViolations.includes("rose-engine-rcone-macro-load"), true);
assert.equal(
simConfigMacroLoadFixtureReport.blockedRows.some((row) =>
row.id === "silverdragon-tool-sensor-python-ui-boundary" &&
row.fixturePath === "linuxcnc/configs/sim/gscreen/silverdragon/macros/tool_sensor.ngc" &&
row.blockedKind === "PYTHON-UI-PROCESS" &&
row.excludedFromPositiveFixtures === true &&
row.boundaryEvidenceReady === true &&
hasFreshBoundaryArtifactHashes(row.boundaryEvidence) &&
row.boundaryEvidence.boundarySummary.dependencies.includes("missing_vendored_ini:configs/sim/gscreen/silverdragon/silverdragon.ini") &&
row.boundaryEvidence.baselineSummary.executed === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.executed &&
row.boundaryEvidence.baselineSummary.passed === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.passed &&
row.boundaryEvidence.baselineSummary.skipped === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.skipped &&
row.boundaryEvidence.baselineSummary.unexpectedFail === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.unexpectedFail &&
row.boundaryEvidence.iniBoundarySummary.vendored === 0 &&
row.boundaryEvidence.iniBoundarySummary.reportAvailable === 0 &&
row.complete === true
),
true,
@@ -903,10 +1011,170 @@ assert.equal(
row.fixturePath === "linuxcnc/configs/sim/gmoccapy/macros/on_abort.ngc" &&
row.blockedKind === "L4-PYTHON-REMAP" &&
row.excludedFromPositiveFixtures === true &&
row.boundaryEvidenceReady === true &&
hasFreshBoundaryArtifactHashes(row.boundaryEvidence) &&
row.boundaryEvidence.boundarySummary.dependencies.includes("missing_vendored_ini:configs/sim/gmoccapy/6_axis.ini") &&
row.boundaryEvidence.baselineSummary.executed === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.executed &&
row.boundaryEvidence.baselineSummary.passed === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.passed &&
row.boundaryEvidence.baselineSummary.skipped === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.skipped &&
row.boundaryEvidence.baselineSummary.unexpectedFail === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.unexpectedFail &&
row.boundaryEvidence.iniBoundarySummary.vendored === 0 &&
row.boundaryEvidence.iniBoundarySummary.reportAvailable === 0 &&
row.complete === true
),
true,
);
assert.equal(
simConfigMacroLoadFixtureReport.auditRows.some((row) =>
row.id === "gscreen-industrial-lathe-wear-toolchange-audit" &&
row.fixturePath === "linuxcnc/configs/sim/gscreen/industrial_lathe_wear/toolchange.ngc" &&
row.auditStatus === "blocked-missing-owning-ini" &&
row.promotionAllowed === false &&
row.excludedFromPositiveFixtures === true &&
row.boundaryEvidenceReady === true &&
hasFreshBoundaryArtifactHashes(row.boundaryEvidence) &&
row.boundaryEvidence.boundarySummary.recommendedBlocked === "UNAVAILABLE" &&
row.boundaryEvidence.boundarySummary.dependencies.includes("missing_vendored_ini:configs/sim/gscreen/industrial_lathe_wear/industrial_lathe_wear.ini") &&
row.boundaryEvidence.baselineSummary.executed === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.executed &&
row.boundaryEvidence.baselineSummary.passed === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.passed &&
row.boundaryEvidence.baselineSummary.skipped === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.skipped &&
row.boundaryEvidence.baselineSummary.unexpectedFail === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.unexpectedFail &&
row.boundaryEvidence.iniBoundarySummary.vendored === 0 &&
row.boundaryEvidence.iniBoundarySummary.reportAvailable === 0 &&
row.complete === true
),
true,
);
assert.equal(
simConfigMacroLoadFixtureReport.auditRows.some((row) =>
row.id === "qtvcp-industrial-lathe-wear-toolchange-audit" &&
row.fixturePath === "linuxcnc/configs/sim/qtvcp_screens/industrial_lathe_wear/toolchange.ngc" &&
row.auditStatus === "blocked-missing-owning-ini" &&
row.promotionAllowed === false &&
row.excludedFromPositiveFixtures === true &&
row.boundaryEvidenceReady === true &&
hasFreshBoundaryArtifactHashes(row.boundaryEvidence) &&
row.boundaryEvidence.boundarySummary.recommendedBlocked === "UNAVAILABLE" &&
row.boundaryEvidence.boundarySummary.dependencies.includes("missing_vendored_ini:configs/sim/qtvcp_screens/industrial_lathe_wear/industrial_lathe_wear.ini") &&
row.boundaryEvidence.baselineSummary.executed === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.executed &&
row.boundaryEvidence.baselineSummary.passed === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.passed &&
row.boundaryEvidence.baselineSummary.skipped === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.skipped &&
row.boundaryEvidence.baselineSummary.unexpectedFail === VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE.unexpectedFail &&
row.boundaryEvidence.iniBoundarySummary.vendored === 0 &&
row.boundaryEvidence.iniBoundarySummary.reportAvailable === 0 &&
row.complete === true
),
true,
);
assert.equal(createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
auditCandidates: [],
}).complete, true);
assert.equal(createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
blockedFixtures: [
{
id: "bad-blocked-boundary-evidence",
fixturePath: "linuxcnc/configs/sim/gscreen/silverdragon/macros/tool_sensor.ngc",
owningIniPath: "linuxcnc/configs/sim/gscreen/silverdragon/silverdragon.ini",
blockedKind: "PYTHON-UI-PROCESS",
dependencyClass: "macro-load-python-ui-boundary",
reason: "negative fixture: blocked row missing generated boundary evidence must fail",
},
],
}).blockedBoundaryEvidenceViolations.includes("bad-blocked-boundary-evidence"), true);
assert.equal(createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
blockedFixtures: [
{
...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_BLOCKED_FIXTURES.find(
({ id }) => id === "silverdragon-tool-sensor-python-ui-boundary",
),
id: "stale-blocked-boundary-evidence",
boundaryEvidence: {
...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_BLOCKED_FIXTURES.find(
({ id }) => id === "silverdragon-tool-sensor-python-ui-boundary",
).boundaryEvidence,
baselineSummary: {
...VIRTUAL_HAL_SIM_CONFIG_INVENTORY_BASELINE,
skipped: 130,
},
},
},
],
}).blockedBoundaryEvidenceViolations.includes("stale-blocked-boundary-evidence"), true);
assert.equal(createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
blockedFixtures: [
{
...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_BLOCKED_FIXTURES.find(
({ id }) => id === "silverdragon-tool-sensor-python-ui-boundary",
),
id: "stale-hash-blocked-boundary-evidence",
boundaryEvidence: {
...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_BLOCKED_FIXTURES.find(
({ id }) => id === "silverdragon-tool-sensor-python-ui-boundary",
).boundaryEvidence,
sourceArtifactHashes: {
...VIRTUAL_HAL_SIM_CONFIG_INVENTORY_ARTIFACT_HASHES,
"wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv": "stale",
},
},
},
],
}).blockedBoundaryEvidenceViolations.includes("stale-hash-blocked-boundary-evidence"), true);
assert.equal(createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
fixtures: [
...VIRTUAL_HAL_SIM_CONFIG_MACRO_LOAD_FIXTURES,
{
id: "bad-positive-industrial-lathe-audit",
label: "Bad positive industrial lathe audit fixture",
fixturePath: "linuxcnc/configs/sim/gscreen/industrial_lathe_wear/toolchange.ngc",
sourceFiles: [
"linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini",
],
owningIniPath: "linuxcnc/configs/sim/gscreen/industrial_lathe_wear/industrial_lathe_wear.ini",
pairedMainProgram: "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc",
declarationSource: "NGCGUI_SUBFILE",
currentNodeInventoryStatus: "PASS",
dependencyClass: "macro-load-ui-family-audit",
targetBrowserEvidence: "non-main-fixture-diagnostics",
blockedKind: "-",
nonMainFixture: true,
declaredOnly: false,
evidence: "negative fixture: audit candidate must not be promoted as a positive fixture",
},
],
}).auditPromotionViolations.includes("gscreen-industrial-lathe-wear-toolchange-audit"), true);
assert.equal(createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
auditCandidates: [
{
id: "bad-audit-boundary-evidence",
fixturePath: "linuxcnc/configs/sim/gscreen/industrial_lathe_wear/toolchange.ngc",
owningIniPath: "linuxcnc/configs/sim/gscreen/industrial_lathe_wear/industrial_lathe_wear.ini",
dependencyClass: "macro-load-ui-family-audit",
auditStatus: "blocked-missing-owning-ini",
promotionAllowed: false,
reason: "negative fixture: missing generated boundary evidence must fail",
},
],
}).auditBoundaryEvidenceViolations.includes("bad-audit-boundary-evidence"), true);
assert.equal(createVirtualHalSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
auditCandidates: [
{
id: "bad-audit-promotion-allowed",
fixturePath: "linuxcnc/configs/sim/qtvcp_screens/industrial_lathe_wear/toolchange.ngc",
owningIniPath: "linuxcnc/configs/sim/qtvcp_screens/industrial_lathe_wear/industrial_lathe_wear.ini",
dependencyClass: "macro-load-ui-family-audit",
auditStatus: "blocked-missing-owning-ini",
promotionAllowed: true,
reason: "negative fixture: promotionAllowed true without boundary/source proof must fail",
},
],
}).auditPromotionAllowedViolations.includes("bad-audit-promotion-allowed"), true);
assert.equal(virtualHalRuntime.getSimConfigMacroLoadFixtureReport({
manifestText: sourceManifestText,
}).complete, true);
@@ -958,6 +1226,22 @@ const browserDiagnosticsArtifact = {
virtualHalSourceCompliance: sourceComplianceReport,
virtualHalSimConfigSourceCoverage: simConfigSourceCoverageReport,
virtualHalSimConfigPromotionCandidates: simConfigPromotionCandidateReport,
virtualHalPromotionCandidateSummary: {
apiName: "real-browser-simulation-promotion-candidate-summary",
summaryVersion: 1,
phase: "ready",
ready: true,
candidateCount: 8,
readyCandidateCount: 8,
familyCount: 3,
sourceFileCount: 17,
preferredCandidateId: "qtdragon-multi-joint-on-abort",
preferredIniPath: "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini",
preferredGcodePath: "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc",
blockedCandidateIds: [],
explicitBrowserDiagnosticsCount: 8,
inventoryBaseline: "executed=28 passed=28 skipped=131 unexpected_fail=0",
},
virtualHalSimConfigMacroLoadFixtures: simConfigMacroLoadFixtureReport,
virtualHalCommandScriptFixtures: commandScriptFixtureReport,
virtualHalMotionControllerMatrix: manifestCheckedMotionControllerMatrixReport,
@@ -984,6 +1268,8 @@ assert.equal(browserDiagnosticsArtifactValidation.sourceComplianceReady, true);
assert.equal(browserDiagnosticsArtifactValidation.simConfigSourceCoverageReady, true);
assert.equal(browserDiagnosticsArtifactValidation.promotionCandidatesReady, true);
assert.equal(browserDiagnosticsArtifactValidation.hasPromotionCandidates, true);
assert.equal(browserDiagnosticsArtifactValidation.promotionCandidateSummaryReady, true);
assert.equal(browserDiagnosticsArtifactValidation.hasPromotionCandidateSummary, true);
assert.equal(browserDiagnosticsArtifactValidation.macroLoadFixturesReady, true);
assert.equal(browserDiagnosticsArtifactValidation.hasMacroLoadFixtures, true);
assert.equal(browserDiagnosticsArtifactValidation.commandScriptFixturesReady, true);
@@ -1004,6 +1290,38 @@ 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/external_offsets/eoffsets.ini"), true);
assert.equal(browserDiagnosticsArtifactValidation.sourceFiles.includes("linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc"), true);
assert.equal(createProjectReleaseBrowserDiagnosticsArtifactValidation({
...browserDiagnosticsArtifact,
virtualHalPromotionCandidateSummary: undefined,
}).missing.includes("virtualHalPromotionCandidateSummary"), true);
assert.equal(createProjectReleaseBrowserDiagnosticsArtifactValidation({
...browserDiagnosticsArtifact,
virtualHalPromotionCandidateSummary: {
...browserDiagnosticsArtifact.virtualHalPromotionCandidateSummary,
readyCandidateCount: 7,
},
}).promotionCandidateSummaryReady, false);
assert.equal(createProjectReleaseBrowserDiagnosticsArtifactValidation({
...browserDiagnosticsArtifact,
virtualHalSimConfigMacroLoadFixtures: {
...simConfigMacroLoadFixtureReport,
auditRows: [],
},
}).macroLoadFixturesReady, false);
assert.equal(createProjectReleaseBrowserDiagnosticsArtifactValidation({
...browserDiagnosticsArtifact,
virtualHalSimConfigMacroLoadFixtures: {
...simConfigMacroLoadFixtureReport,
auditBoundaryEvidenceViolations: ["gscreen-industrial-lathe-wear-toolchange-audit"],
},
}).missing.includes("virtualHalSimConfigMacroLoadFixtures"), true);
assert.equal(createProjectReleaseBrowserDiagnosticsArtifactValidation({
...browserDiagnosticsArtifact,
virtualHalSimConfigMacroLoadFixtures: {
...simConfigMacroLoadFixtureReport,
auditPromotionAllowedViolations: ["qtvcp-industrial-lathe-wear-toolchange-audit"],
},
}).ready, false);
const runtimeProjectReport = virtualHalRuntime.getProjectReport({ availableFunctions: VIRTUAL_HAL_WASM_BRIDGE_FUNCTIONS });
assert.equal(runtimeProjectReport.simulationRuntime.replacesHostRuntimeForSimulation, true);
assert.equal(runtimeProjectReport.systemCoverage.unclassifiedSnapshotPins.length, 0);
@@ -1143,6 +1461,8 @@ assert.equal(releaseReadinessWaiting.ready, false);
assert.deepEqual(releaseReadinessWaiting.missing, [
"project-release-gate",
"virtual-hal-sim-config-source-coverage",
"virtual-hal-sim-config-promotion-candidates",
"virtual-hal-sim-config-macro-load-fixtures",
"virtual-hal-motion-controller-matrix",
]);
assert.equal(releaseReadinessWaiting.simConfigInventory.unexpectedFail, 0);
@@ -1157,11 +1477,23 @@ assert.equal(
const releaseReadinessReady = createProjectReleaseReadinessReport({
observedOutputs: ["project_release_gate=ok"],
virtualHalSimConfigSourceCoverage: simConfigSourceCoverageReport,
virtualHalSimConfigPromotionCandidates: simConfigPromotionCandidateReport,
virtualHalSimConfigMacroLoadFixtures: simConfigMacroLoadFixtureReport,
virtualHalMotionControllerMatrix: manifestCheckedMotionControllerMatrixReport,
});
assert.equal(releaseReadinessReady.ready, true);
assert.equal(releaseReadinessReady.releaseGate.passed, true);
assert.equal(releaseReadinessReady.virtualHalSimConfigSourceCoverageReady, true);
assert.equal(releaseReadinessReady.virtualHalSimConfigPromotionCandidatesReady, true);
assert.equal(releaseReadinessReady.virtualHalPromotionFamilySummary, expectedPromotionFamilySummary);
assert.deepEqual(
releaseReadinessReady.virtualHalPromotionFamilyRows.map(({ id, value }) => [
`virtual-hal-promotion-family-${id}`,
value,
]),
expectedPromotionFamilyRows,
);
assert.equal(releaseReadinessReady.virtualHalSimConfigMacroLoadFixturesReady, true);
assert.equal(releaseReadinessReady.virtualHalMotionControllerMatrixReady, true);
assert.deepEqual(releaseReadinessReady.gateManifest, createProjectReleaseGateManifest());
assert.equal(releaseReadinessReady.gateResultMatrix.rows.length, createProjectReleaseGateManifest().gateCount);
@@ -1179,6 +1511,8 @@ assert.equal(
const releaseReadinessWithScreenshots = createProjectReleaseReadinessReport({
gateResults: Object.fromEntries(createProjectReleaseGateManifest().gateIds.map((id) => [id, true])),
virtualHalSimConfigSourceCoverage: simConfigSourceCoverageReport,
virtualHalSimConfigPromotionCandidates: simConfigPromotionCandidateReport,
virtualHalSimConfigMacroLoadFixtures: simConfigMacroLoadFixtureReport,
virtualHalMotionControllerMatrix: manifestCheckedMotionControllerMatrixReport,
axisScreenshotArtifacts: ["desktop-preview", "desktop-dro", "mobile-preview", "mobile-mdi"].map((viewportName) => ({
apiName: "real-browser-simulation-axis-screenshot-artifact",
@@ -1214,6 +1548,8 @@ assert.equal(
const releaseReadinessArtifact = parseProjectReleaseReadinessArtifactJson(JSON.stringify(createProjectReleaseReadinessReport({
gateResults: Object.fromEntries(createProjectReleaseGateManifest().gateIds.map((id) => [id, true])),
virtualHalSimConfigSourceCoverage: simConfigSourceCoverageReport,
virtualHalSimConfigPromotionCandidates: simConfigPromotionCandidateReport,
virtualHalSimConfigMacroLoadFixtures: simConfigMacroLoadFixtureReport,
virtualHalMotionControllerMatrix: manifestCheckedMotionControllerMatrixReport,
})));
assert.equal(releaseReadinessArtifact.apiName, "project-release-readiness-report");
@@ -1235,6 +1571,10 @@ assert.deepEqual(releaseReadinessArtifactValidation, {
gateResultMatrixReady: true,
gateActionPlanReady: true,
virtualHalSimConfigSourceCoverageReady: true,
virtualHalSimConfigPromotionCandidatesReady: true,
virtualHalPromotionFamilySummary: expectedPromotionFamilySummary,
virtualHalPromotionFamilyRows: releaseReadinessReady.virtualHalPromotionFamilyRows,
virtualHalSimConfigMacroLoadFixturesReady: true,
virtualHalMotionControllerMatrixReady: true,
axisScreenshotArtifactSummaryReady: true,
axisScreenshotArtifactCount: 0,
@@ -1284,6 +1624,29 @@ assert.deepEqual(releaseReadinessArtifactValidation, {
label: "Virtual HAL sim-config source coverage",
value: "ready",
},
{
id: "virtual-hal-sim-config-promotion-candidates",
label: "Virtual HAL sim-config promotion candidates",
value: "ready",
},
{
id: "virtual-hal-promotion-families",
label: "Virtual HAL promotion families",
value: expectedPromotionFamilySummary,
},
...expectedPromotionFamilyRows.map(([id, value]) => ({
id,
label: `Promotion family ${id.replace("virtual-hal-promotion-family-", "")}`,
value,
sourceFiles: releaseReadinessReady.virtualHalPromotionFamilyRows.find((row) =>
`virtual-hal-promotion-family-${row.id}` === id
)?.sourceFiles ?? [],
})),
{
id: "virtual-hal-sim-config-macro-load-fixtures",
label: "Virtual HAL sim-config macro/load fixtures",
value: "ready",
},
{
id: "virtual-hal-motion-controller-matrix",
label: "Virtual HAL motion controller matrix",
@@ -1307,6 +1670,20 @@ assert.equal(
).statusLine,
"Ready: Artifact evidence complete",
);
assert.equal(
createProjectReleaseReadinessArtifactValidationSummaryViewModel(
releaseReadinessArtifactValidation,
).rows.find(({ id }) => id === "virtual-hal-promotion-families")?.value,
expectedPromotionFamilySummary,
);
assert.deepEqual(
createProjectReleaseReadinessArtifactValidationSummaryViewModel(
releaseReadinessArtifactValidation,
).rows
.filter(({ id }) => id.startsWith("virtual-hal-promotion-family-"))
.map(({ id, value }) => [id, value]),
expectedPromotionFamilyRows,
);
assert.equal(
createProjectReleaseReadinessArtifactValidationActionPlan(releaseReadinessArtifactValidation).shellScript,
"# Project release readiness artifact validation is already ready.\n",
@@ -1350,6 +1727,34 @@ assert.equal(
).statusLine,
"Ready: Artifact URL workflow complete",
);
assert.equal(
createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel(
await loadProjectReleaseReadinessArtifactUrlWorkflow({
artifactUrl: "/project-release-readiness.json",
fetchRef: async () => ({
ok: true,
status: 200,
text: async () => JSON.stringify(releaseReadinessArtifact),
}),
}),
).rows.find(({ id }) => id === "virtual-hal-promotion-families")?.value,
expectedPromotionFamilySummary,
);
assert.deepEqual(
createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel(
await loadProjectReleaseReadinessArtifactUrlWorkflow({
artifactUrl: "/project-release-readiness.json",
fetchRef: async () => ({
ok: true,
status: 200,
text: async () => JSON.stringify(releaseReadinessArtifact),
}),
}),
).rows
.filter(({ id }) => id.startsWith("virtual-hal-promotion-family-"))
.map(({ id, value }) => [id, value]),
expectedPromotionFamilyRows,
);
assert.equal(
createProjectReleaseReadinessArtifactUrlWorkflowActionPlan(
await loadProjectReleaseReadinessArtifactUrlWorkflow({
@@ -1386,6 +1791,8 @@ assert.deepEqual(
"simConfigInventory.skipped",
"simConfigInventory.unexpectedFail",
"virtualHalSimConfigSourceCoverage",
"virtualHalSimConfigPromotionCandidates",
"virtualHalSimConfigMacroLoadFixtures",
"virtualHalMotionControllerMatrix",
"blockedRuntimeFamilies",
"gateManifest",

View File

@@ -84,6 +84,25 @@ import {
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState,
createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState,
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel,
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract,
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomReadiness,
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionActionPlan,
handleIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionChange,
bindIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionControls,
renderIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState,
mountIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState,
createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomContract,
createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomReadiness,
renderIniPanelShellWorkflowOverviewPromotionFamilyRowsState,
mountIniPanelShellWorkflowOverviewPromotionFamilyRowsState,
createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownViewModel,
createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownRenderState,
createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomContract,
createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomReadiness,
renderIniPanelShellWorkflowOverviewPromotionCandidateDrilldownState,
mountIniPanelShellWorkflowOverviewPromotionCandidateDrilldownState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
@@ -744,6 +763,19 @@ assert.deepEqual(shellViewModel.shellWorkflowOverviewContract, {
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState",
"getWorkflowOverviewPromotionFamilyRowsRenderState",
"getWorkflowOverviewPromotionFamilySourceFilterViewModel",
"getWorkflowOverviewPromotionFamilySourceFilterDomContract",
"getWorkflowOverviewPromotionFamilySourceFilterDomReadiness",
"getWorkflowOverviewPromotionFamilySourceFilterSelectionActionPlan",
"handleWorkflowOverviewPromotionFamilySourceFilterSelectionChange",
"bindWorkflowOverviewPromotionFamilySourceFilterSelectionControls",
"renderWorkflowOverviewPromotionFamilySourceFilterState",
"mountWorkflowOverviewPromotionFamilySourceFilterState",
"getWorkflowOverviewPromotionFamilyRowsDomContract",
"getWorkflowOverviewPromotionFamilyRowsDomReadiness",
"renderWorkflowOverviewPromotionFamilyRowsState",
"mountWorkflowOverviewPromotionFamilyRowsState",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
@@ -1044,7 +1076,27 @@ const mountRowsNode = {
const mountNode = { dataset: {} };
const mountStatusNode = { textContent: "" };
const mountDocument = {
createElement: (tagName) => ({ tagName, dataset: {}, textContent: "" }),
createElement: (tagName) => ({
tagName,
dataset: {},
textContent: "",
children: [],
listeners: {},
append(...nodes) {
this.children.push(...nodes);
},
addEventListener(eventName, handler) {
this.listeners[eventName] = handler;
},
removeEventListener(eventName, handler) {
if (this.listeners[eventName] === handler) {
delete this.listeners[eventName];
}
},
dispatchEvent(eventName) {
return this.listeners[eventName]?.();
},
}),
};
assert.deepEqual(
createIniPanelShellSessionHandoffMountDomReadiness({
@@ -1366,9 +1418,34 @@ assert.deepEqual(createIniPanelShellWorkflowOverviewContract(), shellViewModel.s
const releaseReadinessMotionControllerMatrix = createVirtualHalMotionControllerMatrixReport({
manifestEntries: VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES,
});
const releaseReadinessPromotionCandidates = createVirtualHalSimConfigPromotionCandidateReport({
manifestEntries: [
...VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES,
"linuxcnc/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini",
"linuxcnc/configs/sim/qtdragon/qtdragon_xyz45/on_abort.ngc",
"linuxcnc/configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/qtdragon_hd_z_compensation.ini",
"linuxcnc/configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/on_abort.ngc",
"linuxcnc/configs/sim/axis/vismach/puma/puma_seam_weld.ngc",
"linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini",
"linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc",
],
motionControllerMatrix: releaseReadinessMotionControllerMatrix,
});
const releaseReadinessMacroLoadFixtures = 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",
],
});
const releaseReadinessArtifactJson = JSON.stringify(createProjectReleaseReadinessReport({
gateResults: Object.fromEntries(createProjectReleaseGateManifest().gateIds.map((id) => [id, true])),
virtualHalSimConfigSourceCoverage: createVirtualHalSimConfigSourceCoverageReport(),
virtualHalSimConfigPromotionCandidates: releaseReadinessPromotionCandidates,
virtualHalSimConfigMacroLoadFixtures: releaseReadinessMacroLoadFixtures,
virtualHalMotionControllerMatrix: releaseReadinessMotionControllerMatrix,
}));
const browserDiagnosticsVirtualHalState = createVirtualHalState();
@@ -1379,29 +1456,24 @@ const browserDiagnosticsArtifact = {
virtualHalSimulationReplacement: createVirtualHalSimulationReplacementReport(browserDiagnosticsVirtualHalState),
virtualHalSourceCompliance: createVirtualHalSourceComplianceReport({ halState: browserDiagnosticsVirtualHalState }),
virtualHalSimConfigSourceCoverage: createVirtualHalSimConfigSourceCoverageReport(),
virtualHalSimConfigPromotionCandidates: createVirtualHalSimConfigPromotionCandidateReport({
manifestEntries: [
...VIRTUAL_HAL_MOTION_MATRIX_MANIFEST_ENTRIES,
"linuxcnc/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini",
"linuxcnc/configs/sim/qtdragon/qtdragon_xyz45/on_abort.ngc",
"linuxcnc/configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/qtdragon_hd_z_compensation.ini",
"linuxcnc/configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/on_abort.ngc",
"linuxcnc/configs/sim/axis/vismach/puma/puma_seam_weld.ngc",
"linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini",
"linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc",
],
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",
],
}),
virtualHalSimConfigPromotionCandidates: releaseReadinessPromotionCandidates,
virtualHalPromotionCandidateSummary: {
apiName: "real-browser-simulation-promotion-candidate-summary",
summaryVersion: 1,
phase: "ready",
ready: true,
candidateCount: 8,
readyCandidateCount: 8,
familyCount: 3,
sourceFileCount: 17,
preferredCandidateId: "qtdragon-multi-joint-on-abort",
preferredIniPath: "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini",
preferredGcodePath: "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc",
blockedCandidateIds: [],
explicitBrowserDiagnosticsCount: 8,
inventoryBaseline: "executed=28 passed=28 skipped=131 unexpected_fail=0",
},
virtualHalSimConfigMacroLoadFixtures: releaseReadinessMacroLoadFixtures,
virtualHalCommandScriptFixtures: createVirtualHalCommandScriptFixtureReport({ halState: browserDiagnosticsVirtualHalState }),
virtualHalMotionControllerMatrix: releaseReadinessMotionControllerMatrix,
};
@@ -1725,7 +1797,7 @@ const releaseArtifactMountResult = mountIniPanelShellWorkflowOverviewReleaseRead
rowsNode: releaseArtifactRowsNode,
});
assert.equal(releaseArtifactRenderResult.rendered, true);
assert.equal(releaseArtifactRenderResult.rowCount, 11);
assert.equal(releaseArtifactRenderResult.rowCount, 17);
assert.equal(releaseArtifactRenderResult.dataset.handoffScope, "workflow-overview-release-readiness-artifact");
assert.equal(
releaseArtifactRenderResult.rowIds.includes("gate-execution-manifest"),
@@ -1735,6 +1807,10 @@ assert.equal(
releaseArtifactRenderResult.rowIds.includes("gate-execution-summary"),
true,
);
assert.equal(
releaseArtifactRenderResult.rowIds.includes("virtual-hal-promotion-families"),
true,
);
assert.equal(
releaseArtifactRenderResult.rowIds.includes("gate-action-plan"),
true,
@@ -1752,7 +1828,7 @@ assert.equal(
true,
);
assert.equal(releaseArtifactMountResult.ready, true);
assert.equal(releaseArtifactMountResult.renderResult.rowCount, 11);
assert.equal(releaseArtifactMountResult.renderResult.rowCount, 17);
assert.deepEqual(
validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson("{").missing,
["artifact-json"],
@@ -1811,11 +1887,18 @@ assert.equal(
);
assert.equal(releaseArtifactUrlWorkflow.renderState.statusLine, "Ready: No blocking reasons");
assert.equal(releaseArtifactUrlWorkflow.mountResult.ready, true);
assert.equal(releaseArtifactUrlWorkflow.mountResult.renderResult.rowCount, 11);
assert.equal(releaseArtifactUrlWorkflow.mountResult.renderResult.rowCount, 17);
const releaseArtifactUrlWorkflowSummary =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(
releaseArtifactUrlWorkflow,
);
const expectedPromotionFamilySummary =
"qtdragon-on-abort: 6/6 ready; vismach-remap-sims: 1/1 ready; rose-engine-rcone-demo: 1/1 ready";
const expectedPromotionFamilyRows = [
["virtual-hal-promotion-family-qtdragon-on-abort", "6/6 ready; sources=12; diagnostics=ready"],
["virtual-hal-promotion-family-vismach-remap-sims", "1/1 ready; sources=3; diagnostics=ready"],
["virtual-hal-promotion-family-rose-engine-rcone-demo", "1/1 ready; sources=2; diagnostics=ready"],
];
assert.equal(
releaseArtifactUrlWorkflowSummary.statusLine,
"Ready: Artifact URL workflow complete",
@@ -1836,6 +1919,583 @@ assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "browser-diagnostics")?.value,
"ready",
);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-summary")?.value,
"ready",
);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate")?.value,
"qtdragon-multi-joint-on-abort",
);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-ini")?.value,
"linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini",
);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-gcode")?.value,
"linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc",
);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-count")?.value,
"8/8 ready",
);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-candidate-baseline")?.value,
"executed=28 passed=28 skipped=131 unexpected_fail=0",
);
const promotionCandidateDrilldownViewModel =
createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownViewModel(
releaseArtifactUrlWorkflowSummary,
{ diagnosticsArtifact: releaseArtifactUrlWorkflow.diagnosticsArtifact },
);
const promotionCandidateDrilldownRenderState =
createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownRenderState(
promotionCandidateDrilldownViewModel,
);
assert.equal(promotionCandidateDrilldownViewModel.ready, true);
assert.equal(
promotionCandidateDrilldownViewModel.statusLine,
"Ready: qtdragon-multi-joint-on-abort source-derived browser evidence ready",
);
assert.equal(promotionCandidateDrilldownViewModel.candidateId, "qtdragon-multi-joint-on-abort");
assert.equal(promotionCandidateDrilldownViewModel.blockedFamilyExcluded, true);
assert.equal(promotionCandidateDrilldownViewModel.nodeInventoryReady, true);
assert.equal(promotionCandidateDrilldownViewModel.browserEvidenceReady, true);
assert.equal(promotionCandidateDrilldownViewModel.virtualHalReportsReady, true);
assert.deepEqual(promotionCandidateDrilldownViewModel.requiredReports, [
"source-compliance",
"sim-config-source-coverage",
"command-script-fixtures",
"manifest-backed-motion-matrix",
]);
assert.equal(
promotionCandidateDrilldownViewModel.rows.find(({ id }) => id === "ini")?.value,
"linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini",
);
assert.equal(
promotionCandidateDrilldownViewModel.rows.find(({ id }) => id === "gcode")?.value,
"linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc",
);
assert.equal(
promotionCandidateDrilldownViewModel.rows.find(({ id }) => id === "blocked-family-exclusion")?.value,
"passed",
);
assert.equal(promotionCandidateDrilldownViewModel.sourceFileCount, 2);
assert.deepEqual(
promotionCandidateDrilldownViewModel.sourceRows.map(({ value, sourceKind, manifestBacked }) => [
value,
sourceKind,
manifestBacked,
]),
[
["linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini", "ini", true],
["linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc", "gcode", true],
],
);
assert.equal(promotionCandidateDrilldownRenderState.ready, true);
assert.equal(promotionCandidateDrilldownRenderState.rowCount, 11);
assert.equal(promotionCandidateDrilldownRenderState.sourceFileCount, 2);
assert.equal(
createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomContract().selectors.mount,
"[data-workflow-overview-promotion-candidate-drilldown]",
);
assert.equal(createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomReadiness().ready, false);
const promotionCandidateDrilldownMountNode = mountDocument.createElement("section");
promotionCandidateDrilldownMountNode.dataset.workflowOverviewPromotionCandidateDrilldown = "";
const promotionCandidateDrilldownStatusNode = mountDocument.createElement("p");
promotionCandidateDrilldownStatusNode.dataset.workflowOverviewPromotionCandidateDrilldownStatus = "";
const promotionCandidateDrilldownRowsNode = {
children: [],
dataset: {},
append(...nodes) {
this.children.push(...nodes);
},
replaceChildren(...nodes) {
this.children = [...nodes];
},
};
promotionCandidateDrilldownRowsNode.dataset.workflowOverviewPromotionCandidateDrilldownRows = "";
const promotionCandidateDrilldownRenderResult =
renderIniPanelShellWorkflowOverviewPromotionCandidateDrilldownState(
promotionCandidateDrilldownRenderState,
{
documentRef: mountDocument,
mountNode: promotionCandidateDrilldownMountNode,
statusNode: promotionCandidateDrilldownStatusNode,
rowsNode: promotionCandidateDrilldownRowsNode,
},
);
const promotionCandidateDrilldownMountResult =
mountIniPanelShellWorkflowOverviewPromotionCandidateDrilldownState({
renderState: promotionCandidateDrilldownRenderState,
documentRef: mountDocument,
mountNode: promotionCandidateDrilldownMountNode,
statusNode: promotionCandidateDrilldownStatusNode,
rowsNode: promotionCandidateDrilldownRowsNode,
});
assert.equal(promotionCandidateDrilldownRenderResult.rendered, true);
assert.equal(promotionCandidateDrilldownRenderResult.rowCount, 11);
assert.deepEqual(promotionCandidateDrilldownRenderResult.dataset, {
handoffPhase: "ready",
handoffReady: "true",
handoffScope: "workflow-overview-promotion-candidate-drilldown",
candidateId: "qtdragon-multi-joint-on-abort",
});
assert.equal(promotionCandidateDrilldownRowsNode.children.some((node) =>
node.dataset?.workflowOverviewPromotionCandidateDrilldownValue === "blocked-family-exclusion" &&
node.textContent === "passed"
), true);
assert.equal(promotionCandidateDrilldownRowsNode.children.some((node) =>
node.dataset?.workflowOverviewPromotionCandidateDrilldownSourceKind === "gcode" &&
node.dataset?.workflowOverviewPromotionCandidateDrilldownManifestBacked === "true" &&
node.textContent === "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc"
), true);
assert.equal(promotionCandidateDrilldownMountResult.ready, true);
assert.equal(promotionCandidateDrilldownMountResult.renderResult.sourceFileCount, 2);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "virtual-hal-promotion-families")?.value,
expectedPromotionFamilySummary,
);
assert.deepEqual(
releaseArtifactUrlWorkflowSummary.rows
.filter(({ id }) => id.startsWith("virtual-hal-promotion-family-"))
.map(({ id, value }) => [id, value]),
expectedPromotionFamilyRows,
);
const promotionFamilyRowsRenderState =
createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState(
releaseArtifactUrlWorkflowSummary,
);
const promotionFamilySourceFilterViewModel =
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(
promotionFamilyRowsRenderState,
);
const promotionFamilyRemapSourceFilterViewModel =
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(
promotionFamilyRowsRenderState,
{ sourceKind: "remap-subroutine" },
);
const promotionFamilyQtDragonGcodeFilterViewModel =
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(
promotionFamilyRowsRenderState,
{
familyId: "virtual-hal-promotion-family-qtdragon-on-abort",
sourceKind: "gcode",
},
);
assert.equal(promotionFamilyRowsRenderState.ready, true);
assert.equal(promotionFamilyRowsRenderState.statusLine, "Ready: 3 promotion families ready");
assert.equal(promotionFamilyRowsRenderState.rows.length, 3);
assert.equal(promotionFamilyRowsRenderState.sourceFileCount, 17);
assert.equal(promotionFamilyRowsRenderState.sourceRows.length, 17);
assert.equal(
promotionFamilyRowsRenderState.rows.find(({ id }) => id === "virtual-hal-promotion-family-qtdragon-on-abort")
?.sourceKindSummary,
"ini=6 gcode=6",
);
assert.deepEqual(
promotionFamilyRowsRenderState.rows.find(({ id }) => id === "virtual-hal-promotion-family-vismach-remap-sims")
?.sourceKindCounts,
{ ini: 1, gcode: 1, "remap-subroutine": 1 },
);
assert.equal(
promotionFamilyRowsRenderState.rows.find(({ id }) => id === "virtual-hal-promotion-family-rose-engine-rcone-demo")
?.sourceKindSummary,
"ini=1 gcode=1",
);
assert.equal(promotionFamilySourceFilterViewModel.ready, true);
assert.equal(promotionFamilySourceFilterViewModel.statusLine, "Ready: 17/17 source files selected");
assert.equal(promotionFamilySourceFilterViewModel.filteredSourceFileCount, 17);
assert.equal(promotionFamilySourceFilterViewModel.totalSourceFileCount, 17);
assert.deepEqual(
promotionFamilySourceFilterViewModel.familyFilters.map(({ id, count, selected }) => [id, count, selected]),
[
["all", 17, true],
["virtual-hal-promotion-family-qtdragon-on-abort", 12, false],
["virtual-hal-promotion-family-vismach-remap-sims", 3, false],
["virtual-hal-promotion-family-rose-engine-rcone-demo", 2, false],
],
);
assert.deepEqual(
promotionFamilySourceFilterViewModel.sourceKindFilters.map(({ id, count, selected }) => [id, count, selected]),
[
["all", 17, true],
["ini", 8, false],
["gcode", 8, false],
["remap-subroutine", 1, false],
],
);
assert.equal(promotionFamilyRemapSourceFilterViewModel.selectedSourceKind, "remap-subroutine");
assert.equal(promotionFamilyRemapSourceFilterViewModel.statusLine, "Ready: 1/17 source files selected");
assert.equal(promotionFamilyRemapSourceFilterViewModel.familyRows.length, 1);
assert.equal(
promotionFamilyRemapSourceFilterViewModel.familyRows[0]?.id,
"virtual-hal-promotion-family-vismach-remap-sims",
);
assert.equal(
promotionFamilyRemapSourceFilterViewModel.sourceRows[0]?.value,
"linuxcnc/configs/sim/axis/vismach/puma/remap_subs/428remap.ngc",
);
assert.equal(promotionFamilyQtDragonGcodeFilterViewModel.selectedFamilyId, "virtual-hal-promotion-family-qtdragon-on-abort");
assert.equal(promotionFamilyQtDragonGcodeFilterViewModel.selectedSourceKind, "gcode");
assert.equal(promotionFamilyQtDragonGcodeFilterViewModel.statusLine, "Ready: 6/17 source files selected");
assert.equal(promotionFamilyQtDragonGcodeFilterViewModel.scopedSourceFileCount, 12);
assert.equal(promotionFamilyQtDragonGcodeFilterViewModel.filteredSourceFileCount, 6);
assert.equal(promotionFamilyQtDragonGcodeFilterViewModel.familyRows.length, 1);
assert.equal(
promotionFamilyQtDragonGcodeFilterViewModel.familyRows[0]?.sourceKindSummary,
"gcode=6",
);
assert.deepEqual(
promotionFamilyQtDragonGcodeFilterViewModel.sourceKindFilters.map(({ id, count, selected }) => [id, count, selected]),
[
["all", 12, false],
["ini", 6, false],
["gcode", 6, true],
],
);
assert.equal(
promotionFamilyQtDragonGcodeFilterViewModel.sourceRows.every(({ familyId, sourceKind }) =>
familyId === "virtual-hal-promotion-family-qtdragon-on-abort" &&
sourceKind === "gcode"
),
true,
);
assert.equal(
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract().selectors.mount,
"[data-workflow-overview-promotion-family-source-filter]",
);
assert.equal(createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomReadiness().ready, false);
const promotionFamilySourceFilterMountNode = mountDocument.createElement("section");
promotionFamilySourceFilterMountNode.dataset.workflowOverviewPromotionFamilySourceFilter = "";
const promotionFamilySourceFilterStatusNode = mountDocument.createElement("p");
promotionFamilySourceFilterStatusNode.dataset.workflowOverviewPromotionFamilySourceFilterStatus = "";
const promotionFamilySourceFilterControlsNode = {
...mountDocument.createElement("div"),
children: [],
replaceChildren() {
this.children = [];
},
append(...nodes) {
this.children.push(...nodes);
},
};
promotionFamilySourceFilterControlsNode.dataset.workflowOverviewPromotionFamilySourceFilterControls = "";
const promotionFamilySourceFilterRowsNode = {
...mountDocument.createElement("dl"),
children: [],
replaceChildren() {
this.children = [];
},
append(...nodes) {
this.children.push(...nodes);
},
};
promotionFamilySourceFilterRowsNode.dataset.workflowOverviewPromotionFamilySourceFilterRows = "";
const promotionFamilySourceFilterRenderResult =
renderIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState(
promotionFamilyQtDragonGcodeFilterViewModel,
{
documentRef: mountDocument,
mountNode: promotionFamilySourceFilterMountNode,
statusNode: promotionFamilySourceFilterStatusNode,
controlsNode: promotionFamilySourceFilterControlsNode,
rowsNode: promotionFamilySourceFilterRowsNode,
},
);
const promotionFamilySourceFilterMountResult =
mountIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState({
viewModel: promotionFamilyQtDragonGcodeFilterViewModel,
documentRef: mountDocument,
mountNode: promotionFamilySourceFilterMountNode,
statusNode: promotionFamilySourceFilterStatusNode,
controlsNode: promotionFamilySourceFilterControlsNode,
rowsNode: promotionFamilySourceFilterRowsNode,
});
assert.equal(promotionFamilySourceFilterRenderResult.rendered, true);
assert.equal(promotionFamilySourceFilterRenderResult.statusLine, "Ready: 6/17 source files selected");
assert.equal(promotionFamilySourceFilterRenderResult.controlCount, 2);
assert.equal(promotionFamilySourceFilterRenderResult.filterRowCount, 7);
assert.equal(promotionFamilySourceFilterRenderResult.sourceFileCount, 6);
assert.equal(promotionFamilySourceFilterRenderResult.rowCount, 13);
assert.deepEqual(promotionFamilySourceFilterRenderResult.dataset, {
handoffPhase: "ready",
handoffReady: "true",
handoffScope: "workflow-overview-promotion-family-source-filter",
selectedFamilyId: "virtual-hal-promotion-family-qtdragon-on-abort",
selectedSourceKind: "gcode",
});
assert.equal(promotionFamilySourceFilterControlsNode.children.length, 4);
assert.equal(
promotionFamilySourceFilterControlsNode.children.some((node) =>
node.dataset?.workflowOverviewPromotionFamilySourceFilterControl === "family" &&
node.dataset?.workflowOverviewPromotionFamilySourceFilterControlValue ===
"virtual-hal-promotion-family-qtdragon-on-abort" &&
node.textContent === "Family"
),
true,
);
assert.equal(
promotionFamilySourceFilterControlsNode.children.some((node) =>
node.dataset?.workflowOverviewPromotionFamilySourceFilterSelect === "source-kind" &&
node.dataset?.workflowOverviewPromotionFamilySourceFilterValue === "gcode" &&
node.value === "gcode" &&
node.children.some((option) =>
option.value === "gcode" &&
option.selected === true &&
option.dataset?.workflowOverviewPromotionFamilySourceFilterCount === "6"
)
),
true,
);
assert.equal(
promotionFamilySourceFilterRowsNode.children.some((node) =>
node.dataset?.workflowOverviewPromotionFamilySourceFilterValue ===
"virtual-hal-promotion-family-qtdragon-on-abort" &&
node.dataset?.workflowOverviewPromotionFamilySourceFilterType === "family-filter" &&
node.dataset?.workflowOverviewPromotionFamilySourceFilterSelected === "true" &&
node.textContent === "virtual-hal-promotion-family-qtdragon-on-abort: 12 selected"
),
true,
);
assert.equal(
promotionFamilySourceFilterRowsNode.children.some((node) =>
node.dataset?.workflowOverviewPromotionFamilySourceFilterValue === "gcode" &&
node.dataset?.workflowOverviewPromotionFamilySourceFilterType === "source-kind-filter" &&
node.dataset?.workflowOverviewPromotionFamilySourceFilterSelected === "true" &&
node.textContent === "gcode: 6 selected"
),
true,
);
assert.equal(
promotionFamilySourceFilterRowsNode.children.some((node) =>
node.dataset?.workflowOverviewPromotionFamilySourceFilterType === "source-row" &&
node.dataset?.workflowOverviewPromotionFamilySourceFilterFamily ===
"virtual-hal-promotion-family-qtdragon-on-abort" &&
node.dataset?.workflowOverviewPromotionFamilySourceFilterSourceKind === "gcode" &&
node.textContent === "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc"
),
true,
);
assert.equal(promotionFamilySourceFilterMountResult.ready, true);
assert.equal(promotionFamilySourceFilterMountResult.renderResult.rowCount, 13);
const promotionFamilySourceFilterSelectionActionPlan =
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionActionPlan(
promotionFamilyRowsRenderState,
{
familyId: "virtual-hal-promotion-family-rose-engine-rcone-demo",
sourceKind: "all",
previousViewModel: promotionFamilyQtDragonGcodeFilterViewModel,
},
);
assert.equal(promotionFamilySourceFilterSelectionActionPlan.ready, true);
assert.equal(promotionFamilySourceFilterSelectionActionPlan.changed, true);
assert.equal(
promotionFamilySourceFilterSelectionActionPlan.statusLine,
"Ready: source filter changed to virtual-hal-promotion-family-rose-engine-rcone-demo / all",
);
assert.equal(
promotionFamilySourceFilterSelectionActionPlan.nextViewModel.statusLine,
"Ready: 2/17 source files selected",
);
assert.equal(promotionFamilySourceFilterSelectionActionPlan.nextViewModel.filteredSourceFileCount, 2);
assert.equal(promotionFamilySourceFilterSelectionActionPlan.nextViewModel.scopedSourceFileCount, 2);
const sourceFilterFamilySelect = promotionFamilySourceFilterControlsNode.children.find((node) =>
node.dataset?.workflowOverviewPromotionFamilySourceFilterSelect === "family"
);
const sourceFilterKindSelect = promotionFamilySourceFilterControlsNode.children.find((node) =>
node.dataset?.workflowOverviewPromotionFamilySourceFilterSelect === "source-kind"
);
sourceFilterFamilySelect.value = "virtual-hal-promotion-family-rose-engine-rcone-demo";
sourceFilterKindSelect.value = "all";
const promotionFamilySourceFilterSelectionChange =
handleIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionChange({
renderState: promotionFamilyRowsRenderState,
viewModel: promotionFamilyQtDragonGcodeFilterViewModel,
documentRef: mountDocument,
mountNode: promotionFamilySourceFilterMountNode,
statusNode: promotionFamilySourceFilterStatusNode,
controlsNode: promotionFamilySourceFilterControlsNode,
rowsNode: promotionFamilySourceFilterRowsNode,
render: true,
});
assert.equal(promotionFamilySourceFilterSelectionChange.ready, true);
assert.equal(
promotionFamilySourceFilterSelectionChange.selectedFamilyId,
"virtual-hal-promotion-family-rose-engine-rcone-demo",
);
assert.equal(promotionFamilySourceFilterSelectionChange.selectedSourceKind, "all");
assert.equal(promotionFamilySourceFilterSelectionChange.actionPlan.changed, true);
assert.equal(promotionFamilySourceFilterSelectionChange.viewModel.filteredSourceFileCount, 2);
assert.equal(promotionFamilySourceFilterSelectionChange.renderResult.sourceFileCount, 2);
assert.equal(promotionFamilySourceFilterSelectionChange.renderResult.dataset.selectedSourceKind, "all");
assert.equal(
promotionFamilySourceFilterRowsNode.children.some((node) =>
node.dataset?.workflowOverviewPromotionFamilySourceFilterType === "source-row" &&
node.dataset?.workflowOverviewPromotionFamilySourceFilterFamily ===
"virtual-hal-promotion-family-rose-engine-rcone-demo" &&
node.textContent === "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc"
),
true,
);
renderIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState(
promotionFamilyQtDragonGcodeFilterViewModel,
{
documentRef: mountDocument,
mountNode: promotionFamilySourceFilterMountNode,
statusNode: promotionFamilySourceFilterStatusNode,
controlsNode: promotionFamilySourceFilterControlsNode,
rowsNode: promotionFamilySourceFilterRowsNode,
},
);
let promotionFamilySourceFilterBindingLastChange = null;
const promotionFamilySourceFilterSelectionBinding =
bindIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionControls({
renderState: promotionFamilyRowsRenderState,
viewModel: promotionFamilyQtDragonGcodeFilterViewModel,
documentRef: mountDocument,
mountNode: promotionFamilySourceFilterMountNode,
statusNode: promotionFamilySourceFilterStatusNode,
controlsNode: promotionFamilySourceFilterControlsNode,
rowsNode: promotionFamilySourceFilterRowsNode,
render: true,
onChange: (changeResult) => {
promotionFamilySourceFilterBindingLastChange = changeResult;
},
});
assert.equal(promotionFamilySourceFilterSelectionBinding.ready, true);
assert.equal(promotionFamilySourceFilterSelectionBinding.boundControlCount, 2);
assert.deepEqual(promotionFamilySourceFilterSelectionBinding.controlIds, ["family", "source-kind"]);
const boundSourceFilterFamilySelect = promotionFamilySourceFilterControlsNode.children.find((node) =>
node.dataset?.workflowOverviewPromotionFamilySourceFilterSelect === "family"
);
const boundSourceFilterKindSelect = promotionFamilySourceFilterControlsNode.children.find((node) =>
node.dataset?.workflowOverviewPromotionFamilySourceFilterSelect === "source-kind"
);
boundSourceFilterFamilySelect.value = "virtual-hal-promotion-family-rose-engine-rcone-demo";
boundSourceFilterKindSelect.value = "all";
const promotionFamilySourceFilterBoundChange = boundSourceFilterFamilySelect.dispatchEvent("change");
assert.equal(promotionFamilySourceFilterBoundChange.ready, true);
assert.equal(
promotionFamilySourceFilterBoundChange.selectedFamilyId,
"virtual-hal-promotion-family-rose-engine-rcone-demo",
);
assert.equal(promotionFamilySourceFilterBoundChange.renderResult.sourceFileCount, 2);
assert.equal(
promotionFamilySourceFilterBindingLastChange.selectedFamilyId,
"virtual-hal-promotion-family-rose-engine-rcone-demo",
);
assert.equal(promotionFamilySourceFilterSelectionBinding.lastChange.selectedSourceKind, "all");
assert.deepEqual(promotionFamilySourceFilterSelectionBinding.unbind(), { unbound: 2 });
assert.equal(
promotionFamilyRowsRenderState.sourceRows.some(({ value }) =>
value === "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini"
),
true,
);
assert.equal(
promotionFamilyRowsRenderState.sourceRows.some(({ sourceKind, manifestBacked, status, value }) =>
sourceKind === "ini" &&
manifestBacked === true &&
status === "manifest-backed" &&
value === "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini"
),
true,
);
assert.equal(
promotionFamilyRowsRenderState.sourceRows.some(({ sourceKind, manifestBacked, status, value }) =>
sourceKind === "gcode" &&
manifestBacked === true &&
status === "manifest-backed" &&
value === "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc"
),
true,
);
assert.equal(
promotionFamilyRowsRenderState.sourceRows.some(({ value }) =>
value === "linuxcnc/configs/sim/axis/vismach/puma/remap_subs/428remap.ngc"
),
true,
);
assert.equal(
promotionFamilyRowsRenderState.sourceRows.some(({ sourceKind, manifestBacked, status, value }) =>
sourceKind === "remap-subroutine" &&
manifestBacked === true &&
status === "manifest-backed" &&
value === "linuxcnc/configs/sim/axis/vismach/puma/remap_subs/428remap.ngc"
),
true,
);
assert.equal(
promotionFamilyRowsRenderState.sourceRows.some(({ value }) =>
value === "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc"
),
true,
);
assert.equal(
createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomContract().selectors.mount,
"[data-workflow-overview-promotion-family-rows]",
);
assert.equal(createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomReadiness().ready, false);
const promotionFamilyRowsMountNode = mountDocument.createElement("section");
promotionFamilyRowsMountNode.dataset.workflowOverviewPromotionFamilyRows = "";
const promotionFamilyRowsStatusNode = mountDocument.createElement("p");
promotionFamilyRowsStatusNode.dataset.workflowOverviewPromotionFamilyRowsStatus = "";
const promotionFamilyRowsNode = {
...mountDocument.createElement("dl"),
children: [],
replaceChildren() {
this.children = [];
},
append(...nodes) {
this.children.push(...nodes);
},
};
promotionFamilyRowsNode.dataset.workflowOverviewPromotionFamilyRowList = "";
const promotionFamilyRowsRenderResult =
renderIniPanelShellWorkflowOverviewPromotionFamilyRowsState(
promotionFamilyRowsRenderState,
{
documentRef: mountDocument,
mountNode: promotionFamilyRowsMountNode,
statusNode: promotionFamilyRowsStatusNode,
rowsNode: promotionFamilyRowsNode,
},
);
const promotionFamilyRowsMountResult =
mountIniPanelShellWorkflowOverviewPromotionFamilyRowsState({
renderState: promotionFamilyRowsRenderState,
documentRef: mountDocument,
mountNode: promotionFamilyRowsMountNode,
statusNode: promotionFamilyRowsStatusNode,
rowsNode: promotionFamilyRowsNode,
});
assert.equal(promotionFamilyRowsRenderResult.rendered, true);
assert.equal(promotionFamilyRowsRenderResult.rowCount, 20);
assert.deepEqual(promotionFamilyRowsRenderResult.rowIds, expectedPromotionFamilyRows.map(([id]) => id));
assert.equal(promotionFamilyRowsRenderResult.sourceFileCount, 17);
assert.equal(
promotionFamilyRowsNode.children.some((node) =>
node.dataset?.workflowOverviewPromotionFamilyValue ===
"virtual-hal-promotion-family-qtdragon-on-abort" &&
node.dataset?.workflowOverviewPromotionFamilySourceKindCounts === "ini=6 gcode=6" &&
node.textContent === "6/6 ready; sources=12; diagnostics=ready; ini=6 gcode=6"
),
true,
);
assert.equal(
promotionFamilyRowsNode.children.some((node) =>
node.dataset?.workflowOverviewPromotionFamilyValue ===
"virtual-hal-promotion-family-qtdragon-on-abort-source-1" &&
node.dataset?.workflowOverviewPromotionFamilySourceKind === "ini" &&
node.dataset?.workflowOverviewPromotionFamilyManifestBacked === "true" &&
node.dataset?.workflowOverviewPromotionFamilySourceStatus === "manifest-backed" &&
node.textContent === "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini"
),
true,
);
assert.equal(promotionFamilyRowsMountResult.ready, true);
assert.equal(promotionFamilyRowsMountResult.renderResult.rowCount, 20);
assert.equal(
releaseArtifactUrlWorkflowSummary.rows.find(({ id }) => id === "saved-session-diagnostics")?.value,
"ready",
@@ -1905,7 +2565,7 @@ const releaseArtifactUrlWorkflowMountResult =
rowsNode: releaseArtifactUrlWorkflowRowsNode,
});
assert.equal(releaseArtifactUrlWorkflowRenderResult.rendered, true);
assert.equal(releaseArtifactUrlWorkflowRenderResult.rowCount, 12);
assert.equal(releaseArtifactUrlWorkflowRenderResult.rowCount, 22);
assert.equal(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("browser-diagnostics"),
true,
@@ -1914,12 +2574,16 @@ assert.equal(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("saved-session-diagnostics"),
true,
);
assert.equal(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("virtual-hal-promotion-families"),
true,
);
assert.equal(
releaseArtifactUrlWorkflowRenderResult.rowIds.includes("mount-result"),
true,
);
assert.equal(releaseArtifactUrlWorkflowMountResult.ready, true);
assert.equal(releaseArtifactUrlWorkflowMountResult.renderResult.rowCount, 12);
assert.equal(releaseArtifactUrlWorkflowMountResult.renderResult.rowCount, 22);
const releaseArtifactUrlWorkflowMissingDom = await loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl({
artifactUrl: "/project-release-readiness.json",
fetchRef: async () => ({
@@ -1978,6 +2642,39 @@ const workflowOverviewApi = {
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel: () => releaseArtifactUrlWorkflowSummary,
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan: () => releaseArtifactUrlWorkflow.actionPlan,
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState: () => releaseArtifactUrlWorkflowRenderState,
getWorkflowOverviewPromotionFamilyRowsRenderState: () => promotionFamilyRowsRenderState,
getWorkflowOverviewPromotionFamilySourceFilterViewModel: () => promotionFamilySourceFilterViewModel,
getWorkflowOverviewPromotionFamilySourceFilterDomContract:
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract,
getWorkflowOverviewPromotionFamilySourceFilterDomReadiness: () => (
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomReadiness({
documentRef: mountDocument,
mountNode: promotionFamilySourceFilterMountNode,
statusNode: promotionFamilySourceFilterStatusNode,
controlsNode: promotionFamilySourceFilterControlsNode,
rowsNode: promotionFamilySourceFilterRowsNode,
})
),
getWorkflowOverviewPromotionFamilySourceFilterSelectionActionPlan: () =>
promotionFamilySourceFilterSelectionActionPlan,
handleWorkflowOverviewPromotionFamilySourceFilterSelectionChange: () =>
promotionFamilySourceFilterSelectionChange,
bindWorkflowOverviewPromotionFamilySourceFilterSelectionControls: () =>
promotionFamilySourceFilterSelectionBinding,
renderWorkflowOverviewPromotionFamilySourceFilterState: () => promotionFamilySourceFilterRenderResult,
mountWorkflowOverviewPromotionFamilySourceFilterState: () => promotionFamilySourceFilterMountResult,
getWorkflowOverviewPromotionFamilyRowsDomContract:
createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomContract,
getWorkflowOverviewPromotionFamilyRowsDomReadiness: () => (
createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomReadiness({
documentRef: mountDocument,
mountNode: promotionFamilyRowsMountNode,
statusNode: promotionFamilyRowsStatusNode,
rowsNode: promotionFamilyRowsNode,
})
),
renderWorkflowOverviewPromotionFamilyRowsState: () => promotionFamilyRowsRenderResult,
mountWorkflowOverviewPromotionFamilyRowsState: () => promotionFamilyRowsMountResult,
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness: () => (

View File

@@ -4,6 +4,7 @@ import { basename, dirname, posix, resolve } from "node:path";
import assert from "node:assert/strict";
import {
VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES,
analyzeIniRuntimeBoundaries,
createLinuxCncInterpSdk,
planSimConfigStaging,
@@ -100,6 +101,7 @@ const runtimeBoundaryNativeAlignmentSummaryPath = resolve(buildDir, "runtime-bou
const runtimeProbeGateAlignmentPath = resolve(buildDir, "runtime-probe-gate-alignment.tsv");
const nativeRuntimeProbeExecutionPlanPath = resolve(buildDir, "native-runtime-probe-execution-plan.tsv");
const nativeRuntimeProbePassEvidenceContractPath = resolve(buildDir, "native-runtime-probe-pass-evidence-contract.tsv");
const promotionCandidatesPath = resolve(buildDir, "promotion-candidates.tsv");
const blockedRuntimePromotionLockPath = resolve(buildDir, "blocked-runtime-promotion-lock.tsv");
const runtimeBoundaryPromotionReadinessPath = resolve(buildDir, "runtime-boundary-promotion-readiness.tsv");
const runtimeBoundaryPromotionBlockersPath = resolve(buildDir, "runtime-boundary-promotion-blockers.tsv");
@@ -155,6 +157,7 @@ const generatedSimConfigInventoryArtifactPaths = [
runtimeProbeGateAlignmentPath,
nativeRuntimeProbeExecutionPlanPath,
nativeRuntimeProbePassEvidenceContractPath,
promotionCandidatesPath,
blockedRuntimePromotionLockPath,
runtimeBoundaryPromotionReadinessPath,
runtimeBoundaryPromotionBlockersPath,
@@ -6087,7 +6090,7 @@ function verifyBoundaryPhaseCompletionSummaryRows(rows) {
const rowByCriterion = new Map(parsedRows.map((row) => [row.criterion, row]));
assert.equal(
rowByCriterion.get("wasm_inventory_artifact_documentation_coverage")?.count,
"54",
"55",
"WASM artifact documentation completion count must match generated artifact baseline",
);
assert.equal(
@@ -8609,7 +8612,7 @@ function verifyGeneratedArtifactDocumentationCoverage({
);
assert.equal(
artifactNames.length,
54,
55,
"generated sim-config inventory artifact list count drift",
);
assert.deepEqual(
@@ -8628,6 +8631,7 @@ function verifyGeneratedArtifactDocumentationCoverage({
"native-runtime-probe-summary.tsv",
"next-boundary-recommendations.tsv",
"next-boundary-worklist.tsv",
"promotion-candidates.tsv",
"python-remap-boundary-summary.tsv",
"python-remap-family-summary.tsv",
"python-remap-native-runtime-alignment.tsv",
@@ -8703,7 +8707,7 @@ function verifyGeneratedArtifactDocumentationCoverage({
"generated sim-config inventory artifacts must be listed in browser smoke",
);
assert.ok(
browserSmokeText.includes("wasmArtifactNames.length !== 54"),
browserSmokeText.includes("wasmArtifactNames.length !== 55"),
"browser smoke must keep generated WASM artifact fixed-count guard",
);
assert.ok(
@@ -11946,6 +11950,198 @@ function verifyHardBlockedInventorySkips(rows, pathMatrixByPath) {
}
}
function sourcePathToInventoryPath(sourcePath) {
const prefix = "linuxcnc/configs/sim/";
return sourcePath.startsWith(prefix) ? sourcePath.slice(prefix.length) : "";
}
function promotionCandidateRows({
summaryRows,
boundaryRows,
nextBoundaryRecords,
trackedMatrixByPath,
nativeByPath,
}) {
const summaryByPath = new Map(summaryRows.map((row) => {
const [
path,
inventoryStatus,
reason,
className,
nativeStatus,
nativeExpectedFailure,
] = row.split("\t");
return [path, {
path,
inventoryStatus,
reason,
className,
nativeStatus,
nativeExpectedFailure,
}];
}));
const boundaryByPath = new Map(boundaryRows.map((row) => [row.path, row]));
const nextBoundaryByBlocked = new Map(nextBoundaryRecords.map((row) => [row.blocked, row]));
const evidenceReadyRows = VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES.map((candidate) => {
const inventoryPath = sourcePathToInventoryPath(candidate.gcodePath);
const summary = summaryByPath.get(inventoryPath);
const matrix = trackedMatrixByPath.get(inventoryPath);
const native = nativeByPath.get(inventoryPath);
const boundary = boundaryByPath.get(inventoryPath);
const virtualHalEvidenceReady = candidate.currentNodeInventoryStatus === "PASS" &&
candidate.currentMatrixBrowserStatus === "explicit-browser-diagnostics" &&
candidate.targetBrowserEvidence === "explicit-browser-diagnostics" &&
candidate.blockedKind === "-" &&
summary?.inventoryStatus === "PASS";
return [
"evidence-ready",
candidate.id,
inventoryPath,
sourcePathToInventoryPath(candidate.iniPath),
summary?.inventoryStatus ?? "-",
summary?.reason ?? "-",
matrix?.layer4Node ?? "-",
matrix?.layer4Browser ?? "-",
summary?.className ?? native?.class ?? "-",
summary?.nativeStatus ?? native?.status ?? "-",
summary?.nativeExpectedFailure ?? native?.expected_failure ?? "-",
matrix?.blocked ?? candidate.blockedKind ?? "-",
candidate.dependencyClass,
flagValue(virtualHalEvidenceReady),
"0",
virtualHalEvidenceReady ? "browser_release_evidence_ready_inventory_baseline_unchanged" : "virtual_hal_evidence_incomplete",
"wasm-port/tests/sdk/node/verify_sdk_surface.sh && wasm-port/tests/sdk/node/verify_project_release_gate_manifest.sh",
].map(tsvValue).join("\t");
});
const inventoryReadyRows = [...summaryByPath.values()]
.filter((row) => row.className === "main" && row.inventoryStatus === "SKIP")
.sort((left, right) => left.path.localeCompare(right.path))
.map((row) => {
const boundary = boundaryByPath.get(row.path);
const matrix = trackedMatrixByPath.get(row.path);
const boundaryWork = nextBoundaryByBlocked.get(row.reason);
const promotionAllowed = row.reason === "-" &&
boundary?.recommended_blocked === "-" &&
row.nativeStatus === "PASS";
const blockReason = promotionAllowed
? "-"
: (boundaryWork?.next_action ?? `blocked_by_${row.reason}`);
const recommendedNextCommand = promotionAllowed
? "SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh"
: (boundaryWork?.required_native_proof ?? "no_direct_baseline_promotion_candidate");
return [
"inventory-ready",
row.path,
row.path,
boundary?.ini ?? "-",
row.inventoryStatus,
row.reason,
matrix?.layer4Node ?? "-",
matrix?.layer4Browser ?? "-",
row.className,
row.nativeStatus,
row.nativeExpectedFailure,
matrix?.blocked ?? row.reason,
boundary?.dependencies ?? "-",
"0",
flagValue(promotionAllowed),
blockReason,
recommendedNextCommand,
].map(tsvValue).join("\t");
});
return [...evidenceReadyRows, ...inventoryReadyRows];
}
function verifyPromotionCandidateRows(rows, summaryRows, boundaryRows) {
const expectedHeaders = [
"candidate_kind",
"candidate_id",
"path",
"ini",
"current_status",
"skip_kind",
"matrix_layer4_node",
"matrix_layer4_browser",
"class",
"native_status",
"native_expected_failure",
"blocked_kind",
"dependency_class",
"virtual_hal_evidence_ready",
"promotion_allowed",
"block_reason",
"recommended_next_command",
];
const parsedRows = parseTsv(
`${expectedHeaders.join("\t")}\n${rows.join("\n")}\n`,
expectedHeaders,
);
const expectedSkippedMain = summaryRows
.map((row) => {
const [path, inventoryStatus, reason, className] = row.split("\t");
return { path, inventoryStatus, reason, className };
})
.filter((row) => row.inventoryStatus === "SKIP" && row.className === "main")
.map((row) => row.path)
.sort();
const evidenceReadyPaths = VIRTUAL_HAL_SIM_CONFIG_PROMOTION_CANDIDATES
.map((candidate) => sourcePathToInventoryPath(candidate.gcodePath))
.sort();
const boundaryByPath = new Map(boundaryRows.map((row) => [row.path, row]));
const parsedEvidenceReady = parsedRows.filter((row) => row.candidate_kind === "evidence-ready");
const parsedInventoryReady = parsedRows.filter((row) => row.candidate_kind === "inventory-ready");
assert.deepEqual(
parsedEvidenceReady.map((row) => row.path).sort(),
evidenceReadyPaths,
"promotion-candidates must cover virtual HAL evidence-ready rows",
);
assert.deepEqual(
parsedInventoryReady.map((row) => row.path).sort(),
expectedSkippedMain,
"promotion-candidates must cover every skipped main inventory candidate row",
);
assert.equal(
parsedInventoryReady.filter((row) => row.promotion_allowed === "1").length,
0,
"current baseline has no direct skipped-main inventory promotion candidate",
);
for (const row of parsedEvidenceReady) {
assert.equal(row.current_status, "PASS", `${row.path}: evidence-ready row must be a current inventory PASS`);
assert.equal(row.skip_kind, "-", `${row.path}: evidence-ready row must not have a skip kind`);
assert.equal(row.blocked_kind, "-", `${row.path}: evidence-ready row must not be hard-blocked`);
assert.equal(row.virtual_hal_evidence_ready, "1", `${row.path}: evidence-ready row lacks virtual HAL evidence`);
assert.equal(row.promotion_allowed, "0", `${row.path}: evidence-ready row must not claim inventory promotion`);
assert.equal(row.matrix_layer4_node, "INV", `${row.path}: evidence-ready row should remain Node INV`);
assert.equal(row.matrix_layer4_browser, "-", `${row.path}: evidence-ready row should record explicit diagnostics outside matrix browser REP`);
assert.equal(row.block_reason, "browser_release_evidence_ready_inventory_baseline_unchanged");
assert.ok(
row.recommended_next_command.includes("verify_sdk_surface.sh"),
`${row.path}: evidence-ready row lacks virtual HAL gate command`,
);
}
for (const row of parsedInventoryReady) {
assert.equal(row.current_status, "SKIP", `${row.path}: promotion candidate status drift`);
assert.equal(row.class, "main", `${row.path}: promotion candidate must be main class`);
assert.equal(row.blocked_kind, row.skip_kind, `${row.path}: skipped inventory blocked kind drift`);
assert.equal(row.virtual_hal_evidence_ready, "0", `${row.path}: skipped inventory row must not claim virtual HAL evidence ready`);
assert.ok(
["L4-PYTHON-REMAP", "L4-TOOL-DB", "L4-USER-M-PROCESS", "UPSTREAM-DEMO"].includes(row.skip_kind),
`${row.path}: direct promotion candidate must remain hard-blocked or upstream-demo`,
);
const boundary = boundaryByPath.get(row.path);
assert.ok(boundary, `${row.path}: promotion candidate lacks boundary evidence`);
if (row.skip_kind.startsWith("L4-")) {
assert.notEqual(row.recommended_next_command, "-", `${row.path}: blocked row lacks next proof command`);
assert.notEqual(row.block_reason, "-", `${row.path}: blocked row lacks block reason`);
}
}
return parsedRows;
}
for (const record of nativeRecords) {
const skipReason = blockedKind(record, pathMatrixByPath);
if (skipReason) {
@@ -12425,6 +12621,44 @@ writeFileSync(
].join("\n")}\n`,
);
const promotionCandidateRowsGenerated = promotionCandidateRows({
summaryRows,
boundaryRows: boundarySummaryRecords,
nextBoundaryRecords,
trackedMatrixByPath,
nativeByPath: new Map(nativeRecords.map((record) => [record.path, record])),
});
verifyPromotionCandidateRows(
promotionCandidateRowsGenerated,
summaryRows,
boundarySummaryRecords,
);
writeFileSync(
promotionCandidatesPath,
`${[
[
"candidate_kind",
"candidate_id",
"path",
"ini",
"current_status",
"skip_kind",
"matrix_layer4_node",
"matrix_layer4_browser",
"class",
"native_status",
"native_expected_failure",
"blocked_kind",
"dependency_class",
"virtual_hal_evidence_ready",
"promotion_allowed",
"block_reason",
"recommended_next_command",
].join("\t"),
...promotionCandidateRowsGenerated,
].join("\n")}\n`,
);
writeFileSync(
boundarySummaryPath,
`${[