虚拟HAL完全满足Web数控仿真

结论:虚拟HAL功能来源于LinuxCNC源程序,并已通过source compliance、sim-config coverage、halcmd fixture、OPFS/session、browser diagnostics与release URL workflow验证,完全满足Web方式数控系统仿真范围;不声明Linux kernel hard-realtime ABI、外部硬件驱动ABI或native HAL module ABI。
This commit is contained in:
2026-06-17 22:03:26 +08:00
parent a4d449ad48
commit 3a6972437f
21 changed files with 2017 additions and 240 deletions

View File

@@ -88,6 +88,97 @@ const BLOCKED_RUNTIME_FAMILIES = [
const PROJECT_RELEASE_READINESS_ARTIFACT_API = "project-release-readiness-report";
const PROJECT_RELEASE_READINESS_ARTIFACT_VERSION = 1;
function isVirtualHalSimConfigSourceCoverageReady(report) {
const coverage = objectOrEmpty(report);
return coverage.apiName === "linuxcnc-wasm-virtual-hal-sim-config-source-coverage-report" &&
coverage.complete === true &&
coverage.webSimulationSatisfied === true &&
arrayOrEmpty(coverage.missingTargets).length === 0 &&
arrayOrEmpty(coverage.missingCapabilities).length === 0 &&
arrayOrEmpty(coverage.sourceFiles).includes("linuxcnc/configs/sim/axis/foam/axis_foam.ini") &&
arrayOrEmpty(coverage.sourceFiles).includes("linuxcnc/configs/sim/qtdragon/qtdragon_xyz/on_abort.ngc");
}
export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifact = {}) {
const artifactObject = objectOrEmpty(artifact);
const sourceCompliance = objectOrEmpty(artifactObject.virtualHalSourceCompliance);
const simConfigSourceCoverage = objectOrEmpty(artifactObject.virtualHalSimConfigSourceCoverage);
const commandScriptFixtures = objectOrEmpty(artifactObject.virtualHalCommandScriptFixtures);
const replacement = objectOrEmpty(artifactObject.virtualHalSimulationReplacement);
const virtualHal = objectOrEmpty(artifactObject.virtualHal);
const sourceComplianceReady = sourceCompliance.complete === true &&
sourceCompliance.webSimulationSatisfied === true &&
arrayOrEmpty(sourceCompliance.sourceFiles).includes("linuxcnc/src/hal/utils/halcmd_commands.cc");
const simConfigSourceCoverageReady = isVirtualHalSimConfigSourceCoverageReady(simConfigSourceCoverage);
const commandScriptFixturesReady = commandScriptFixtures.complete === true &&
commandScriptFixtures.webSimulationSatisfied === true &&
arrayOrEmpty(commandScriptFixtures.coveredActions).includes("loadusr") &&
arrayOrEmpty(commandScriptFixtures.coveredActions).includes("stop") &&
arrayOrEmpty(commandScriptFixtures.sourceFiles).includes("linuxcnc/src/hal/utils/halcmd_commands.cc");
const replacementReady = replacement.ready === true &&
replacement.replacesHostRuntimeForSimulation === true &&
objectOrEmpty(replacement.sourceCompliance).webSimulationSatisfied === true;
const virtualHalReady = virtualHal.source === "browser-virtual-hal";
const missing = [
...(artifactObject.apiName === "real-browser-simulation-diagnostics-artifact" ? [] : ["apiName"]),
...(virtualHalReady ? [] : ["virtualHal"]),
...(replacementReady ? [] : ["virtualHalSimulationReplacement"]),
...(sourceComplianceReady ? [] : ["virtualHalSourceCompliance"]),
...(simConfigSourceCoverageReady ? [] : ["virtualHalSimConfigSourceCoverage"]),
...(commandScriptFixturesReady ? [] : ["virtualHalCommandScriptFixtures"]),
];
return {
apiName: "project-release-browser-diagnostics-artifact-validation",
validationVersion: 1,
phase: missing.length === 0 ? "ready" : "blocked",
ready: missing.length === 0,
missing,
artifactApiName: artifactObject.apiName ?? null,
virtualHalReady,
replacementReady,
sourceComplianceReady,
simConfigSourceCoverageReady,
commandScriptFixturesReady,
sourceFiles: [...new Set([
...arrayOrEmpty(sourceCompliance.sourceFiles),
...arrayOrEmpty(simConfigSourceCoverage.sourceFiles),
...arrayOrEmpty(commandScriptFixtures.sourceFiles),
])],
rows: [
{
id: "artifact",
label: "Browser diagnostics artifact",
value: artifactObject.apiName ?? "missing",
},
{
id: "virtual-hal",
label: "Virtual HAL state",
value: virtualHalReady ? "ready" : "missing",
},
{
id: "source-compliance",
label: "Virtual HAL source compliance",
value: sourceComplianceReady ? "ready" : "missing",
},
{
id: "sim-config-source-coverage",
label: "Virtual HAL sim-config source coverage",
value: simConfigSourceCoverageReady ? "ready" : "missing",
},
{
id: "command-script-fixtures",
label: "Virtual HAL command script fixtures",
value: commandScriptFixturesReady ? "ready" : "missing",
},
{
id: "missing",
label: "Missing diagnostics evidence",
value: missing.length > 0 ? missing.join(", ") : "none",
},
],
};
}
function outputContains(observedOutputs, expectedOutput) {
return observedOutputs.some((output) => String(output).includes(expectedOutput));
}
@@ -470,6 +561,7 @@ export function createProjectBatchAcceptanceWorkflow({
capabilities = [],
gateResults = {},
observedOutputs = [],
virtualHalSimConfigSourceCoverage = null,
} = {}) {
const capabilityMatrix = createProjectBatchAcceptanceCapabilityMatrix({ capabilities });
const gateManifest = createProjectReleaseGateManifest();
@@ -480,10 +572,13 @@ export function createProjectBatchAcceptanceWorkflow({
});
const batchGatePassed = gateResultMatrix.rows
.find(({ id }) => id === "project-batch-acceptance")?.passed === true;
const ready = capabilityMatrix.ready && batchGatePassed;
const virtualHalSimConfigSourceCoverageReady = virtualHalSimConfigSourceCoverage === null ||
isVirtualHalSimConfigSourceCoverageReady(virtualHalSimConfigSourceCoverage);
const ready = capabilityMatrix.ready && batchGatePassed && virtualHalSimConfigSourceCoverageReady;
const missing = [
...capabilityMatrix.missing,
...(batchGatePassed ? [] : ["project-batch-acceptance"]),
...(virtualHalSimConfigSourceCoverageReady ? [] : ["virtual-hal-sim-config-source-coverage"]),
];
return {
@@ -498,6 +593,8 @@ export function createProjectBatchAcceptanceWorkflow({
capabilityMatrix,
capabilities: capabilityMatrix.capabilities,
rejectedCapabilities: capabilityMatrix.rejectedCapabilities,
virtualHalSimConfigSourceCoverage,
virtualHalSimConfigSourceCoverageReady,
gateResultMatrix,
missing,
rows: [
@@ -516,6 +613,13 @@ export function createProjectBatchAcceptanceWorkflow({
label: "Batch acceptance gate",
value: batchGatePassed ? "passed" : "unknown",
},
{
id: "virtual-hal-sim-config-source-coverage",
label: "Virtual HAL sim-config source coverage",
value: virtualHalSimConfigSourceCoverage === null
? "not required"
: (virtualHalSimConfigSourceCoverageReady ? "ready" : "missing"),
},
{
id: "missing",
label: "Missing acceptance evidence",
@@ -649,6 +753,15 @@ export function createProjectBatchAcceptanceChecklist({
detail: workflow?.gateResultMatrix?.rows
?.find?.(({ id }) => id === "project-batch-acceptance")?.status ?? "unknown",
},
{
id: "virtual-hal-sim-config-source-coverage",
label: "Virtual HAL sim-config source coverage",
status: workflow?.virtualHalSimConfigSourceCoverageReady !== false ? "pass" : "blocked",
passed: workflow?.virtualHalSimConfigSourceCoverageReady !== false,
detail: workflow?.virtualHalSimConfigSourceCoverage === null
? "not required"
: (workflow?.virtualHalSimConfigSourceCoverageReady === true ? "ready" : "missing"),
},
{
id: "next-action",
label: "Next acceptance action",
@@ -680,6 +793,7 @@ export function createProjectBatchAcceptanceReport({
capabilities = [],
gateResults = {},
observedOutputs = [],
virtualHalSimConfigSourceCoverage = null,
} = {}) {
const capabilityMatrix = createProjectBatchAcceptanceCapabilityMatrix({ capabilities });
const workflow = createProjectBatchAcceptanceWorkflow({
@@ -687,6 +801,7 @@ export function createProjectBatchAcceptanceReport({
capabilities,
gateResults,
observedOutputs,
virtualHalSimConfigSourceCoverage,
});
const summaryViewModel = createProjectBatchAcceptanceSummaryViewModel(workflow);
const actionPlan = createProjectBatchAcceptanceActionPlan(workflow);
@@ -701,6 +816,7 @@ export function createProjectBatchAcceptanceReport({
missing: [...workflow.missing],
capabilityMatrix,
workflow,
virtualHalSimConfigSourceCoverage,
summaryViewModel,
actionPlan,
checklist,
@@ -736,7 +852,12 @@ export function createProjectBatchAcceptanceReportValidation(report = {}) {
const summaryViewModel = objectOrEmpty(reportObject.summaryViewModel);
const actionPlan = objectOrEmpty(reportObject.actionPlan);
const checklist = objectOrEmpty(reportObject.checklist);
const virtualHalSimConfigSourceCoverage = objectOrEmpty(reportObject.virtualHalSimConfigSourceCoverage);
const rows = arrayOrEmpty(reportObject.rows);
const virtualHalSimConfigSourceCoverageRequired = reportObject.virtualHalSimConfigSourceCoverage !== null &&
reportObject.virtualHalSimConfigSourceCoverage !== undefined;
const virtualHalSimConfigSourceCoverageReady = !virtualHalSimConfigSourceCoverageRequired ||
isVirtualHalSimConfigSourceCoverageReady(virtualHalSimConfigSourceCoverage);
const missing = [
...(reportObject.apiName === "project-batch-acceptance-report" ? [] : ["apiName"]),
...(reportObject.reportVersion === 1 ? [] : ["reportVersion"]),
@@ -760,7 +881,8 @@ export function createProjectBatchAcceptanceReportValidation(report = {}) {
...(checklist.apiName === "project-batch-acceptance-checklist" && checklist.ready === true
? []
: ["checklist"]),
...(rows.find(({ id, value }) => id === "checklist" && value === "3/3 passed")
...(virtualHalSimConfigSourceCoverageReady ? [] : ["virtualHalSimConfigSourceCoverage"]),
...(rows.find(({ id, value }) => id === "checklist" && /^([34])\/\1 passed$/.test(value))
? []
: ["rows.checklist"]),
];
@@ -795,6 +917,13 @@ export function createProjectBatchAcceptanceReportValidation(report = {}) {
label: "Checklist",
value: checklist.ready === true ? "ready" : "missing",
},
{
id: "virtual-hal-sim-config-source-coverage",
label: "Virtual HAL sim-config source coverage",
value: virtualHalSimConfigSourceCoverageRequired
? (virtualHalSimConfigSourceCoverageReady ? "ready" : "missing")
: "not required",
},
{
id: "missing",
label: "Missing report evidence",
@@ -1251,6 +1380,7 @@ export function createProjectReleaseReadinessReport({
gateResults = {},
observedOutputs = [],
simConfigInventory = DEFAULT_SIM_CONFIG_INVENTORY_BASELINE,
virtualHalSimConfigSourceCoverage = null,
blockedRuntimeFamilies = BLOCKED_RUNTIME_FAMILIES,
promotedRuntimeFamilies = [],
axisScreenshotArtifacts = [],
@@ -1283,13 +1413,21 @@ export function createProjectReleaseReadinessReport({
const promotedFamilies = [...promotedRuntimeFamilies];
const promotedBlockedFamilies = promotedFamilies.filter((family) => blockedFamilies.includes(family));
const inventoryReady = inventory.unexpectedFail === 0;
const virtualHalSimConfigSourceCoverageReady = isVirtualHalSimConfigSourceCoverageReady(
virtualHalSimConfigSourceCoverage,
);
const blockedRuntimeReady = promotedBlockedFamilies.length === 0;
const axisScreenshotArtifactSummary = createAxisScreenshotArtifactSummary(axisScreenshotArtifacts);
const axisScreenshotArtifactsReady = axisScreenshotArtifactSummary.ready;
const ready = releaseGatePassed && inventoryReady && blockedRuntimeReady && axisScreenshotArtifactsReady;
const ready = releaseGatePassed &&
inventoryReady &&
virtualHalSimConfigSourceCoverageReady &&
blockedRuntimeReady &&
axisScreenshotArtifactsReady;
const missing = [
...(releaseGatePassed ? [] : ["project-release-gate"]),
...(inventoryReady ? [] : ["sim-config-inventory"]),
...(virtualHalSimConfigSourceCoverageReady ? [] : ["virtual-hal-sim-config-source-coverage"]),
...(blockedRuntimeReady ? [] : ["blocked-runtime-families"]),
...(axisScreenshotArtifactsReady ? [] : ["axis-screenshot-artifacts"]),
];
@@ -1306,6 +1444,8 @@ export function createProjectReleaseReadinessReport({
expectedOutput: "project_release_gate=ok",
},
simConfigInventory: inventory,
virtualHalSimConfigSourceCoverage,
virtualHalSimConfigSourceCoverageReady,
blockedRuntimeFamilies: blockedFamilies,
promotedRuntimeFamilies: promotedFamilies,
promotedBlockedFamilies,
@@ -1327,6 +1467,11 @@ export function createProjectReleaseReadinessReport({
label: "Sim config inventory",
value: `unexpected_fail=${inventory.unexpectedFail}`,
},
{
id: "virtual-hal-sim-config-source-coverage",
label: "Virtual HAL sim-config source coverage",
value: virtualHalSimConfigSourceCoverageReady ? "ready" : "missing",
},
{
id: "blocked-runtime-families",
label: "Blocked runtime families",
@@ -1349,6 +1494,7 @@ export function createProjectReleaseReadinessSummaryViewModel(
const missing = Array.isArray(report?.missing) ? report.missing : [];
const gateResultMatrix = objectOrEmpty(report?.gateResultMatrix);
const simConfigInventory = objectOrEmpty(report?.simConfigInventory);
const virtualHalSimConfigSourceCoverageReady = report?.virtualHalSimConfigSourceCoverageReady === true;
const axisScreenshotArtifactSummary = objectOrEmpty(report?.axisScreenshotArtifactSummary);
const blockedRuntimeFamilies = arrayOrEmpty(report?.blockedRuntimeFamilies);
const promotedBlockedFamilies = arrayOrEmpty(report?.promotedBlockedFamilies);
@@ -1380,6 +1526,11 @@ export function createProjectReleaseReadinessSummaryViewModel(
label: "Sim config inventory",
value: `unexpected_fail=${simConfigInventory.unexpectedFail ?? "unknown"}`,
},
{
id: "virtual-hal-sim-config-source-coverage",
label: "Virtual HAL sim-config source coverage",
value: virtualHalSimConfigSourceCoverageReady ? "ready" : "missing",
},
{
id: "blocked-runtime-families",
label: "Blocked runtime families",
@@ -1457,6 +1608,11 @@ export function createProjectReleaseReadinessArtifactValidationSummaryViewModel(
label: "Gate action plan",
value: validation?.gateActionPlanReady === true ? "ready" : "missing",
},
{
id: "virtual-hal-sim-config-source-coverage",
label: "Virtual HAL sim-config source coverage",
value: validation?.virtualHalSimConfigSourceCoverageReady === true ? "ready" : "missing",
},
{
id: "missing",
label: "Missing artifact evidence",
@@ -1609,14 +1765,19 @@ export function createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson
export async function loadProjectReleaseReadinessArtifactUrlWorkflow({
artifactUrl = "",
diagnosticsUrl = "",
fetchRef = globalThis.fetch,
} = {}) {
if (!artifactUrl || typeof fetchRef !== "function") {
const jsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson: "" });
const diagnosticsValidation = diagnosticsUrl
? createProjectReleaseBrowserDiagnosticsArtifactValidation({})
: null;
const missing = [
...(artifactUrl ? [] : ["artifact-url"]),
...(typeof fetchRef === "function" ? [] : ["fetch"]),
...jsonWorkflow.missing,
...(diagnosticsUrl ? ["diagnostics-fetch", ...diagnosticsValidation.missing.map((item) => `diagnostics.${item}`)] : []),
];
return {
apiName: "project-release-readiness-artifact-url-workflow",
@@ -1624,11 +1785,16 @@ export async function loadProjectReleaseReadinessArtifactUrlWorkflow({
phase: "blocked",
ready: false,
artifactUrl,
diagnosticsUrl,
fetched: false,
diagnosticsFetched: false,
httpStatus: null,
diagnosticsHttpStatus: null,
fetchError: null,
diagnosticsFetchError: null,
jsonWorkflow,
validation: jsonWorkflow.validation,
diagnosticsValidation,
summaryViewModel: jsonWorkflow.summaryViewModel,
actionPlan: jsonWorkflow.actionPlan,
missing,
@@ -1664,14 +1830,23 @@ export async function loadProjectReleaseReadinessArtifactUrlWorkflow({
phase: "blocked",
ready: false,
artifactUrl,
diagnosticsUrl,
fetched: false,
diagnosticsFetched: false,
httpStatus,
diagnosticsHttpStatus: null,
fetchError,
diagnosticsFetchError: null,
jsonWorkflow,
validation: jsonWorkflow.validation,
diagnosticsValidation: diagnosticsUrl ? createProjectReleaseBrowserDiagnosticsArtifactValidation({}) : null,
summaryViewModel: jsonWorkflow.summaryViewModel,
actionPlan: jsonWorkflow.actionPlan,
missing: ["artifact-fetch", ...jsonWorkflow.missing],
missing: [
"artifact-fetch",
...jsonWorkflow.missing,
...(diagnosticsUrl ? ["diagnostics-fetch"] : []),
],
rows: [
{
id: "fetch",
@@ -1694,20 +1869,56 @@ export async function loadProjectReleaseReadinessArtifactUrlWorkflow({
const artifactJson = await response.text();
const jsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson });
let diagnosticsFetched = false;
let diagnosticsHttpStatus = null;
let diagnosticsFetchError = null;
let diagnosticsValidation = null;
const diagnosticsMissing = [];
if (diagnosticsUrl) {
try {
const diagnosticsResponse = await fetchRef(diagnosticsUrl);
diagnosticsHttpStatus = diagnosticsResponse?.status ?? null;
if (!diagnosticsResponse?.ok) {
diagnosticsFetchError = `diagnostics artifact URL fetch failed${diagnosticsHttpStatus ? `: ${diagnosticsHttpStatus}` : ""}`;
diagnosticsMissing.push("diagnostics-fetch");
diagnosticsValidation = createProjectReleaseBrowserDiagnosticsArtifactValidation({});
} else {
diagnosticsFetched = true;
const diagnosticsArtifact = JSON.parse(await diagnosticsResponse.text());
diagnosticsValidation = createProjectReleaseBrowserDiagnosticsArtifactValidation(diagnosticsArtifact);
diagnosticsMissing.push(...diagnosticsValidation.missing.map((item) => `diagnostics.${item}`));
}
} catch (error) {
diagnosticsFetchError = error?.message ?? "diagnostics artifact URL fetch error";
diagnosticsValidation = createProjectReleaseBrowserDiagnosticsArtifactValidation({});
diagnosticsMissing.push("diagnostics-fetch");
}
}
const missing = [
...jsonWorkflow.missing,
...diagnosticsMissing,
];
const ready = jsonWorkflow.ready === true &&
(!diagnosticsUrl || diagnosticsValidation?.ready === true);
return {
apiName: "project-release-readiness-artifact-url-workflow",
workflowVersion: 1,
phase: jsonWorkflow.ready === true ? "ready" : "blocked",
ready: jsonWorkflow.ready === true,
phase: ready ? "ready" : "blocked",
ready,
artifactUrl,
diagnosticsUrl,
fetched: true,
diagnosticsFetched,
httpStatus,
diagnosticsHttpStatus,
fetchError: null,
diagnosticsFetchError,
jsonWorkflow,
validation: jsonWorkflow.validation,
diagnosticsValidation,
summaryViewModel: jsonWorkflow.summaryViewModel,
actionPlan: jsonWorkflow.actionPlan,
missing: jsonWorkflow.missing,
missing,
rows: [
{
id: "fetch",
@@ -1719,6 +1930,13 @@ export async function loadProjectReleaseReadinessArtifactUrlWorkflow({
label: "Artifact JSON workflow",
value: jsonWorkflow.ready === true ? "ready" : "blocked",
},
{
id: "diagnostics-workflow",
label: "Browser diagnostics workflow",
value: diagnosticsUrl
? (diagnosticsValidation?.ready === true ? "ready" : "blocked")
: "not requested",
},
{
id: "next-command",
label: "Next command",
@@ -1734,14 +1952,23 @@ export async function loadProjectReleaseReadinessArtifactUrlWorkflow({
phase: "blocked",
ready: false,
artifactUrl,
diagnosticsUrl,
fetched: false,
diagnosticsFetched: false,
httpStatus: null,
diagnosticsHttpStatus: null,
fetchError: error?.message ?? "artifact URL fetch error",
diagnosticsFetchError: null,
jsonWorkflow,
validation: jsonWorkflow.validation,
diagnosticsValidation: diagnosticsUrl ? createProjectReleaseBrowserDiagnosticsArtifactValidation({}) : null,
summaryViewModel: jsonWorkflow.summaryViewModel,
actionPlan: jsonWorkflow.actionPlan,
missing: ["artifact-fetch", ...jsonWorkflow.missing],
missing: [
"artifact-fetch",
...jsonWorkflow.missing,
...(diagnosticsUrl ? ["diagnostics-fetch"] : []),
],
rows: [
{
id: "fetch",
@@ -1802,6 +2029,13 @@ export function createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel
label: "Artifact validation",
value: workflow?.validation?.ready === true ? "ready" : "blocked",
},
{
id: "browser-diagnostics",
label: "Browser diagnostics",
value: workflow?.diagnosticsUrl
? (workflow?.diagnosticsValidation?.ready === true ? "ready" : "blocked")
: "not requested",
},
{
id: "next-command",
label: "Next command",
@@ -1850,6 +2084,15 @@ export function createProjectReleaseReadinessArtifactUrlWorkflowActionPlan(
expectedOutput: null,
}]
: []),
...(missing.includes("diagnostics-fetch")
? [{
id: "verify-diagnostics-url-fetch",
label: "Verify browser diagnostics artifact URL fetch",
kind: "fetch",
command: null,
expectedOutput: null,
}]
: []),
];
const commandActions = validationCommands.map((command) => ({
id: command.id ?? command.gateId ?? `command-${command.step}`,
@@ -1902,6 +2145,7 @@ export function createProjectReleaseReadinessArtifactValidation(artifact = {}) {
const artifactObject = objectOrEmpty(artifact);
const releaseGate = objectOrEmpty(artifactObject.releaseGate);
const simConfigInventory = objectOrEmpty(artifactObject.simConfigInventory);
const virtualHalSimConfigSourceCoverage = objectOrEmpty(artifactObject.virtualHalSimConfigSourceCoverage);
const gateManifest = objectOrEmpty(artifactObject.gateManifest);
const gateExecutionManifest = objectOrEmpty(artifactObject.gateExecutionManifest);
const gateExecutionSummaryViewModel = objectOrEmpty(artifactObject.gateExecutionSummaryViewModel);
@@ -1947,6 +2191,9 @@ export function createProjectReleaseReadinessArtifactValidation(artifact = {}) {
&& gateActionPlan.pendingCount === 0
&& gateActionPlan.nextCommand === null
&& actionPlanCommands.length === 0;
const virtualHalSimConfigSourceCoverageReady = isVirtualHalSimConfigSourceCoverageReady(
virtualHalSimConfigSourceCoverage,
) && artifactObject.virtualHalSimConfigSourceCoverageReady === true;
const axisScreenshotArtifacts = arrayOrEmpty(axisScreenshotArtifactSummary.artifacts);
const axisScreenshotSummaryReady = !axisScreenshotArtifactSummary.apiName
|| axisScreenshotArtifacts.length === 0
@@ -1984,6 +2231,7 @@ export function createProjectReleaseReadinessArtifactValidation(artifact = {}) {
...(simConfigInventory.passed === 28 ? [] : ["simConfigInventory.passed"]),
...(simConfigInventory.skipped === 131 ? [] : ["simConfigInventory.skipped"]),
...(simConfigInventory.unexpectedFail === 0 ? [] : ["simConfigInventory.unexpectedFail"]),
...(virtualHalSimConfigSourceCoverageReady ? [] : ["virtualHalSimConfigSourceCoverage"]),
...(arrayOrEmpty(artifactObject.blockedRuntimeFamilies).join(",") === BLOCKED_RUNTIME_FAMILIES.join(",")
? []
: ["blockedRuntimeFamilies"]),
@@ -2017,6 +2265,7 @@ export function createProjectReleaseReadinessArtifactValidation(artifact = {}) {
gateExecutionSummaryReady: executionSummaryReady,
gateResultMatrixReady: matrixReady,
gateActionPlanReady: actionPlanReady,
virtualHalSimConfigSourceCoverageReady,
axisScreenshotArtifactSummaryReady: axisScreenshotSummaryReady,
axisScreenshotArtifactCount: axisScreenshotArtifacts.length,
blockedRuntimeFamilies: arrayOrEmpty(artifactObject.blockedRuntimeFamilies),
@@ -2056,6 +2305,11 @@ export function createProjectReleaseReadinessArtifactValidation(artifact = {}) {
label: "Gate action plan",
value: actionPlanReady ? "ready" : "missing",
},
{
id: "virtual-hal-sim-config-source-coverage",
label: "Virtual HAL sim-config source coverage",
value: virtualHalSimConfigSourceCoverageReady ? "ready" : "missing",
},
{
id: "axis-screenshot-artifacts",
label: "AXIS screenshot artifacts",