const REQUIRED_RELEASE_GATES = [ { id: "diff-check", label: "Git diff check", command: "git diff --check", }, { id: "vendor-sync", label: "Vendor sync guard", command: "wasm-port/tools/verify_vendor_sync.sh", expectedOutput: "vendor sync up to date", }, { id: "standalone-cnc-semantics", label: "Standalone CNC semantics guard", command: "wasm-port/tools/verify_no_standalone_cnc_semantics.sh", expectedOutput: "standalone CNC semantics guard complete", }, { id: "interp-wasm", label: "Interpreter WASM Node smoke", command: "SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_interp_wasm.sh", expectedOutput: "interp_wasm_node_smoke=ok", }, { id: "sim-config-inventory", label: "Sim config inventory WASM Node smoke", command: "SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh", expectedOutput: "sim_configs_wasm_node_inventory_unexpected_fail=0", }, { id: "ini-panel-browser", label: "INI panel browser smoke", command: "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh", expectedOutput: "browser_ini_shell_integration_workflow_smoke=ok", }, { id: "opfs-session-browser", label: "OPFS session browser workflow smoke", command: "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_opfs_session_workflow_browser.sh", expectedOutput: "browser_opfs_session_workflow_smoke=ok", }, { id: "tool-db-process-proof", label: "Tool DB process protocol proof", command: "wasm-port/tests/host/verify_tool_db_process_proof.sh", expectedOutput: "tool_db_process_proof=ok", }, { id: "release-artifact-url-browser", label: "Release artifact URL browser workflow smoke", command: "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh", expectedOutput: "browser_release_artifact_url_workflow_smoke=ok", }, { id: "project-batch-acceptance", label: "Project batch acceptance workflow smoke", command: "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh", expectedOutput: "project_batch_acceptance_workflow_node_smoke=ok", }, { id: "ui-node-smokes", label: "UI Node smokes", command: "wasm-port/tests/ui/node/verify_ui_node_smokes.sh", expectedOutput: "ui_node_smokes=ok", }, { id: "host-smokes", label: "Host aggregate smoke", command: "wasm-port/tests/host/verify_host_smokes.sh", expectedOutput: "host_wasm_opfs_browser_smokes=ok", }, { id: "project-release-gate", label: "Project release gate", command: "wasm-port/tests/host/verify_project_release_gate.sh", expectedOutput: "project_release_gate=ok", }, ]; const DEFAULT_SIM_CONFIG_INVENTORY_BASELINE = { executed: 82, passed: 82, skipped: 77, unexpectedFail: 0, }; const DEFAULT_SIM_CONFIG_INVENTORY_ARTIFACT_HASHES = { "wasm-port/build/wasm/sim-configs-inventory/boundary-summary.tsv": "6cc15052cad03d04eff4506cd0a9d651cd45a2bd5da4d9f38633e9535826b9f3", "wasm-port/build/wasm/sim-configs-inventory/ini-boundary-summary.tsv": "17bff95b57c55ff4201a23c7286e733550e4df513470c66dd5f24329e7781a35", }; function isBoundaryEvidenceBaselineFresh(boundaryEvidence = {}) { const baseline = objectOrEmpty(boundaryEvidence.baselineSummary); const hashes = objectOrEmpty(boundaryEvidence.sourceArtifactHashes); return baseline.executed === DEFAULT_SIM_CONFIG_INVENTORY_BASELINE.executed && baseline.passed === DEFAULT_SIM_CONFIG_INVENTORY_BASELINE.passed && baseline.skipped === DEFAULT_SIM_CONFIG_INVENTORY_BASELINE.skipped && baseline.unexpectedFail === DEFAULT_SIM_CONFIG_INVENTORY_BASELINE.unexpectedFail && Object.entries(DEFAULT_SIM_CONFIG_INVENTORY_ARTIFACT_HASHES) .every(([artifactPath, expectedHash]) => hashes[artifactPath] === expectedHash); } function createPromotionFamilySummaryText(candidateReport = {}) { const families = arrayOrEmpty(objectOrEmpty(candidateReport).familyRows); if (families.length === 0) { return "not provided"; } return families.map((family) => { const label = family.id ?? "unknown"; const completeCount = family.completeCount ?? 0; const candidateCount = family.candidateCount ?? 0; const state = family.complete === true && family.explicitBrowserDiagnosticsReady === true ? "ready" : "blocked"; return `${label}: ${completeCount}/${candidateCount} ${state}`; }).join("; "); } function createPromotionFamilySummaryRows(candidateReport = {}) { return arrayOrEmpty(objectOrEmpty(candidateReport).familyRows).map((family) => { const sourceFileCount = arrayOrEmpty(family.sourceFiles).length; const candidateCount = family.candidateCount ?? 0; const completeCount = family.completeCount ?? 0; const explicitBrowserDiagnosticsReady = family.explicitBrowserDiagnosticsReady === true; const ready = family.complete === true && explicitBrowserDiagnosticsReady; return { id: family.id ?? "unknown", label: family.id ?? "Unknown promotion family", value: `${completeCount}/${candidateCount} ${ready ? "ready" : "blocked"}; sources=${sourceFileCount}; diagnostics=${explicitBrowserDiagnosticsReady ? "ready" : "blocked"}`, sourceFiles: arrayOrEmpty(family.sourceFiles), candidateCount, completeCount, sourceFileCount, explicitBrowserDiagnosticsReady, ready, }; }); } function createPromotionCandidateArtifactSummary({ candidateReport = {}, evidenceExpansionReport = {}, inventory = DEFAULT_SIM_CONFIG_INVENTORY_BASELINE, blockedFamilies = BLOCKED_RUNTIME_FAMILIES, promotedBlockedFamilies = [], promotionCandidateRows = [], evidenceExpansionRows = [], } = {}) { const rows = arrayOrEmpty(objectOrEmpty(candidateReport).rows); const candidateArtifactRows = arrayOrEmpty(promotionCandidateRows); const evidenceExpansionArtifactRows = arrayOrEmpty(evidenceExpansionRows); const evidenceReadyCount = rows.filter((row) => row.currentNodeInventoryStatus === "PASS" && row.blockedKind === "-" && row.currentMatrixBrowserStatus === "explicit-browser-diagnostics" && row.targetBrowserEvidence === "explicit-browser-diagnostics" ).length; const artifactEvidenceReadyRows = candidateArtifactRows .filter((row) => row.candidate_kind === "evidence-ready"); const artifactInventoryReadyRows = candidateArtifactRows .filter((row) => row.candidate_kind === "inventory-ready"); const artifactEvidenceReadyCount = artifactEvidenceReadyRows.length; const inventoryReadyCount = artifactInventoryReadyRows.length > 0 ? artifactInventoryReadyRows.length : 2; const evidenceExpansionCandidateCount = evidenceExpansionArtifactRows.length > 0 ? evidenceExpansionArtifactRows.length : 14; const promotionAllowedCount = candidateArtifactRows.length > 0 ? candidateArtifactRows.filter((row) => String(row.promotion_allowed ?? row.promotionAllowed) === "1").length : 0; const hardBlockRuntimeFamilyRows = artifactInventoryReadyRows .filter((row) => blockedFamilies.includes(row.skip_kind ?? row.blocked_kind ?? row.blockedKind)) .map((row, index) => ({ candidateId: row.candidate_id ?? row.path ?? "unknown", path: row.path ?? "unknown", skipKind: row.skip_kind ?? row.blocked_kind ?? row.blockedKind ?? "unknown", promotionAllowed: String(row.promotion_allowed ?? row.promotionAllowed ?? "0") === "1", blockReason: row.block_reason ?? row.blockReason ?? "-", recommendedNextCommand: row.recommended_next_command ?? row.recommendedNextCommand ?? "-", detailId: `hard-block-runtime-detail-${index + 1}`, })); const resolvedEvidenceReadyCount = artifactEvidenceReadyCount > 0 ? artifactEvidenceReadyCount : evidenceReadyCount; const hardBlockRuntimePromotionAllowedCount = hardBlockRuntimeFamilyRows .filter((row) => row.promotionAllowed) .length; const hardBlockRuntimeFamilySummaryRows = blockedFamilies.map((family) => { const familyRows = hardBlockRuntimeFamilyRows.filter((row) => row.skipKind === family); const promotionAllowedRows = familyRows.filter((row) => row.promotionAllowed); return { family, candidateCount: familyRows.length, promotionAllowedCount: promotionAllowedRows.length, locked: promotionAllowedRows.length === 0, lockedPaths: familyRows.map((row) => row.path), firstPath: familyRows[0]?.path ?? null, firstBlockReason: familyRows[0]?.blockReason ?? null, nextProof: familyRows[0]?.recommendedNextCommand ?? null, }; }); const hardBlockRuntimeLockSummary = createHardBlockRuntimeLockSummary( blockedFamilies, promotedBlockedFamilies, ); const baselineText = [ `executed=${inventory.executed ?? "unknown"}`, `passed=${inventory.passed ?? "unknown"}`, `skipped=${inventory.skipped ?? "unknown"}`, `unexpected_fail=${inventory.unexpectedFail ?? "unknown"}`, ].join(" "); return { apiName: "project-release-promotion-candidate-artifact-summary", summaryVersion: 1, phase: "ready", ready: true, artifactPath: "wasm-port/build/wasm/sim-configs-inventory/promotion-candidates.tsv", evidenceExpansionArtifactPath: "wasm-port/build/wasm/sim-configs-inventory/evidence-expansion-candidates.tsv", layerCount: 2, evidenceReadyCount: resolvedEvidenceReadyCount, inventoryReadyCount, evidenceExpansionCandidateCount, totalCandidateCount: resolvedEvidenceReadyCount + inventoryReadyCount, promotionAllowedCount, hardBlockRuntimeLock: hardBlockRuntimeLockSummary.lockValue, hardBlockRuntimePromotionAllowedCount, inventoryBaseline: baselineText, artifactRows: { promotionCandidates: candidateArtifactRows.length > 0 ? candidateArtifactRows.length : resolvedEvidenceReadyCount + inventoryReadyCount, evidenceExpansion: evidenceExpansionArtifactRows.length > 0 ? evidenceExpansionArtifactRows.length : evidenceExpansionCandidateCount, }, hardBlockRuntimeFamilyRows, hardBlockRuntimeFamilyDetailRows: hardBlockRuntimeFamilyRows.map((row) => ({ id: row.detailId, family: row.skipKind, path: row.path, blockReason: row.blockReason, nextProof: row.recommendedNextCommand, promotionAllowed: row.promotionAllowed, })), hardBlockRuntimeFamilySummaryRows, layers: [ { id: "evidence-ready", candidateCount: resolvedEvidenceReadyCount, promotionAllowedCount: 0, virtualHalEvidenceReady: true, baselineChanging: false, }, { id: "inventory-ready", candidateCount: inventoryReadyCount, promotionAllowedCount, virtualHalEvidenceReady: false, baselineChanging: promotionAllowedCount > 0, }, ], evidenceExpansion: { id: "browser-diagnostics-expansion", candidateCount: evidenceExpansionCandidateCount, artifactRowCount: evidenceExpansionArtifactRows.length > 0 ? evidenceExpansionArtifactRows.length : evidenceExpansionCandidateCount, promotionAllowedCount: 0, baselineChanging: false, nextEvidence: "browser-diagnostics-binding", }, }; } function createHardBlockRuntimeLockSummary(blockedFamilies = [], promotedBlockedFamilies = []) { const blockedCount = arrayOrEmpty(blockedFamilies).length; const promotedCount = arrayOrEmpty(promotedBlockedFamilies).length; return { lockValue: promotedCount === 0 ? `locked (${blockedCount} families)` : `violated (${promotedCount} promoted)`, promotedCountValue: `${promotedCount} promoted`, }; } function createToolDbProcessProofSummary(toolDbProcessProof = {}) { const proof = objectOrEmpty(toolDbProcessProof); const nativeProtocolReady = proof.nativeProtocolReady === true; const wasmProtocolReady = proof.wasmProtocolReady !== false; const browserProtocolReady = proof.browserProtocolReady !== false; const opfsPersistenceReady = proof.opfsPersistenceReady !== false; const tblFallbackSufficient = proof.tblFallbackSufficient === true; const promotionAllowed = proof.promotionAllowed === true; const ready = wasmProtocolReady && browserProtocolReady && opfsPersistenceReady && tblFallbackSufficient === false && promotionAllowed === false; return { apiName: "tool-db-process-proof-summary", summaryVersion: 1, phase: ready ? "ready" : "blocked", ready, boundaryClass: "L4-TOOL-DB", path: proof.path ?? "axis/db_demo/base.ngc", dbProgramPath: proof.dbProgramPath ?? "./db_nonran.py", runtimeMode: proof.runtimeMode ?? "browser-python-wasm-worker", nativeProtocolReady, nativeRuntimeRequiredForPromotion: true, wasmProtocolReady, browserProtocolReady, opfsPersistenceReady, tblFallbackSufficient, promotionAllowed, executionEnabled: proof.executionEnabled === true, requiredCommands: [ "wasm-port/tests/sdk/node/verify_tool_db_process_port.sh", "wasm-port/tests/opfs/node/verify_tool_db_store.sh", "wasm-port/tests/wasm/node/verify_tool_db_process_port_wasm.sh", "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_tool_db_process_browser.sh", ], }; } function createPythonRemapRuntimeProofSummary(pythonRemapRuntimeProof = {}) { const proof = objectOrEmpty(pythonRemapRuntimeProof); const nativeLifecycleReady = proof.nativeLifecycleReady === true; const wasmLifecycleReady = proof.wasmLifecycleReady !== false; const browserLifecycleReady = proof.browserLifecycleReady !== false; const promotionAllowed = proof.promotionAllowed === true; const executionEnabled = proof.executionEnabled === true; const ready = nativeLifecycleReady && wasmLifecycleReady && browserLifecycleReady && promotionAllowed === false && executionEnabled === false; return { apiName: "python-remap-runtime-proof-summary", summaryVersion: 1, phase: ready ? "ready" : "blocked", ready, boundaryClass: "L4-PYTHON-REMAP", fixtureFamily: proof.fixtureFamily ?? "axis/remap/stop-lookahead/nc_files", fixtureId: proof.fixtureId ?? "stop_lookahead_python_runtime_lifecycle", iniPath: proof.iniPath ?? "axis/remap/stop-lookahead/demo.ini", pythonPathPrepend: proof.pythonPathPrepend ?? "python", topLevelPath: proof.topLevelPath ?? "python/toplevel.py", callableName: proof.callableName ?? "queuebuster", runtimeMode: proof.runtimeMode ?? "browser-python-wasm-worker", nativeProbeStatus: proof.nativeProbeStatus ?? (nativeLifecycleReady ? "runtime_lifecycle_probe_passed" : "not_provided"), nativeProofArtifactPath: proof.nativeProofArtifactPath ?? "wasm-port/build/native/native-runtime-probe-summary.tsv", nativeProofStdoutLog: proof.nativeProofStdoutLog ?? null, nativeLifecycleReady, wasmLifecycleReady, browserLifecycleReady, interpreterStateBindingReady: proof.interpreterStateBindingReady !== false, generatorLifecycleReady: proof.generatorLifecycleReady !== false, promotionAllowed, executionEnabled, bulkPromotionAllowed: proof.bulkPromotionAllowed === true, manualLockUpdateRequired: proof.manualLockUpdateRequired !== false, requiredCommands: [ "ENABLE_PYTHON_REMAP_RUNTIME_PROBE=1 wasm-port/tests/native/probe_python_remap_runtime.sh", "wasm-port/tests/sdk/node/verify_python_remap_runtime_port.sh", "SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_python_remap_runtime_port_wasm.sh", "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_python_remap_runtime_browser.sh", ], }; } const BLOCKED_RUNTIME_FAMILIES = [ "L4-USER-M-PROCESS", "L4-PYTHON-REMAP", ]; const PROJECT_RELEASE_READINESS_ARTIFACT_API = "project-release-readiness-report"; const PROJECT_RELEASE_READINESS_ARTIFACT_VERSION = 1; const REQUIRED_PROMOTION_CANDIDATES = [ { id: "qtdragon-multi-joint-on-abort", sourceFiles: [ "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini", "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc", ], }, { id: "qtdragon-xyz-on-abort", sourceFiles: [ "linuxcnc/configs/sim/qtdragon/qtdragon_xyz/qtdragon_inch.ini", "linuxcnc/configs/sim/qtdragon/qtdragon_xyz/on_abort.ngc", ], }, { id: "qtdragon-xyz45-on-abort", sourceFiles: [ "linuxcnc/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini", "linuxcnc/configs/sim/qtdragon/qtdragon_xyz45/on_abort.ngc", ], }, { id: "qtdragon-hd-xyz-on-abort", sourceFiles: [ "linuxcnc/configs/sim/qtdragon_hd/qtdragon_hd_xyz/qtdragon_hd_vertical.ini", "linuxcnc/configs/sim/qtdragon_hd/qtdragon_hd_xyz/on_abort.ngc", ], }, { id: "qtdragon-hd-z-compensation-on-abort", sourceFiles: [ "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", ], }, { id: "qtvcp-screens-qtdragon-on-abort", sourceFiles: [ "linuxcnc/configs/sim/qtvcp_screens/qtdragon/qtdragon_mpg.ini", "linuxcnc/configs/sim/qtvcp_screens/qtdragon/on_abort.ngc", ], }, { id: "puma-seam-weld", sourceFiles: [ "linuxcnc/configs/sim/axis/vismach/puma/puma.ini", "linuxcnc/configs/sim/axis/vismach/puma/puma_seam_weld.ngc", "linuxcnc/configs/sim/axis/vismach/puma/remap_subs/428remap.ngc", ], }, { id: "rose-engine-rcone-demo", sourceFiles: [ "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", ], }, ]; const REQUIRED_EVIDENCE_EXPANSION_CANDIDATES = [ { id: "woodpecker-on-abort", sourceFiles: [ "linuxcnc/configs/sim/woodpecker/woodpecker.ini", "linuxcnc/configs/sim/woodpecker/on_abort.ngc", "linuxcnc/configs/sim/woodpecker/tool.tbl", ], }, { id: "puma-cube", sourceFiles: [ "linuxcnc/configs/sim/axis/vismach/puma/puma_cube.ini", "linuxcnc/configs/sim/axis/vismach/puma/puma_cube.ngc", "linuxcnc/configs/sim/axis/vismach/puma/remap_subs/428remap.ngc", ], }, { id: "melfa-example", sourceFiles: [ "linuxcnc/configs/sim/axis/vismach/melfa-sim/melfa.ini", "linuxcnc/configs/sim/axis/vismach/melfa-sim/example.ngc", "linuxcnc/configs/sim/axis/vismach/melfa-sim/remap_subs/428remap.ngc", ], }, ]; const REQUIRED_MACRO_LOAD_FIXTURES = [ { id: "rose-engine-rcone-macro-load", fixturePath: "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc", declarationEvidence: { sourceFile: "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", key: "NGCGUI_SUBFILE", value: "rcone.ngc", line: 34, }, sourceFiles: [ "linuxcnc/configs/sim/axis/rose_engine/rose_engine.ini", "linuxcnc/configs/sim/axis/rose_engine/rcone.ngc", "linuxcnc/configs/sim/axis/rose_engine/rcone_demo.ngc", ], }, { id: "external-offsets-queuebuster-macro-load", fixturePath: "linuxcnc/configs/sim/axis/external_offsets/queuebuster.ngc", declarationEvidence: { sourceFile: "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini", key: "NGCGUI_SUBFILE", value: "queuebuster.ngc", line: 40, }, sourceFiles: [ "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ini", "linuxcnc/configs/sim/axis/external_offsets/eoffsets.ngc", ], }, ]; const REQUIRED_BLOCKED_MACRO_LOAD_FIXTURES = [ { id: "silverdragon-tool-sensor-python-ui-boundary", fixturePath: "linuxcnc/configs/sim/gscreen/silverdragon/macros/tool_sensor.ngc", blockedKind: "PYTHON-UI-PROCESS", }, { id: "gmoccapy-on-abort-python-remap-boundary", fixturePath: "linuxcnc/configs/sim/gmoccapy/macros/on_abort.ngc", blockedKind: "L4-PYTHON-REMAP", }, ]; const REQUIRED_MACRO_LOAD_AUDIT_CANDIDATES = [ { id: "gscreen-industrial-lathe-wear-toolchange-audit", fixturePath: "linuxcnc/configs/sim/gscreen/industrial_lathe_wear/toolchange.ngc", auditStatus: "blocked-missing-owning-ini", }, { id: "qtvcp-industrial-lathe-wear-toolchange-audit", fixturePath: "linuxcnc/configs/sim/qtvcp_screens/industrial_lathe_wear/toolchange.ngc", auditStatus: "blocked-missing-owning-ini", }, ]; 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") && arrayOrEmpty(coverage.sourceFiles).includes("linuxcnc/configs/sim/qtdragon/qtdragon_xyz45/qtdragon_xyza.ini") && arrayOrEmpty(coverage.sourceFiles).includes( "linuxcnc/configs/sim/qtdragon_hd/qtdragon_hd_z_compensation/qtdragon_hd_z_compensation.ini", ); } function hasRequiredPromotionCandidates(rows) { return REQUIRED_PROMOTION_CANDIDATES.every((candidate) => rows.some((row) => row.id === candidate.id && row.complete === true && row.currentNodeInventoryStatus === "PASS" && row.blockedKind === "-" && row.targetBrowserEvidence === "explicit-browser-diagnostics" && candidate.sourceFiles.every((file) => arrayOrEmpty(row.sourceFiles).includes(file)) ) ); } function isVirtualHalSimConfigMacroLoadFixtureReportReady(report) { const fixtureReport = objectOrEmpty(report); const rows = arrayOrEmpty(fixtureReport.rows); return fixtureReport.apiName === "linuxcnc-wasm-virtual-hal-sim-config-macro-load-fixture-report" && fixtureReport.complete === true && fixtureReport.webSimulationSatisfied === true && fixtureReport.inventoryBaselineUnchanged === true && arrayOrEmpty(fixtureReport.missingFixtures).length === 0 && arrayOrEmpty(fixtureReport.blockedFixtureIds).length === 0 && arrayOrEmpty(fixtureReport.declarationEvidenceViolations).length === 0 && arrayOrEmpty(fixtureReport.standaloneMainViolations).length === 0 && arrayOrEmpty(fixtureReport.blockedFixturePromotionViolations).length === 0 && arrayOrEmpty(fixtureReport.blockedBoundaryEvidenceViolations).length === 0 && arrayOrEmpty(fixtureReport.missingAuditRows).length === 0 && arrayOrEmpty(fixtureReport.auditPromotionViolations).length === 0 && arrayOrEmpty(fixtureReport.auditBoundaryEvidenceViolations).length === 0 && arrayOrEmpty(fixtureReport.auditPromotionAllowedViolations).length === 0 && arrayOrEmpty(fixtureReport.missingManifestFiles).length === 0 && REQUIRED_MACRO_LOAD_FIXTURES.every((fixture) => rows.some((row) => row.id === fixture.id && row.complete === true && row.nonMainFixture === true && row.targetBrowserEvidence === "non-main-fixture-diagnostics" && row.fixturePath === fixture.fixturePath && ( !fixture.declarationEvidence || ( row.declarationEvidenceReady === true && objectOrEmpty(row.declarationEvidence).sourceFile === fixture.declarationEvidence.sourceFile && objectOrEmpty(row.declarationEvidence).key === fixture.declarationEvidence.key && objectOrEmpty(row.declarationEvidence).value === fixture.declarationEvidence.value && objectOrEmpty(row.declarationEvidence).line === fixture.declarationEvidence.line ) ) && fixture.sourceFiles.every((file) => arrayOrEmpty(row.sourceFiles).includes(file)) ) ) && REQUIRED_BLOCKED_MACRO_LOAD_FIXTURES.every((fixture) => arrayOrEmpty(fixtureReport.blockedRows).some((row) => row.id === fixture.id && row.fixturePath === fixture.fixturePath && row.blockedKind === fixture.blockedKind && row.excludedFromPositiveFixtures === true && row.boundaryEvidenceReady === true && isBoundaryEvidenceBaselineFresh(row.boundaryEvidence) && objectOrEmpty(row.boundaryEvidence?.boundarySummary).recommendedBlocked === "UNAVAILABLE" && String(objectOrEmpty(row.boundaryEvidence?.boundarySummary).dependencies ?? "").includes("missing_vendored_ini:") && objectOrEmpty(row.boundaryEvidence?.iniBoundarySummary).vendored === 0 && objectOrEmpty(row.boundaryEvidence?.iniBoundarySummary).reportAvailable === 0 && row.complete === true ) ) && REQUIRED_MACRO_LOAD_AUDIT_CANDIDATES.every((candidate) => arrayOrEmpty(fixtureReport.auditRows).some((row) => row.id === candidate.id && row.fixturePath === candidate.fixturePath && row.auditStatus === candidate.auditStatus && row.promotionAllowed === false && row.excludedFromPositiveFixtures === true && row.boundaryEvidenceReady === true && isBoundaryEvidenceBaselineFresh(row.boundaryEvidence) && objectOrEmpty(row.boundaryEvidence?.boundarySummary).recommendedBlocked === "UNAVAILABLE" && String(objectOrEmpty(row.boundaryEvidence?.boundarySummary).dependencies ?? "").includes("missing_vendored_ini:") && objectOrEmpty(row.boundaryEvidence?.iniBoundarySummary).vendored === 0 && objectOrEmpty(row.boundaryEvidence?.iniBoundarySummary).reportAvailable === 0 && row.complete === true ) ); } function isVirtualHalMotionControllerMatrixReady(report) { const matrix = objectOrEmpty(report); return matrix.apiName === "linuxcnc-wasm-virtual-hal-motion-controller-matrix-report" && matrix.complete === true && matrix.webSimulationSatisfied === true && matrix.manifestChecked === true && arrayOrEmpty(matrix.missingFixtures).length === 0 && arrayOrEmpty(matrix.missingSimConfigTargets).length === 0 && arrayOrEmpty(matrix.missingManifestFiles).length === 0 && arrayOrEmpty(matrix.requiredPins).includes("motion.distance-to-go") && arrayOrEmpty(matrix.requiredPins).includes("motion.in-position") && arrayOrEmpty(matrix.sourceFiles).includes("linuxcnc/src/emc/motion/motion.c") && arrayOrEmpty(matrix.sourceFiles).includes("linuxcnc/src/emc/motion/axis.c") && arrayOrEmpty(matrix.simConfigTargets).includes("external-offsets") && arrayOrEmpty(matrix.simConfigTargets).includes("qtdragon-on-abort") && arrayOrEmpty(matrix.simConfigTargets).includes("vismach-remap-sims") && arrayOrEmpty(matrix.simConfigSourceFiles).includes("linuxcnc/configs/sim/axis/external_offsets/dynamic_offsets.ini") && arrayOrEmpty(matrix.simConfigSourceFiles).includes("linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini") && arrayOrEmpty(matrix.simConfigSourceFiles).includes("linuxcnc/configs/sim/axis/vismach/puma/puma.ini"); } function isVirtualHalSimConfigPromotionCandidateReportReady(report) { const candidateReport = objectOrEmpty(report); const rows = arrayOrEmpty(candidateReport.rows); return candidateReport.apiName === "linuxcnc-wasm-virtual-hal-sim-config-promotion-candidate-report" && candidateReport.complete === true && candidateReport.webSimulationSatisfied === true && candidateReport.inventoryBaselineUnchanged === true && arrayOrEmpty(candidateReport.missingCandidates).length === 0 && arrayOrEmpty(candidateReport.blockedCandidateIds).length === 0 && arrayOrEmpty(candidateReport.missingManifestFiles).length === 0 && arrayOrEmpty(candidateReport.missingRequiredReports).length === 0 && hasRequiredPromotionCandidates(rows); } function isVirtualHalSimConfigEvidenceExpansionReportReady(report) { const expansionReport = objectOrEmpty(report); const rows = arrayOrEmpty(expansionReport.rows); return expansionReport.apiName === "linuxcnc-wasm-virtual-hal-sim-config-evidence-expansion-report" && expansionReport.complete === true && expansionReport.webSimulationSatisfied === true && expansionReport.inventoryBaselineUnchanged === true && expansionReport.promotionAllowed === false && expansionReport.candidateCount === 3 && expansionReport.readyCandidateCount === 3 && arrayOrEmpty(expansionReport.missingCandidates).length === 0 && arrayOrEmpty(expansionReport.promotionAllowedViolations).length === 0 && arrayOrEmpty(expansionReport.blockedCandidateIds).length === 0 && arrayOrEmpty(expansionReport.missingManifestFiles).length === 0 && arrayOrEmpty(expansionReport.missingRequiredReports).length === 0 && REQUIRED_EVIDENCE_EXPANSION_CANDIDATES.every((candidate) => rows.some((row) => row.id === candidate.id && row.complete === true && row.currentNodeInventoryStatus === "PASS" && row.currentMatrixBrowserStatus === "REP" && row.targetBrowserEvidence === "browser-diagnostics-expansion" && row.blockedKind === "-" && row.promotionAllowed === false && candidate.sourceFiles.every((file) => arrayOrEmpty(row.sourceFiles).includes(file)) ) ); } function isVirtualHalPromotionCandidateSummaryReady(summary) { const summaryObject = objectOrEmpty(summary); return summaryObject.apiName === "real-browser-simulation-promotion-candidate-summary" && summaryObject.ready === true && summaryObject.phase === "ready" && summaryObject.candidateCount === 8 && summaryObject.readyCandidateCount === 8 && summaryObject.familyCount === 3 && summaryObject.sourceFileCount === 17 && summaryObject.preferredCandidateId === "qtdragon-multi-joint-on-abort" && summaryObject.preferredIniPath === "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/qtdragon_xyyz.ini" && summaryObject.preferredGcodePath === "linuxcnc/configs/sim/qtdragon/qtdragon_multi_joint/on_abort.ngc" && summaryObject.explicitBrowserDiagnosticsCount === 8 && summaryObject.inventoryBaseline === "executed=82 passed=82 skipped=77 unexpected_fail=0" && arrayOrEmpty(summaryObject.blockedCandidateIds).length === 0; } export function createProjectReleaseBrowserDiagnosticsArtifactValidation(artifact = {}) { const artifactObject = objectOrEmpty(artifact); const sourceCompliance = objectOrEmpty(artifactObject.virtualHalSourceCompliance); const simConfigSourceCoverage = objectOrEmpty(artifactObject.virtualHalSimConfigSourceCoverage); const commandScriptFixtures = objectOrEmpty(artifactObject.virtualHalCommandScriptFixtures); const motionControllerMatrix = objectOrEmpty(artifactObject.virtualHalMotionControllerMatrix); const promotionCandidates = objectOrEmpty(artifactObject.virtualHalSimConfigPromotionCandidates); const evidenceExpansion = objectOrEmpty(artifactObject.virtualHalSimConfigEvidenceExpansion); const promotionCandidateSummary = objectOrEmpty(artifactObject.virtualHalPromotionCandidateSummary); const macroLoadFixtures = objectOrEmpty(artifactObject.virtualHalSimConfigMacroLoadFixtures); const sessionDiagnostics = objectOrEmpty(artifactObject.virtualHalSessionDiagnostics); 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 motionControllerMatrixReady = isVirtualHalMotionControllerMatrixReady(motionControllerMatrix); const hasPromotionCandidates = artifactObject.virtualHalSimConfigPromotionCandidates !== undefined; const promotionCandidatesReady = !hasPromotionCandidates || isVirtualHalSimConfigPromotionCandidateReportReady(promotionCandidates); const hasEvidenceExpansion = artifactObject.virtualHalSimConfigEvidenceExpansion !== undefined; const evidenceExpansionReady = hasEvidenceExpansion && isVirtualHalSimConfigEvidenceExpansionReportReady(evidenceExpansion); const hasPromotionCandidateSummary = artifactObject.virtualHalPromotionCandidateSummary !== undefined; const promotionCandidateSummaryReady = hasPromotionCandidateSummary && isVirtualHalPromotionCandidateSummaryReady(promotionCandidateSummary); const hasMacroLoadFixtures = artifactObject.virtualHalSimConfigMacroLoadFixtures !== undefined; const macroLoadFixturesReady = hasMacroLoadFixtures && isVirtualHalSimConfigMacroLoadFixtureReportReady(macroLoadFixtures); const replacementReady = replacement.ready === true && replacement.replacesHostRuntimeForSimulation === true && objectOrEmpty(replacement.sourceCompliance).webSimulationSatisfied === true && objectOrEmpty(replacement.motionControllerMatrix).complete === true; const virtualHalReady = virtualHal.source === "browser-virtual-hal"; const hasSessionDiagnostics = artifactObject.virtualHalSessionDiagnostics !== undefined; const sessionDiagnosticsReady = !hasSessionDiagnostics || ( sessionDiagnostics.apiName === "real-browser-simulation-virtual-hal-session-diagnostics" && sessionDiagnostics.ready === true && sessionDiagnostics.phase === "release-ready" && objectOrEmpty(sessionDiagnostics.validation).ready === true && objectOrEmpty(sessionDiagnostics.diagnosticsArtifact).apiName === "real-browser-simulation-diagnostics-artifact" && objectOrEmpty(sessionDiagnostics.diagnosticsArtifact?.virtualHalSourceCompliance).complete === true && objectOrEmpty(sessionDiagnostics.diagnosticsArtifact?.virtualHalMotionControllerMatrix).manifestChecked === true ); const missing = [ ...(artifactObject.apiName === "real-browser-simulation-diagnostics-artifact" ? [] : ["apiName"]), ...(virtualHalReady ? [] : ["virtualHal"]), ...(replacementReady ? [] : ["virtualHalSimulationReplacement"]), ...(sourceComplianceReady ? [] : ["virtualHalSourceCompliance"]), ...(simConfigSourceCoverageReady ? [] : ["virtualHalSimConfigSourceCoverage"]), ...(promotionCandidatesReady ? [] : ["virtualHalSimConfigPromotionCandidates"]), ...(evidenceExpansionReady ? [] : ["virtualHalSimConfigEvidenceExpansion"]), ...(promotionCandidateSummaryReady ? [] : ["virtualHalPromotionCandidateSummary"]), ...(macroLoadFixturesReady ? [] : ["virtualHalSimConfigMacroLoadFixtures"]), ...(commandScriptFixturesReady ? [] : ["virtualHalCommandScriptFixtures"]), ...(motionControllerMatrixReady ? [] : ["virtualHalMotionControllerMatrix"]), ...(sessionDiagnosticsReady ? [] : ["virtualHalSessionDiagnostics"]), ]; 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, promotionCandidatesReady, hasPromotionCandidates, evidenceExpansionReady, hasEvidenceExpansion, promotionCandidateSummaryReady, hasPromotionCandidateSummary, macroLoadFixturesReady, hasMacroLoadFixtures, commandScriptFixturesReady, motionControllerMatrixReady, sessionDiagnosticsReady, hasSessionDiagnostics, sourceFiles: [...new Set([ ...arrayOrEmpty(sourceCompliance.sourceFiles), ...arrayOrEmpty(simConfigSourceCoverage.sourceFiles), ...arrayOrEmpty(promotionCandidates.sourceFiles), ...arrayOrEmpty(evidenceExpansion.sourceFiles), ...arrayOrEmpty(macroLoadFixtures.sourceFiles), ...arrayOrEmpty(commandScriptFixtures.sourceFiles), ...arrayOrEmpty(motionControllerMatrix.sourceFiles), ...arrayOrEmpty(motionControllerMatrix.simConfigSourceFiles), ])], 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: "sim-config-promotion-candidates", label: "Virtual HAL sim-config promotion candidates", value: hasPromotionCandidates ? (promotionCandidatesReady ? "ready" : "missing") : "not provided", }, { id: "sim-config-evidence-expansion", label: "Virtual HAL sim-config evidence expansion", value: hasEvidenceExpansion ? (evidenceExpansionReady ? "ready" : "missing") : "not provided", }, { id: "promotion-candidate-summary", label: "Virtual HAL promotion candidate summary", value: hasPromotionCandidateSummary ? (promotionCandidateSummaryReady ? "ready" : "missing") : "not provided", }, { id: "sim-config-macro-load-fixtures", label: "Virtual HAL sim-config macro/load fixtures", value: hasMacroLoadFixtures ? (macroLoadFixturesReady ? "ready" : "missing") : "not provided", }, { id: "command-script-fixtures", label: "Virtual HAL command script fixtures", value: commandScriptFixturesReady ? "ready" : "missing", }, { id: "motion-controller-matrix", label: "Virtual HAL motion controller matrix", value: motionControllerMatrixReady ? "ready" : "missing", }, { id: "session-diagnostics", label: "Saved-session diagnostics", value: hasSessionDiagnostics ? (sessionDiagnosticsReady ? "ready" : "missing") : "not provided", }, { 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)); } function readGatePassed({ gate, gateResults, observedOutputs }) { if (gateResults?.[gate.id] === true) { return true; } if (gate.expectedOutput && outputContains(observedOutputs, gate.expectedOutput)) { return true; } return false; } function objectOrEmpty(value) { return value && typeof value === "object" ? value : {}; } function arrayOrEmpty(value) { return Array.isArray(value) ? value : []; } function normalizeObservedOutput(value) { if (Array.isArray(value)) { return value.map((output) => String(output)); } if (typeof value === "string") { return [value]; } return []; } function normalizeAxisScreenshotArtifacts(value) { return arrayOrEmpty(value) .map((artifact) => objectOrEmpty(artifact)) .filter(({ apiName }) => apiName === "real-browser-simulation-axis-screenshot-artifact") .map((artifact) => ({ apiName: artifact.apiName, artifactVersion: artifact.artifactVersion ?? 1, viewportName: artifact.viewportName ?? "unknown", windowSize: artifact.windowSize ?? "unknown", query: artifact.query ?? "", screenshotBytes: Number.isFinite(artifact.screenshotBytes) ? artifact.screenshotBytes : 0, validatedBy: artifact.validatedBy ?? "unknown", fullDiagnosticsApiName: artifact.fullDiagnosticsApiName ?? null, fullDiagnosticsPath: artifact.fullDiagnosticsPath ?? null, previewRenderer: artifact.previewRenderer ?? null, previewViewMode: artifact.previewViewMode ?? null, threeReady: artifact.threeReady === true, threePathPoints: Number.isFinite(artifact.threePathPoints) ? artifact.threePathPoints : 0, screenshotPath: artifact.screenshotPath ?? null, diagnosticsPath: artifact.diagnosticsPath ?? null, })); } function createAxisScreenshotArtifactSummary(axisScreenshotArtifacts = []) { const artifacts = normalizeAxisScreenshotArtifacts(axisScreenshotArtifacts); const expectedViewports = ["desktop-preview", "desktop-dro", "mobile-preview", "mobile-mdi"]; const viewportNames = artifacts.map(({ viewportName }) => viewportName); const missingViewports = expectedViewports.filter((name) => !viewportNames.includes(name)); const undersizedViewports = artifacts .filter(({ screenshotBytes }) => screenshotBytes < 10000) .map(({ viewportName }) => viewportName); const ready = artifacts.length === 0 || (missingViewports.length === 0 && undersizedViewports.length === 0); return { apiName: "project-release-axis-screenshot-artifact-summary", summaryVersion: 1, phase: ready ? "ready" : "blocked", ready, expectedViewports, artifactCount: artifacts.length, viewportNames, missingViewports, undersizedViewports, totalScreenshotBytes: artifacts.reduce((sum, { screenshotBytes }) => sum + screenshotBytes, 0), artifacts, }; } export function createProjectReleaseGateManifest() { return { apiName: "project-release-gate-manifest", manifestVersion: 1, gateCount: REQUIRED_RELEASE_GATES.length, gateIds: REQUIRED_RELEASE_GATES.map(({ id }) => id), gates: REQUIRED_RELEASE_GATES.map((gate) => ({ id: gate.id, label: gate.label, command: gate.command, expectedOutput: gate.expectedOutput ?? null, })), }; } export function createProjectReleaseGateExecutionManifest({ gateResults = {}, observedOutputs = [], gateObservedOutputs = {}, manifest = createProjectReleaseGateManifest(), } = {}) { const globalOutputs = normalizeObservedOutput(observedOutputs); const gates = arrayOrEmpty(manifest?.gates); const rows = gates.map((gate) => { const scopedOutputs = [ ...normalizeObservedOutput(gateObservedOutputs?.[gate.id]), ...globalOutputs, ]; const matchedOutput = gate.expectedOutput ? scopedOutputs.find((output) => output.includes(gate.expectedOutput)) ?? null : null; const explicitPassed = gateResults?.[gate.id] === true; const passed = explicitPassed || matchedOutput !== null; return { id: gate.id, label: gate.label, command: gate.command, expectedOutput: gate.expectedOutput ?? null, observedOutput: matchedOutput, observedOutputCount: scopedOutputs.length, status: passed ? "passed" : "unknown", passed, evidence: matchedOutput !== null ? "expected-output" : (explicitPassed ? "explicit-result" : "missing"), }; }); return { apiName: "project-release-gate-execution-manifest", manifestVersion: 1, phase: rows.every(({ passed }) => passed) ? "ready" : "waiting", ready: rows.every(({ passed }) => passed), gateCount: rows.length, passedCount: rows.filter(({ passed }) => passed).length, unknownCount: rows.filter(({ passed }) => !passed).length, missingGateIds: rows.filter(({ passed }) => !passed).map(({ id }) => id), manifest, rows, }; } export function createProjectReleaseGateExecutionSummaryViewModel( executionManifest = createProjectReleaseGateExecutionManifest(), ) { const rows = arrayOrEmpty(executionManifest?.rows); const ready = executionManifest?.ready === true; const missingGateIds = arrayOrEmpty(executionManifest?.missingGateIds); const statusText = ready ? "Ready" : "Waiting"; const detailText = ready ? "All release gate evidence present" : (missingGateIds.length > 0 ? missingGateIds.join(", ") : "release gate evidence missing"); const evidenceCounts = rows.reduce((counts, row) => ({ ...counts, [row.evidence ?? "missing"]: (counts[row.evidence ?? "missing"] ?? 0) + 1, }), {}); return { apiName: "project-release-gate-execution-summary-view-model", viewModelVersion: 1, phase: ready ? "ready" : "waiting", ready, title: "Project release gate execution", statusText, detailText, statusLine: `${statusText}: ${detailText}`, gateCount: executionManifest?.gateCount ?? rows.length, passedCount: executionManifest?.passedCount ?? rows.filter(({ passed }) => passed === true).length, unknownCount: executionManifest?.unknownCount ?? rows.filter(({ passed }) => passed !== true).length, missingGateIds, nextGateId: missingGateIds[0] ?? null, evidenceCounts, rows: [ { id: "gate-results", label: "Release gate evidence", value: `${executionManifest?.passedCount ?? 0}/${executionManifest?.gateCount ?? rows.length} passed`, }, { id: "unknown-gates", label: "Unknown gates", value: `${executionManifest?.unknownCount ?? 0}`, }, { id: "next-gate", label: "Next gate", value: missingGateIds[0] ?? "none", }, { id: "expected-output-evidence", label: "Expected-output evidence", value: `${evidenceCounts["expected-output"] ?? 0}`, }, { id: "explicit-result-evidence", label: "Explicit-result evidence", value: `${evidenceCounts["explicit-result"] ?? 0}`, }, { id: "missing", label: "Missing gate evidence", value: missingGateIds.length > 0 ? missingGateIds.join(", ") : "none", }, ], gateRows: rows.map((row) => ({ id: row.id, label: row.label, command: row.command, expectedOutput: row.expectedOutput ?? null, observedOutput: row.observedOutput ?? null, evidence: row.evidence ?? "missing", status: row.status ?? (row.passed === true ? "passed" : "unknown"), passed: row.passed === true, })), }; } export function createProjectReleaseGateResultMatrix({ gateResults = {}, observedOutputs = [], manifest = createProjectReleaseGateManifest(), } = {}) { const outputs = Array.isArray(observedOutputs) ? observedOutputs : []; const gates = Array.isArray(manifest?.gates) ? manifest.gates : []; const rows = gates.map((gate) => { const passed = readGatePassed({ gate, gateResults, observedOutputs: outputs }); return { id: gate.id, label: gate.label, command: gate.command, expectedOutput: gate.expectedOutput ?? null, status: passed ? "passed" : "unknown", passed, }; }); return { apiName: "project-release-gate-result-matrix", matrixVersion: 1, phase: rows.every(({ passed }) => passed) ? "ready" : "waiting", ready: rows.every(({ passed }) => passed), gateCount: rows.length, passedCount: rows.filter(({ passed }) => passed).length, unknownCount: rows.filter(({ passed }) => !passed).length, missingGateIds: rows.filter(({ passed }) => !passed).map(({ id }) => id), manifest, rows, }; } export function createProjectReleaseGateActionPlan({ gateResultMatrix = null, gateResults = {}, observedOutputs = [], manifest = createProjectReleaseGateManifest(), } = {}) { const matrix = gateResultMatrix && typeof gateResultMatrix === "object" ? gateResultMatrix : createProjectReleaseGateResultMatrix({ gateResults, observedOutputs, manifest }); const rows = Array.isArray(matrix.rows) ? matrix.rows : []; const pendingRows = rows.filter(({ passed }) => passed !== true); const completedRows = rows.filter(({ passed }) => passed === true); const commands = pendingRows.map((gate, index) => ({ step: index + 1, gateId: gate.id, label: gate.label, command: gate.command, expectedOutput: gate.expectedOutput ?? null, })); const nextGate = commands[0] ?? null; const shellScript = commands.length > 0 ? [ "#!/usr/bin/env bash", "set -euo pipefail", "", ...commands.map(({ command }) => command), "", ].join("\n") : "# Project release gates are already marked passed.\n"; return { apiName: "project-release-gate-action-plan", planVersion: 1, phase: commands.length === 0 ? "ready" : "waiting", ready: commands.length === 0, gateCount: rows.length, completedCount: completedRows.length, pendingCount: pendingRows.length, completedGateIds: completedRows.map(({ id }) => id), pendingGateIds: pendingRows.map(({ id }) => id), nextGateId: nextGate?.gateId ?? null, nextCommand: nextGate?.command ?? null, commands, shellScript, rows: commands.map(({ gateId, label, command, expectedOutput }) => ({ id: gateId, label, value: command, expectedOutput, })), }; } const BATCH_ACCEPTANCE_CAPABILITY_TYPES = [ "api", "workflow", "gate", "browser", ]; function normalizeBatchCapabilities(capabilities) { return arrayOrEmpty(capabilities) .map((capability) => objectOrEmpty(capability)) .filter(({ id, type }) => typeof id === "string" && typeof type === "string") .map((capability) => ({ id: capability.id, type: capability.type, label: capability.label ?? capability.id, evidence: capability.evidence ?? null, command: capability.command ?? null, })); } export function createProjectBatchAcceptanceCapabilityMatrix({ capabilities = [], } = {}) { const normalizedCapabilities = normalizeBatchCapabilities(capabilities); const acceptedCapabilities = normalizedCapabilities.filter(({ type }) => BATCH_ACCEPTANCE_CAPABILITY_TYPES.includes(type) ); const rejectedCapabilities = normalizedCapabilities.filter(({ type }) => !BATCH_ACCEPTANCE_CAPABILITY_TYPES.includes(type) ); const capabilityTypes = [...new Set(acceptedCapabilities.map(({ type }) => type))]; const countsByType = BATCH_ACCEPTANCE_CAPABILITY_TYPES.reduce((counts, type) => ({ ...counts, [type]: acceptedCapabilities.filter((capability) => capability.type === type).length, }), {}); const missing = acceptedCapabilities.length > 0 ? [] : ["batch-capability"]; return { apiName: "project-batch-acceptance-capability-matrix", matrixVersion: 1, phase: missing.length === 0 ? "ready" : "blocked", ready: missing.length === 0, acceptedCapabilityTypes: BATCH_ACCEPTANCE_CAPABILITY_TYPES, capabilityTypes, capabilityCount: acceptedCapabilities.length, acceptedCount: acceptedCapabilities.length, rejectedCount: rejectedCapabilities.length, countsByType, capabilities: acceptedCapabilities, rejectedCapabilities, missing, rows: [ { id: "accepted-capabilities", label: "Accepted capabilities", value: `${acceptedCapabilities.length}`, }, { id: "accepted-types", label: "Accepted capability types", value: capabilityTypes.join(", ") || "none", }, { id: "rejected-capabilities", label: "Rejected capabilities", value: `${rejectedCapabilities.length}`, }, { id: "missing", label: "Missing capability evidence", value: missing.length > 0 ? missing.join(", ") : "none", }, ], }; } export function createProjectBatchAcceptanceWorkflow({ batchId = "current-batch", capabilities = [], gateResults = {}, observedOutputs = [], virtualHalSimConfigSourceCoverage = null, virtualHalMotionControllerMatrix = null, } = {}) { const capabilityMatrix = createProjectBatchAcceptanceCapabilityMatrix({ capabilities }); const gateManifest = createProjectReleaseGateManifest(); const gateResultMatrix = createProjectReleaseGateResultMatrix({ gateResults, observedOutputs, manifest: gateManifest, }); const batchGatePassed = gateResultMatrix.rows .find(({ id }) => id === "project-batch-acceptance")?.passed === true; const virtualHalSimConfigSourceCoverageReady = virtualHalSimConfigSourceCoverage === null || isVirtualHalSimConfigSourceCoverageReady(virtualHalSimConfigSourceCoverage); const virtualHalMotionControllerMatrixReady = virtualHalMotionControllerMatrix === null || isVirtualHalMotionControllerMatrixReady(virtualHalMotionControllerMatrix); const ready = capabilityMatrix.ready && batchGatePassed && virtualHalSimConfigSourceCoverageReady && virtualHalMotionControllerMatrixReady; const missing = [ ...capabilityMatrix.missing, ...(batchGatePassed ? [] : ["project-batch-acceptance"]), ...(virtualHalSimConfigSourceCoverageReady ? [] : ["virtual-hal-sim-config-source-coverage"]), ...(virtualHalMotionControllerMatrixReady ? [] : ["virtual-hal-motion-controller-matrix"]), ]; return { apiName: "project-batch-acceptance-workflow", workflowVersion: 1, phase: ready ? "ready" : "blocked", ready, batchId, acceptedCapabilityTypes: capabilityMatrix.acceptedCapabilityTypes, capabilityTypes: capabilityMatrix.capabilityTypes, capabilityCount: capabilityMatrix.capabilityCount, capabilityMatrix, capabilities: capabilityMatrix.capabilities, rejectedCapabilities: capabilityMatrix.rejectedCapabilities, virtualHalSimConfigSourceCoverage, virtualHalSimConfigSourceCoverageReady, virtualHalMotionControllerMatrix, virtualHalMotionControllerMatrixReady, gateResultMatrix, missing, rows: [ { id: "batch", label: "Batch", value: batchId, }, { id: "capabilities", label: "Accepted capabilities", value: capabilityMatrix.capabilityTypes.join(", ") || "none", }, { id: "project-batch-acceptance", 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: "virtual-hal-motion-controller-matrix", label: "Virtual HAL motion controller matrix", value: virtualHalMotionControllerMatrix === null ? "not required" : (virtualHalMotionControllerMatrixReady ? "ready" : "missing"), }, { id: "missing", label: "Missing acceptance evidence", value: missing.length > 0 ? missing.join(", ") : "none", }, ], }; } export function createProjectBatchAcceptanceSummaryViewModel( workflow = createProjectBatchAcceptanceWorkflow(), ) { const missing = arrayOrEmpty(workflow?.missing); const ready = workflow?.ready === true; const statusText = ready ? "Ready" : "Blocked"; const detailText = ready ? "Batch acceptance evidence complete" : (missing.length > 0 ? missing.join(", ") : "batch acceptance evidence missing"); return { apiName: "project-batch-acceptance-summary-view-model", viewModelVersion: 1, phase: ready ? "ready" : "blocked", ready, title: "Project batch acceptance", statusText, detailText, statusLine: `${statusText}: ${detailText}`, rows: [ { id: "batch", label: "Batch", value: workflow?.batchId ?? "current-batch", }, { id: "capability-count", label: "Accepted capability count", value: `${workflow?.capabilityCount ?? 0}`, }, { id: "capability-types", label: "Accepted capability types", value: arrayOrEmpty(workflow?.capabilityTypes).join(", ") || "none", }, { id: "missing", label: "Missing acceptance evidence", value: missing.length > 0 ? missing.join(", ") : "none", }, ], }; } export function createProjectBatchAcceptanceActionPlan( workflow = createProjectBatchAcceptanceWorkflow(), ) { const missing = arrayOrEmpty(workflow?.missing); const ready = workflow?.ready === true; const commands = ready ? [] : [ ...(missing.includes("project-batch-acceptance") ? [{ step: 1, id: "project-batch-acceptance", label: "Run project batch acceptance workflow smoke", command: "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh", expectedOutput: "project_batch_acceptance_workflow_node_smoke=ok", }] : []), ]; const shellScript = commands.length > 0 ? [ "#!/usr/bin/env bash", "set -euo pipefail", "", ...commands.map(({ command }) => command), "", ].join("\n") : (ready ? "# Project batch acceptance workflow is already ready.\n" : "# Project batch acceptance workflow requires at least one API, workflow, gate, or browser capability.\n"); return { apiName: "project-batch-acceptance-action-plan", planVersion: 1, phase: ready ? "ready" : "blocked", ready, missing, commandCount: commands.length, nextActionId: commands[0]?.id ?? (missing[0] ?? null), nextCommand: commands[0]?.command ?? null, commands, shellScript, rows: [ { id: "batch-acceptance", label: "Batch acceptance", value: ready ? "ready" : "blocked", }, { id: "missing", label: "Missing acceptance evidence", value: missing.length > 0 ? missing.join(", ") : "none", }, { id: "next-command", label: "Next command", value: commands[0]?.command ?? "none", }, ], }; } export function createProjectBatchAcceptanceChecklist({ workflow = createProjectBatchAcceptanceWorkflow(), actionPlan = createProjectBatchAcceptanceActionPlan(workflow), } = {}) { const capabilityMatrix = objectOrEmpty(workflow?.capabilityMatrix); const ready = workflow?.ready === true; const items = [ { id: "accepted-capability", label: "At least one API, workflow, gate, or browser capability", status: capabilityMatrix.ready === true ? "pass" : "blocked", passed: capabilityMatrix.ready === true, detail: arrayOrEmpty(workflow?.capabilityTypes).join(", ") || "none", }, { id: "batch-acceptance-gate", label: "Batch acceptance gate evidence", status: !arrayOrEmpty(workflow?.missing).includes("project-batch-acceptance") ? "pass" : "blocked", passed: !arrayOrEmpty(workflow?.missing).includes("project-batch-acceptance"), 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: "virtual-hal-motion-controller-matrix", label: "Virtual HAL motion controller matrix", status: workflow?.virtualHalMotionControllerMatrixReady !== false ? "pass" : "blocked", passed: workflow?.virtualHalMotionControllerMatrixReady !== false, detail: workflow?.virtualHalMotionControllerMatrix === null ? "not required" : (workflow?.virtualHalMotionControllerMatrixReady === true ? "ready" : "missing"), }, { id: "next-action", label: "Next acceptance action", status: actionPlan?.nextActionId ? "blocked" : "pass", passed: !actionPlan?.nextActionId, detail: actionPlan?.nextCommand ?? "none", }, ]; return { apiName: "project-batch-acceptance-checklist", checklistVersion: 1, phase: ready ? "ready" : "blocked", ready, batchId: workflow?.batchId ?? "current-batch", passedCount: items.filter(({ passed }) => passed).length, blockedCount: items.filter(({ passed }) => !passed).length, items, rows: items.map(({ id, label, status, detail }) => ({ id, label, value: `${status}: ${detail}`, })), }; } export function createProjectBatchAcceptanceReport({ batchId = "current-batch", capabilities = [], gateResults = {}, observedOutputs = [], virtualHalSimConfigSourceCoverage = null, virtualHalMotionControllerMatrix = null, } = {}) { const capabilityMatrix = createProjectBatchAcceptanceCapabilityMatrix({ capabilities }); const workflow = createProjectBatchAcceptanceWorkflow({ batchId, capabilities, gateResults, observedOutputs, virtualHalSimConfigSourceCoverage, virtualHalMotionControllerMatrix, }); const summaryViewModel = createProjectBatchAcceptanceSummaryViewModel(workflow); const actionPlan = createProjectBatchAcceptanceActionPlan(workflow); const checklist = createProjectBatchAcceptanceChecklist({ workflow, actionPlan }); return { apiName: "project-batch-acceptance-report", reportVersion: 1, phase: workflow.phase, ready: workflow.ready, batchId: workflow.batchId, missing: [...workflow.missing], capabilityMatrix, workflow, virtualHalSimConfigSourceCoverage, virtualHalMotionControllerMatrix, summaryViewModel, actionPlan, checklist, rows: [ { id: "summary", label: "Batch acceptance summary", value: summaryViewModel.statusLine, }, { id: "capabilities", label: "Accepted capabilities", value: capabilityMatrix.capabilityTypes.join(", ") || "none", }, { id: "checklist", label: "Checklist", value: `${checklist.passedCount}/${checklist.items.length} passed`, }, { id: "next-command", label: "Next command", value: actionPlan.nextCommand ?? "none", }, ], }; } export function createProjectBatchAcceptanceReportValidation(report = {}) { const reportObject = objectOrEmpty(report); const capabilityMatrix = objectOrEmpty(reportObject.capabilityMatrix); const workflow = objectOrEmpty(reportObject.workflow); const summaryViewModel = objectOrEmpty(reportObject.summaryViewModel); const actionPlan = objectOrEmpty(reportObject.actionPlan); const checklist = objectOrEmpty(reportObject.checklist); const virtualHalSimConfigSourceCoverage = objectOrEmpty(reportObject.virtualHalSimConfigSourceCoverage); const virtualHalMotionControllerMatrix = objectOrEmpty(reportObject.virtualHalMotionControllerMatrix); const rows = arrayOrEmpty(reportObject.rows); const virtualHalSimConfigSourceCoverageRequired = reportObject.virtualHalSimConfigSourceCoverage !== null && reportObject.virtualHalSimConfigSourceCoverage !== undefined; const virtualHalSimConfigSourceCoverageReady = !virtualHalSimConfigSourceCoverageRequired || isVirtualHalSimConfigSourceCoverageReady(virtualHalSimConfigSourceCoverage); const virtualHalMotionControllerMatrixRequired = reportObject.virtualHalMotionControllerMatrix !== null && reportObject.virtualHalMotionControllerMatrix !== undefined; const virtualHalMotionControllerMatrixReady = !virtualHalMotionControllerMatrixRequired || isVirtualHalMotionControllerMatrixReady(virtualHalMotionControllerMatrix); const missing = [ ...(reportObject.apiName === "project-batch-acceptance-report" ? [] : ["apiName"]), ...(reportObject.reportVersion === 1 ? [] : ["reportVersion"]), ...(reportObject.phase === "ready" ? [] : ["phase"]), ...(reportObject.ready === true ? [] : ["ready"]), ...(Array.isArray(reportObject.missing) && reportObject.missing.length === 0 ? [] : ["missing"]), ...(capabilityMatrix.apiName === "project-batch-acceptance-capability-matrix" && capabilityMatrix.ready === true ? [] : ["capabilityMatrix"]), ...(workflow.apiName === "project-batch-acceptance-workflow" && workflow.ready === true ? [] : ["workflow"]), ...(summaryViewModel.apiName === "project-batch-acceptance-summary-view-model" && summaryViewModel.ready === true ? [] : ["summaryViewModel"]), ...(actionPlan.apiName === "project-batch-acceptance-action-plan" && actionPlan.ready === true ? [] : ["actionPlan"]), ...(checklist.apiName === "project-batch-acceptance-checklist" && checklist.ready === true ? [] : ["checklist"]), ...(virtualHalSimConfigSourceCoverageReady ? [] : ["virtualHalSimConfigSourceCoverage"]), ...(virtualHalMotionControllerMatrixReady ? [] : ["virtualHalMotionControllerMatrix"]), ...(rows.find(({ id, value }) => id === "checklist" && /^([45])\/\1 passed$/.test(value)) ? [] : ["rows.checklist"]), ]; return { apiName: "project-batch-acceptance-report-validation", validationVersion: 1, phase: missing.length === 0 ? "ready" : "blocked", ready: missing.length === 0, missing, batchId: reportObject.batchId ?? null, reportApiName: reportObject.apiName ?? null, reportVersion: reportObject.reportVersion ?? null, virtualHalSimConfigSourceCoverageReady, virtualHalMotionControllerMatrixReady, rows: [ { id: "report", label: "Batch acceptance report", value: reportObject.apiName ?? "missing", }, { id: "capability-matrix", label: "Capability matrix", value: capabilityMatrix.ready === true ? "ready" : "missing", }, { id: "workflow", label: "Batch workflow", value: workflow.ready === true ? "ready" : "missing", }, { id: "checklist", 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: "virtual-hal-motion-controller-matrix", label: "Virtual HAL motion controller matrix", value: virtualHalMotionControllerMatrixRequired ? (virtualHalMotionControllerMatrixReady ? "ready" : "missing") : "not required", }, { id: "missing", label: "Missing report evidence", value: missing.length > 0 ? missing.join(", ") : "none", }, ], }; } export function createProjectBatchAcceptanceReportValidationSummaryViewModel( validation = createProjectBatchAcceptanceReportValidation(), ) { const missing = arrayOrEmpty(validation?.missing); const ready = validation?.ready === true; const statusText = ready ? "Ready" : "Blocked"; const detailText = ready ? "Batch acceptance report evidence complete" : (missing.length > 0 ? missing.join(", ") : "batch acceptance report evidence missing"); return { apiName: "project-batch-acceptance-report-validation-summary-view-model", viewModelVersion: 1, phase: ready ? "ready" : "blocked", ready, title: "Project batch acceptance report validation", statusText, detailText, statusLine: `${statusText}: ${detailText}`, rows: [ { id: "report", label: "Batch acceptance report", value: validation?.reportApiName ?? "missing", }, { id: "batch", label: "Batch", value: validation?.batchId ?? "missing", }, { id: "validation", label: "Report validation", value: ready ? "ready" : "blocked", }, { id: "missing", label: "Missing report evidence", value: missing.length > 0 ? missing.join(", ") : "none", }, ], }; } export function createProjectBatchAcceptanceReportValidationActionPlan( validation = createProjectBatchAcceptanceReportValidation(), ) { const missing = arrayOrEmpty(validation?.missing); const ready = validation?.ready === true; const commands = ready ? [] : [ { step: 1, id: "project-batch-acceptance", label: "Run project batch acceptance workflow and artifact gate", command: "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh", expectedOutput: "project_batch_acceptance_artifact_node_smoke=ok", }, ]; const shellScript = commands.length > 0 ? [ "#!/usr/bin/env bash", "set -euo pipefail", "", ...commands.map(({ command }) => command), "", ].join("\n") : "# Project batch acceptance report validation is already ready.\n"; return { apiName: "project-batch-acceptance-report-validation-action-plan", planVersion: 1, phase: ready ? "ready" : "blocked", ready, missing, missingCount: missing.length, commandCount: commands.length, nextActionId: commands[0]?.id ?? null, nextCommand: commands[0]?.command ?? null, commands, shellScript, rows: [ { id: "report-validation", label: "Report validation", value: ready ? "ready" : "blocked", }, { id: "missing", label: "Missing report evidence", value: missing.length > 0 ? missing.join(", ") : "none", }, { id: "next-command", label: "Next command", value: commands[0]?.command ?? "none", }, ], }; } export function createProjectBatchAcceptanceReportJsonWorkflow({ reportJson = "" } = {}) { try { const report = JSON.parse(String(reportJson)); const validation = createProjectBatchAcceptanceReportValidation(report); return { apiName: "project-batch-acceptance-report-json-workflow", workflowVersion: 1, phase: validation.ready ? "ready" : "blocked", ready: validation.ready, parsed: true, parseError: null, report, validation, missing: validation.missing, rows: [ { id: "parse", label: "Batch report JSON parse", value: "ready", }, { id: "validation", label: "Batch report validation", value: validation.ready ? "ready" : "blocked", }, { id: "missing", label: "Missing report evidence", value: validation.missing.length > 0 ? validation.missing.join(", ") : "none", }, ], }; } catch (error) { const validation = createProjectBatchAcceptanceReportValidation({}); return { apiName: "project-batch-acceptance-report-json-workflow", workflowVersion: 1, phase: "blocked", ready: false, parsed: false, parseError: error?.message ?? "batch acceptance report JSON parse error", report: null, validation, missing: ["report-json", ...validation.missing], rows: [ { id: "parse", label: "Batch report JSON parse", value: "blocked", }, { id: "validation", label: "Batch report validation", value: "blocked", }, { id: "missing", label: "Missing report evidence", value: ["report-json", ...validation.missing].join(", "), }, ], }; } } export async function loadProjectBatchAcceptanceReportUrlWorkflow({ reportUrl = "", fetchRef = globalThis.fetch, } = {}) { if (!reportUrl || typeof fetchRef !== "function") { const jsonWorkflow = createProjectBatchAcceptanceReportJsonWorkflow({ reportJson: "" }); const missing = [ ...(reportUrl ? [] : ["report-url"]), ...(typeof fetchRef === "function" ? [] : ["fetch"]), ...jsonWorkflow.missing, ]; return { apiName: "project-batch-acceptance-report-url-workflow", workflowVersion: 1, phase: "blocked", ready: false, reportUrl, fetched: false, httpStatus: null, fetchError: null, jsonWorkflow, validation: jsonWorkflow.validation, missing, rows: [ { id: "fetch", label: "Batch report URL fetch", value: "blocked", }, { id: "json-workflow", label: "Batch report JSON workflow", value: "blocked", }, { id: "missing", label: "Missing report evidence", value: missing.join(", "), }, ], }; } try { const response = await fetchRef(reportUrl); const httpStatus = response?.status ?? null; if (!response?.ok) { const jsonWorkflow = createProjectBatchAcceptanceReportJsonWorkflow({ reportJson: "" }); const fetchError = `batch report URL fetch failed${httpStatus ? `: ${httpStatus}` : ""}`; return { apiName: "project-batch-acceptance-report-url-workflow", workflowVersion: 1, phase: "blocked", ready: false, reportUrl, fetched: false, httpStatus, fetchError, jsonWorkflow, validation: jsonWorkflow.validation, missing: ["report-fetch", ...jsonWorkflow.missing], rows: [ { id: "fetch", label: "Batch report URL fetch", value: "blocked", }, { id: "json-workflow", label: "Batch report JSON workflow", value: "blocked", }, { id: "missing", label: "Missing report evidence", value: ["report-fetch", ...jsonWorkflow.missing].join(", "), }, ], }; } const reportJson = await response.text(); const jsonWorkflow = createProjectBatchAcceptanceReportJsonWorkflow({ reportJson }); return { apiName: "project-batch-acceptance-report-url-workflow", workflowVersion: 1, phase: jsonWorkflow.ready === true ? "ready" : "blocked", ready: jsonWorkflow.ready === true, reportUrl, fetched: true, httpStatus, fetchError: null, jsonWorkflow, validation: jsonWorkflow.validation, missing: jsonWorkflow.missing, rows: [ { id: "fetch", label: "Batch report URL fetch", value: "ready", }, { id: "json-workflow", label: "Batch report JSON workflow", value: jsonWorkflow.ready === true ? "ready" : "blocked", }, { id: "missing", label: "Missing report evidence", value: jsonWorkflow.missing.length > 0 ? jsonWorkflow.missing.join(", ") : "none", }, ], }; } catch (error) { const jsonWorkflow = createProjectBatchAcceptanceReportJsonWorkflow({ reportJson: "" }); return { apiName: "project-batch-acceptance-report-url-workflow", workflowVersion: 1, phase: "blocked", ready: false, reportUrl, fetched: false, httpStatus: null, fetchError: error?.message ?? "batch report URL fetch error", jsonWorkflow, validation: jsonWorkflow.validation, missing: ["report-fetch", ...jsonWorkflow.missing], rows: [ { id: "fetch", label: "Batch report URL fetch", value: "blocked", }, { id: "json-workflow", label: "Batch report JSON workflow", value: "blocked", }, { id: "missing", label: "Missing report evidence", value: ["report-fetch", ...jsonWorkflow.missing].join(", "), }, ], }; } } export function createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel( workflow = {}, ) { const missing = arrayOrEmpty(workflow?.missing); const ready = workflow?.ready === true; const statusText = ready ? "Ready" : "Blocked"; const detailText = ready ? "Batch report URL workflow complete" : (missing.length > 0 ? missing.join(", ") : workflow?.fetchError ?? "batch report URL workflow blocked"); return { apiName: "project-batch-acceptance-report-url-workflow-summary-view-model", viewModelVersion: 1, phase: ready ? "ready" : "blocked", ready, title: "Project batch acceptance report URL workflow", statusText, detailText, statusLine: `${statusText}: ${detailText}`, rows: [ { id: "report-url", label: "Report URL", value: workflow?.reportUrl || "missing", }, { id: "fetch", label: "Fetch", value: workflow?.fetched === true ? `ready${workflow?.httpStatus ? ` (${workflow.httpStatus})` : ""}` : "blocked", }, { id: "json-workflow", label: "JSON workflow", value: workflow?.jsonWorkflow?.ready === true ? "ready" : "blocked", }, { id: "report-validation", label: "Report validation", value: workflow?.validation?.ready === true ? "ready" : "blocked", }, { id: "missing", label: "Missing workflow evidence", value: missing.length > 0 ? missing.join(", ") : "none", }, ], }; } export function createProjectBatchAcceptanceReportUrlWorkflowActionPlan( workflow = {}, ) { const missing = arrayOrEmpty(workflow?.missing); const ready = workflow?.ready === true; const inputActions = [ ...(missing.includes("report-url") ? [{ id: "provide-report-url", label: "Provide project batch acceptance report URL", kind: "input", command: null, expectedOutput: null, }] : []), ...(missing.includes("fetch") ? [{ id: "provide-fetch", label: "Provide fetch implementation", kind: "input", command: null, expectedOutput: null, }] : []), ...(missing.includes("report-fetch") ? [{ id: "verify-report-url-fetch", label: "Verify project batch acceptance report URL fetch", kind: "fetch", command: null, expectedOutput: null, }] : []), ]; const commandActions = ready ? [] : [ { id: "project-batch-acceptance", label: "Run project batch acceptance workflow smoke", kind: "command", command: "wasm-port/tests/sdk/node/verify_project_batch_acceptance_workflow.sh", expectedOutput: "project_batch_acceptance_workflow_node_smoke=ok", }, ]; const actions = ready ? [] : [...inputActions, ...commandActions].map((action, index) => ({ step: index + 1, ...action, })); const commands = actions.filter(({ command }) => typeof command === "string" && command.length > 0); const shellScript = commands.length > 0 ? [ "#!/usr/bin/env bash", "set -euo pipefail", "", ...commands.map(({ command }) => command), "", ].join("\n") : (ready ? "# Project batch acceptance report URL workflow is already ready.\n" : "# Project batch acceptance report URL workflow requires non-shell input.\n"); return { apiName: "project-batch-acceptance-report-url-workflow-action-plan", planVersion: 1, phase: ready ? "ready" : "blocked", ready, missing, actionCount: actions.length, commandCount: commands.length, nextActionId: actions[0]?.id ?? null, nextCommand: commands[0]?.command ?? null, actions, commands, shellScript, rows: actions.map(({ id, label, kind, command, expectedOutput }) => ({ id, label, kind, value: command ?? kind, expectedOutput, })), }; } export function createProjectReleaseReadinessReport({ gateResults = {}, observedOutputs = [], simConfigInventory = DEFAULT_SIM_CONFIG_INVENTORY_BASELINE, virtualHalSimConfigSourceCoverage = null, virtualHalSimConfigPromotionCandidates = null, virtualHalSimConfigEvidenceExpansion = null, promotionCandidateRows = [], evidenceExpansionRows = [], virtualHalSimConfigMacroLoadFixtures = null, virtualHalMotionControllerMatrix = null, toolDbProcessProof = {}, pythonRemapRuntimeProof = {}, blockedRuntimeFamilies = BLOCKED_RUNTIME_FAMILIES, promotedRuntimeFamilies = [], axisScreenshotArtifacts = [], } = {}) { const gateManifest = createProjectReleaseGateManifest(); const gateExecutionManifest = createProjectReleaseGateExecutionManifest({ gateResults, observedOutputs, manifest: gateManifest, }); const gateExecutionSummaryViewModel = createProjectReleaseGateExecutionSummaryViewModel( gateExecutionManifest, ); const gateResultMatrix = createProjectReleaseGateResultMatrix({ gateResults, observedOutputs, manifest: gateManifest, }); const gateActionPlan = createProjectReleaseGateActionPlan({ gateResultMatrix, manifest: gateManifest, }); const gateRows = gateResultMatrix.rows; const releaseGatePassed = gateRows.find(({ id }) => id === "project-release-gate")?.passed === true; const inventory = { ...DEFAULT_SIM_CONFIG_INVENTORY_BASELINE, ...(simConfigInventory && typeof simConfigInventory === "object" ? simConfigInventory : {}), }; const blockedFamilies = [...blockedRuntimeFamilies]; const promotedFamilies = [...promotedRuntimeFamilies]; const promotedBlockedFamilies = promotedFamilies.filter((family) => blockedFamilies.includes(family)); const inventoryReady = inventory.unexpectedFail === 0; const virtualHalSimConfigSourceCoverageReady = isVirtualHalSimConfigSourceCoverageReady( virtualHalSimConfigSourceCoverage, ); const virtualHalSimConfigPromotionCandidatesReady = isVirtualHalSimConfigPromotionCandidateReportReady( virtualHalSimConfigPromotionCandidates, ); const virtualHalPromotionFamilySummary = createPromotionFamilySummaryText(virtualHalSimConfigPromotionCandidates); const virtualHalPromotionFamilyRows = createPromotionFamilySummaryRows(virtualHalSimConfigPromotionCandidates); const virtualHalSimConfigMacroLoadFixturesReady = isVirtualHalSimConfigMacroLoadFixtureReportReady( virtualHalSimConfigMacroLoadFixtures, ); const virtualHalMotionControllerMatrixReady = isVirtualHalMotionControllerMatrixReady( virtualHalMotionControllerMatrix, ); const blockedRuntimeReady = promotedBlockedFamilies.length === 0; const hardBlockRuntimeLockSummary = createHardBlockRuntimeLockSummary(blockedFamilies, promotedBlockedFamilies); const promotionCandidateArtifactSummary = createPromotionCandidateArtifactSummary({ candidateReport: virtualHalSimConfigPromotionCandidates, evidenceExpansionReport: virtualHalSimConfigEvidenceExpansion, inventory, blockedFamilies, promotedBlockedFamilies, promotionCandidateRows, evidenceExpansionRows, }); const axisScreenshotArtifactSummary = createAxisScreenshotArtifactSummary(axisScreenshotArtifacts); const axisScreenshotArtifactsReady = axisScreenshotArtifactSummary.ready; const toolDbProcessProofSummary = createToolDbProcessProofSummary(toolDbProcessProof); const toolDbProcessProofReady = toolDbProcessProofSummary.ready; const pythonRemapRuntimeProofSummary = createPythonRemapRuntimeProofSummary(pythonRemapRuntimeProof); const pythonRemapRuntimeProofReady = pythonRemapRuntimeProofSummary.ready; const ready = releaseGatePassed && inventoryReady && virtualHalSimConfigSourceCoverageReady && virtualHalSimConfigPromotionCandidatesReady && virtualHalSimConfigMacroLoadFixturesReady && virtualHalMotionControllerMatrixReady && toolDbProcessProofReady && pythonRemapRuntimeProofReady && blockedRuntimeReady && axisScreenshotArtifactsReady; const missing = [ ...(releaseGatePassed ? [] : ["project-release-gate"]), ...(inventoryReady ? [] : ["sim-config-inventory"]), ...(virtualHalSimConfigSourceCoverageReady ? [] : ["virtual-hal-sim-config-source-coverage"]), ...(virtualHalSimConfigPromotionCandidatesReady ? [] : ["virtual-hal-sim-config-promotion-candidates"]), ...(virtualHalSimConfigMacroLoadFixturesReady ? [] : ["virtual-hal-sim-config-macro-load-fixtures"]), ...(virtualHalMotionControllerMatrixReady ? [] : ["virtual-hal-motion-controller-matrix"]), ...(toolDbProcessProofReady ? [] : ["tool-db-process-proof"]), ...(pythonRemapRuntimeProofReady ? [] : ["python-remap-runtime-proof"]), ...(blockedRuntimeReady ? [] : ["blocked-runtime-families"]), ...(axisScreenshotArtifactsReady ? [] : ["axis-screenshot-artifacts"]), ]; return { apiName: PROJECT_RELEASE_READINESS_ARTIFACT_API, reportVersion: PROJECT_RELEASE_READINESS_ARTIFACT_VERSION, phase: ready ? "ready" : "waiting", ready, missing, releaseGate: { command: "wasm-port/tests/host/verify_project_release_gate.sh", passed: releaseGatePassed, expectedOutput: "project_release_gate=ok", }, simConfigInventory: inventory, virtualHalSimConfigSourceCoverage, virtualHalSimConfigSourceCoverageReady, virtualHalSimConfigPromotionCandidates, virtualHalSimConfigPromotionCandidatesReady, virtualHalSimConfigEvidenceExpansion, virtualHalPromotionFamilySummary, virtualHalPromotionFamilyRows, promotionCandidateArtifactSummary, virtualHalSimConfigMacroLoadFixtures, virtualHalSimConfigMacroLoadFixturesReady, virtualHalMotionControllerMatrix, virtualHalMotionControllerMatrixReady, toolDbProcessProofSummary, toolDbProcessProofReady, pythonRemapRuntimeProofSummary, pythonRemapRuntimeProofReady, blockedRuntimeFamilies: blockedFamilies, promotedRuntimeFamilies: promotedFamilies, promotedBlockedFamilies, axisScreenshotArtifactSummary, gateManifest, gateExecutionManifest, gateExecutionSummaryViewModel, gateResultMatrix, gateActionPlan, gates: gateRows, rows: [ { id: "project-release-gate", label: "Project release gate", value: releaseGatePassed ? "passed" : "unknown", }, { id: "sim-config-inventory", 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: "virtual-hal-sim-config-promotion-candidates", label: "Virtual HAL sim-config promotion candidates", value: virtualHalSimConfigPromotionCandidatesReady ? "ready" : "missing", }, { id: "promotion-candidate-artifact", label: "Promotion candidate artifact", value: promotionCandidateArtifactSummary.artifactPath, }, { id: "promotion-candidate-artifact-rows", label: "Promotion candidate artifact rows", value: `${promotionCandidateArtifactSummary.artifactRows.promotionCandidates}`, }, { id: "evidence-expansion-artifact-rows", label: "Evidence expansion artifact rows", value: `${promotionCandidateArtifactSummary.artifactRows.evidenceExpansion}`, }, { id: "promotion-candidate-layers", label: "Promotion candidate layers", value: `evidence-ready=${promotionCandidateArtifactSummary.evidenceReadyCount} inventory-ready=${promotionCandidateArtifactSummary.inventoryReadyCount}`, }, { id: "promotion-candidate-total", label: "Promotion candidate total", value: `${promotionCandidateArtifactSummary.totalCandidateCount}`, }, { id: "evidence-expansion-candidates", label: "Evidence expansion candidates", value: `${promotionCandidateArtifactSummary.evidenceExpansionCandidateCount}`, }, { id: "evidence-expansion-next-evidence", label: "Evidence expansion next evidence", value: promotionCandidateArtifactSummary.evidenceExpansion.nextEvidence, }, { id: "evidence-expansion-baseline-changing", label: "Evidence expansion baseline changing", value: promotionCandidateArtifactSummary.evidenceExpansion.baselineChanging ? "yes" : "no", }, { id: "evidence-expansion-artifact", label: "Evidence expansion artifact", value: promotionCandidateArtifactSummary.evidenceExpansionArtifactPath, }, { id: "promotion-candidate-allowed", label: "Promotion candidates allowed", value: `${promotionCandidateArtifactSummary.promotionAllowedCount}`, }, { id: "virtual-hal-promotion-families", label: "Virtual HAL promotion families", value: virtualHalPromotionFamilySummary, }, ...virtualHalPromotionFamilyRows.map((row) => ({ id: `virtual-hal-promotion-family-${row.id}`, label: `Promotion family ${row.label}`, value: row.value, sourceFiles: row.sourceFiles, })), { id: "virtual-hal-sim-config-macro-load-fixtures", label: "Virtual HAL sim-config macro/load fixtures", value: virtualHalSimConfigMacroLoadFixturesReady ? "ready" : "missing", }, { id: "virtual-hal-motion-controller-matrix", label: "Virtual HAL motion controller matrix", value: virtualHalMotionControllerMatrixReady ? "ready" : "missing", }, { id: "tool-db-process-proof", label: "Tool DB process proof", value: toolDbProcessProofReady ? "ready" : "missing", }, { id: "tool-db-process-proof-detail", label: "Tool DB process proof detail", value: `wasm=${toolDbProcessProofSummary.wasmProtocolReady ? "ready" : "missing"} browser=${toolDbProcessProofSummary.browserProtocolReady ? "ready" : "missing"} opfs=${toolDbProcessProofSummary.opfsPersistenceReady ? "ready" : "missing"} promotion_allowed=${toolDbProcessProofSummary.promotionAllowed ? "1" : "0"}`, }, { id: "python-remap-runtime-proof", label: "Python remap runtime proof", value: pythonRemapRuntimeProofReady ? "ready" : "locked", }, { id: "python-remap-runtime-proof-detail", label: "Python remap runtime proof detail", value: `native=${pythonRemapRuntimeProofSummary.nativeLifecycleReady ? "ready" : "missing"} wasm=${pythonRemapRuntimeProofSummary.wasmLifecycleReady ? "ready" : "missing"} browser=${pythonRemapRuntimeProofSummary.browserLifecycleReady ? "ready" : "missing"} promotion_allowed=${pythonRemapRuntimeProofSummary.promotionAllowed ? "1" : "0"}`, }, { id: "blocked-runtime-families", label: "Blocked runtime families", value: blockedRuntimeReady ? blockedFamilies.join(", ") : `promoted: ${promotedBlockedFamilies.join(", ")}`, }, { id: "hard-block-runtime-lock", label: "Hard-block runtime lock", value: hardBlockRuntimeLockSummary.lockValue, }, { id: "promoted-blocked-family-count", label: "Promoted blocked families", value: hardBlockRuntimeLockSummary.promotedCountValue, }, { id: "axis-screenshot-artifacts", label: "AXIS screenshot artifacts", value: axisScreenshotArtifactSummary.artifactCount > 0 ? `${axisScreenshotArtifactSummary.artifactCount}/${axisScreenshotArtifactSummary.expectedViewports.length} captured` : "not captured", }, ], }; } export function createProjectReleaseReadinessSummaryViewModel( report = createProjectReleaseReadinessReport(), ) { const missing = Array.isArray(report?.missing) ? report.missing : []; const gateResultMatrix = objectOrEmpty(report?.gateResultMatrix); const simConfigInventory = objectOrEmpty(report?.simConfigInventory); const virtualHalSimConfigSourceCoverageReady = report?.virtualHalSimConfigSourceCoverageReady === true; const virtualHalSimConfigPromotionCandidatesReady = report?.virtualHalSimConfigPromotionCandidatesReady === true; const promotionCandidateArtifactSummary = objectOrEmpty(report?.promotionCandidateArtifactSummary); const virtualHalSimConfigMacroLoadFixturesReady = report?.virtualHalSimConfigMacroLoadFixturesReady === true; const virtualHalMotionControllerMatrixReady = report?.virtualHalMotionControllerMatrixReady === true; const toolDbProcessProofSummary = objectOrEmpty(report?.toolDbProcessProofSummary); const toolDbProcessProofReady = report?.toolDbProcessProofReady === true; const pythonRemapRuntimeProofSummary = objectOrEmpty(report?.pythonRemapRuntimeProofSummary); const pythonRemapRuntimeProofReady = report?.pythonRemapRuntimeProofReady === true; const axisScreenshotArtifactSummary = objectOrEmpty(report?.axisScreenshotArtifactSummary); const blockedRuntimeFamilies = arrayOrEmpty(report?.blockedRuntimeFamilies); const promotedBlockedFamilies = arrayOrEmpty(report?.promotedBlockedFamilies); const hardBlockRuntimeLockSummary = createHardBlockRuntimeLockSummary( blockedRuntimeFamilies, promotedBlockedFamilies, ); const ready = report?.ready === true; const statusText = ready ? "Ready" : "Waiting"; const detailText = ready ? "No blocking reasons" : (missing.length > 0 ? missing.join(", ") : "release evidence missing"); return { apiName: "project-release-readiness-summary-view-model", viewModelVersion: 1, phase: ready ? "ready" : "waiting", ready, title: "Project release readiness", statusText, detailText, statusLine: `${statusText}: ${detailText}`, rows: [ { id: "gate-results", label: "Release gates", value: `${gateResultMatrix.passedCount ?? 0}/${gateResultMatrix.gateCount ?? 0} passed`, }, { id: "unknown-gates", label: "Unknown gates", value: `${gateResultMatrix.unknownCount ?? 0}`, }, { id: "sim-config-inventory", 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: "virtual-hal-sim-config-promotion-candidates", label: "Virtual HAL sim-config promotion candidates", value: virtualHalSimConfigPromotionCandidatesReady ? "ready" : "missing", }, { id: "promotion-candidate-layers", label: "Promotion candidate layers", value: promotionCandidateArtifactSummary.ready === true ? `evidence-ready=${promotionCandidateArtifactSummary.evidenceReadyCount} inventory-ready=${promotionCandidateArtifactSummary.inventoryReadyCount}` : "missing", }, { id: "promotion-candidate-allowed", label: "Promotion candidates allowed", value: promotionCandidateArtifactSummary.ready === true ? `${promotionCandidateArtifactSummary.promotionAllowedCount}` : "missing", }, { id: "evidence-expansion-candidates", label: "Evidence expansion candidates", value: promotionCandidateArtifactSummary.ready === true ? `${promotionCandidateArtifactSummary.evidenceExpansionCandidateCount}` : "missing", }, { id: "evidence-expansion-next-evidence", label: "Evidence expansion next evidence", value: promotionCandidateArtifactSummary.ready === true ? promotionCandidateArtifactSummary.evidenceExpansion.nextEvidence : "missing", }, { id: "evidence-expansion-baseline-changing", label: "Evidence expansion baseline changing", value: promotionCandidateArtifactSummary.ready === true ? (promotionCandidateArtifactSummary.evidenceExpansion.baselineChanging ? "yes" : "no") : "missing", }, { id: "virtual-hal-sim-config-macro-load-fixtures", label: "Virtual HAL sim-config macro/load fixtures", value: virtualHalSimConfigMacroLoadFixturesReady ? "ready" : "missing", }, { id: "virtual-hal-motion-controller-matrix", label: "Virtual HAL motion controller matrix", value: virtualHalMotionControllerMatrixReady ? "ready" : "missing", }, { id: "tool-db-process-proof", label: "Tool DB process proof", value: toolDbProcessProofReady ? "ready" : "missing", }, { id: "tool-db-process-proof-detail", label: "Tool DB process proof detail", value: toolDbProcessProofSummary.apiName ? `wasm=${toolDbProcessProofSummary.wasmProtocolReady ? "ready" : "missing"} browser=${toolDbProcessProofSummary.browserProtocolReady ? "ready" : "missing"} opfs=${toolDbProcessProofSummary.opfsPersistenceReady ? "ready" : "missing"} promotion_allowed=${toolDbProcessProofSummary.promotionAllowed ? "1" : "0"}` : "missing", }, { id: "python-remap-runtime-proof", label: "Python remap runtime proof", value: pythonRemapRuntimeProofReady ? "ready" : "locked", }, { id: "python-remap-runtime-proof-detail", label: "Python remap runtime proof detail", value: pythonRemapRuntimeProofSummary.apiName ? `native=${pythonRemapRuntimeProofSummary.nativeLifecycleReady ? "ready" : "missing"} wasm=${pythonRemapRuntimeProofSummary.wasmLifecycleReady ? "ready" : "missing"} browser=${pythonRemapRuntimeProofSummary.browserLifecycleReady ? "ready" : "missing"} promotion_allowed=${pythonRemapRuntimeProofSummary.promotionAllowed ? "1" : "0"}` : "missing", }, { id: "blocked-runtime-families", label: "Blocked runtime families", value: promotedBlockedFamilies.length > 0 ? `promoted: ${promotedBlockedFamilies.join(", ")}` : (blockedRuntimeFamilies.join(", ") || "none"), }, { id: "hard-block-runtime-lock", label: "Hard-block runtime lock", value: hardBlockRuntimeLockSummary.lockValue, }, { id: "promoted-blocked-family-count", label: "Promoted blocked families", value: hardBlockRuntimeLockSummary.promotedCountValue, }, { id: "axis-screenshot-artifacts", label: "AXIS screenshot artifacts", value: Number(axisScreenshotArtifactSummary.artifactCount ?? 0) > 0 ? `${axisScreenshotArtifactSummary.artifactCount}/${arrayOrEmpty(axisScreenshotArtifactSummary.expectedViewports).length} captured` : "not captured", }, { id: "missing", label: "Missing readiness", value: missing.length > 0 ? missing.join(", ") : "none", }, ], }; } export function createProjectReleaseReadinessArtifactValidationSummaryViewModel( validation = createProjectReleaseReadinessArtifactValidation(), ) { const missing = arrayOrEmpty(validation?.missing); const ready = validation?.ready === true; const statusText = ready ? "Ready" : "Blocked"; const detailText = ready ? "Artifact evidence complete" : (missing.length > 0 ? missing.join(", ") : "artifact evidence missing"); return { apiName: "project-release-readiness-artifact-validation-summary-view-model", viewModelVersion: 1, phase: ready ? "ready" : "blocked", ready, title: "Project release artifact validation", statusText, detailText, statusLine: `${statusText}: ${detailText}`, rows: [ { id: "artifact", label: "Readiness artifact", value: validation?.artifactApiName ?? "missing", }, { id: "gate-count", label: "Gate count", value: `${validation?.gateCount ?? 0}/${validation?.expectedGateCount ?? 0}`, }, { id: "gate-manifest", label: "Gate manifest", value: validation?.gateManifestReady === true ? "ready" : "missing", }, { id: "gate-execution-manifest", label: "Gate execution manifest", value: validation?.gateExecutionManifestReady === true ? "ready" : "missing", }, { id: "gate-execution-summary", label: "Gate execution summary", value: validation?.gateExecutionSummaryReady === true ? "ready" : "missing", }, { id: "gate-result-matrix", label: "Gate result matrix", value: validation?.gateResultMatrixReady === true ? "ready" : "missing", }, { id: "gate-action-plan", 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: "virtual-hal-sim-config-promotion-candidates", label: "Virtual HAL sim-config promotion candidates", value: validation?.virtualHalSimConfigPromotionCandidatesReady === true ? "ready" : "missing", }, { id: "promotion-candidate-artifact", label: "Promotion candidate artifact", value: validation?.promotionCandidateArtifactSummaryReady === true ? validation.promotionCandidateArtifactSummary.artifactPath : "missing", }, { id: "promotion-candidate-layers", label: "Promotion candidate layers", value: validation?.promotionCandidateArtifactSummaryReady === true ? `evidence-ready=${validation.promotionCandidateArtifactSummary.evidenceReadyCount} inventory-ready=${validation.promotionCandidateArtifactSummary.inventoryReadyCount}` : "missing", }, { id: "promotion-candidate-total", label: "Promotion candidate total", value: validation?.promotionCandidateArtifactSummaryReady === true ? `${validation.promotionCandidateArtifactSummary.totalCandidateCount}` : "missing", }, { id: "promotion-candidate-artifact-rows", label: "Promotion candidate artifact rows", value: validation?.promotionCandidateArtifactSummaryReady === true ? `${validation.promotionCandidateArtifactSummary.artifactRows.promotionCandidates}` : "missing", }, { id: "evidence-expansion-candidates", label: "Evidence expansion candidates", value: validation?.promotionCandidateArtifactSummaryReady === true ? `${validation.promotionCandidateArtifactSummary.evidenceExpansionCandidateCount}` : "missing", }, { id: "evidence-expansion-artifact-rows", label: "Evidence expansion artifact rows", value: validation?.promotionCandidateArtifactSummaryReady === true ? `${validation.promotionCandidateArtifactSummary.artifactRows.evidenceExpansion}` : "missing", }, { id: "evidence-expansion-next-evidence", label: "Evidence expansion next evidence", value: validation?.promotionCandidateArtifactSummaryReady === true ? validation.promotionCandidateArtifactSummary.evidenceExpansion.nextEvidence : "missing", }, { id: "evidence-expansion-baseline-changing", label: "Evidence expansion baseline changing", value: validation?.promotionCandidateArtifactSummaryReady === true ? (validation.promotionCandidateArtifactSummary.evidenceExpansion.baselineChanging ? "yes" : "no") : "missing", }, { id: "evidence-expansion-artifact", label: "Evidence expansion artifact", value: validation?.promotionCandidateArtifactSummaryReady === true ? validation.promotionCandidateArtifactSummary.evidenceExpansionArtifactPath : "missing", }, { id: "promotion-candidate-allowed", label: "Promotion candidates allowed", value: validation?.promotionCandidateArtifactSummaryReady === true ? `${validation.promotionCandidateArtifactSummary.promotionAllowedCount}` : "missing", }, { id: "virtual-hal-promotion-families", label: "Virtual HAL promotion families", value: validation?.virtualHalPromotionFamilySummary ?? "not provided", }, ...arrayOrEmpty(validation?.virtualHalPromotionFamilyRows).map((row) => ({ id: `virtual-hal-promotion-family-${row.id}`, label: `Promotion family ${row.label}`, value: row.value, sourceFiles: row.sourceFiles, })), { id: "virtual-hal-sim-config-macro-load-fixtures", label: "Virtual HAL sim-config macro/load fixtures", value: validation?.virtualHalSimConfigMacroLoadFixturesReady === true ? "ready" : "missing", }, { id: "virtual-hal-motion-controller-matrix", label: "Virtual HAL motion controller matrix", value: validation?.virtualHalMotionControllerMatrixReady === true ? "ready" : "missing", }, { id: "tool-db-process-proof", label: "Tool DB process proof", value: validation?.toolDbProcessProofReady === true ? "ready" : "missing", }, { id: "tool-db-process-proof-detail", label: "Tool DB process proof detail", value: validation?.toolDbProcessProofReady === true ? `wasm=${validation.toolDbProcessProofSummary.wasmProtocolReady ? "ready" : "missing"} browser=${validation.toolDbProcessProofSummary.browserProtocolReady ? "ready" : "missing"} opfs=${validation.toolDbProcessProofSummary.opfsPersistenceReady ? "ready" : "missing"} promotion_allowed=${validation.toolDbProcessProofSummary.promotionAllowed ? "1" : "0"}` : "missing", }, { id: "python-remap-runtime-proof", label: "Python remap runtime proof", value: validation?.pythonRemapRuntimeProofSummary?.ready === true ? "ready" : "locked", }, { id: "python-remap-runtime-proof-detail", label: "Python remap runtime proof detail", value: validation?.pythonRemapRuntimeProofSummary?.apiName ? `native=${validation.pythonRemapRuntimeProofSummary.nativeLifecycleReady ? "ready" : "missing"} wasm=${validation.pythonRemapRuntimeProofSummary.wasmLifecycleReady ? "ready" : "missing"} browser=${validation.pythonRemapRuntimeProofSummary.browserLifecycleReady ? "ready" : "missing"} promotion_allowed=${validation.pythonRemapRuntimeProofSummary.promotionAllowed ? "1" : "0"}` : "missing", }, { id: "missing", label: "Missing artifact evidence", value: missing.length > 0 ? missing.join(", ") : "none", }, ], }; } export function createProjectReleaseReadinessArtifactValidationActionPlan( validation = createProjectReleaseReadinessArtifactValidation(), ) { const missing = arrayOrEmpty(validation?.missing); const ready = validation?.ready === true; const commands = ready ? [] : [ { step: 1, id: "project-release-gate", label: "Run project release gate", command: "wasm-port/tests/host/verify_project_release_gate.sh", expectedOutput: "project_release_gate=ok", }, { step: 2, id: "artifact-validation", label: "Validate project release readiness artifact", command: "wasm-port/tests/host/verify_project_release_readiness_artifact.sh build/project-release-readiness.json", expectedOutput: "project_release_readiness_artifact_node_smoke=ok", }, ]; const shellScript = commands.length > 0 ? [ "#!/usr/bin/env bash", "set -euo pipefail", "", ...commands.map(({ command }) => command), "", ].join("\n") : "# Project release readiness artifact validation is already ready.\n"; return { apiName: "project-release-readiness-artifact-validation-action-plan", planVersion: 1, phase: ready ? "ready" : "blocked", ready, missing, missingCount: missing.length, commandCount: commands.length, nextActionId: commands[0]?.id ?? null, nextCommand: commands[0]?.command ?? null, commands, shellScript, rows: [ { id: "artifact-validation", label: "Artifact validation", value: ready ? "ready" : "blocked", }, { id: "missing", label: "Missing artifact evidence", value: missing.length > 0 ? missing.join(", ") : "none", }, { id: "next-command", label: "Next command", value: commands[0]?.command ?? "none", }, ], }; } export function parseProjectReleaseReadinessArtifactJson(text) { return JSON.parse(String(text)); } export function createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson = "" } = {}) { try { const artifact = parseProjectReleaseReadinessArtifactJson(artifactJson); const validation = createProjectReleaseReadinessArtifactValidation(artifact); const summaryViewModel = createProjectReleaseReadinessArtifactValidationSummaryViewModel(validation); const actionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(validation); return { apiName: "project-release-readiness-artifact-json-workflow", workflowVersion: 1, phase: validation.ready === true ? "ready" : "blocked", ready: validation.ready === true, parsed: true, parseError: null, artifact, artifactApiName: validation.artifactApiName, validation, summaryViewModel, actionPlan, missing: validation.missing, rows: [ { id: "parse", label: "Artifact JSON parse", value: "ready", }, { id: "validation", label: "Artifact validation", value: validation.ready === true ? "ready" : "blocked", }, { id: "next-command", label: "Next command", value: actionPlan.nextCommand ?? "none", }, ], }; } catch (error) { const validation = createProjectReleaseReadinessArtifactValidation({}); const summaryViewModel = createProjectReleaseReadinessArtifactValidationSummaryViewModel(validation); const actionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(validation); const parseError = error?.message ?? "artifact JSON parse error"; return { apiName: "project-release-readiness-artifact-json-workflow", workflowVersion: 1, phase: "blocked", ready: false, parsed: false, parseError, artifactApiName: null, validation, summaryViewModel, actionPlan, missing: ["artifact-json", ...validation.missing], rows: [ { id: "parse", label: "Artifact JSON parse", value: "blocked", }, { id: "validation", label: "Artifact validation", value: "blocked", }, { id: "next-command", label: "Next command", value: actionPlan.nextCommand ?? "none", }, ], }; } } export async function loadProjectReleaseReadinessArtifactUrlWorkflow({ artifactUrl = "", diagnosticsUrl = "", requireSavedSessionDiagnostics = false, 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", workflowVersion: 1, phase: "blocked", ready: false, artifactUrl, diagnosticsUrl, requireSavedSessionDiagnostics, fetched: false, diagnosticsFetched: false, httpStatus: null, diagnosticsHttpStatus: null, fetchError: null, diagnosticsFetchError: null, jsonWorkflow, validation: jsonWorkflow.validation, diagnosticsValidation, summaryViewModel: jsonWorkflow.summaryViewModel, actionPlan: jsonWorkflow.actionPlan, missing, rows: [ { id: "fetch", label: "Artifact URL fetch", value: "blocked", }, { id: "json-workflow", label: "Artifact JSON workflow", value: "blocked", }, { id: "next-command", label: "Next command", value: jsonWorkflow.actionPlan.nextCommand ?? "none", }, ], }; } try { const response = await fetchRef(artifactUrl); const httpStatus = response?.status ?? null; if (!response?.ok) { const jsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson: "" }); const fetchError = `artifact URL fetch failed${httpStatus ? `: ${httpStatus}` : ""}`; return { apiName: "project-release-readiness-artifact-url-workflow", workflowVersion: 1, phase: "blocked", ready: false, artifactUrl, diagnosticsUrl, requireSavedSessionDiagnostics, 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, ...(diagnosticsUrl ? ["diagnostics-fetch"] : []), ], rows: [ { id: "fetch", label: "Artifact URL fetch", value: "blocked", }, { id: "json-workflow", label: "Artifact JSON workflow", value: "blocked", }, { id: "next-command", label: "Next command", value: jsonWorkflow.actionPlan.nextCommand ?? "none", }, ], }; } const artifactJson = await response.text(); const jsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson }); let diagnosticsFetched = false; let diagnosticsHttpStatus = null; let diagnosticsFetchError = null; let diagnosticsValidation = null; let diagnosticsArtifact = 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; diagnosticsArtifact = JSON.parse(await diagnosticsResponse.text()); diagnosticsValidation = createProjectReleaseBrowserDiagnosticsArtifactValidation(diagnosticsArtifact); diagnosticsMissing.push(...diagnosticsValidation.missing.map((item) => `diagnostics.${item}`)); if (requireSavedSessionDiagnostics && diagnosticsValidation.hasSessionDiagnostics !== true) { diagnosticsMissing.push("diagnostics.virtualHalSessionDiagnostics"); } } } 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 && diagnosticsMissing.length === 0)); return { apiName: "project-release-readiness-artifact-url-workflow", workflowVersion: 1, phase: ready ? "ready" : "blocked", ready, artifactUrl, diagnosticsUrl, requireSavedSessionDiagnostics, fetched: true, diagnosticsFetched, httpStatus, diagnosticsHttpStatus, fetchError: null, diagnosticsFetchError, jsonWorkflow, validation: jsonWorkflow.validation, diagnosticsValidation, diagnosticsArtifact, summaryViewModel: jsonWorkflow.summaryViewModel, actionPlan: jsonWorkflow.actionPlan, missing, rows: [ { id: "fetch", label: "Artifact URL fetch", value: "ready", }, { id: "json-workflow", 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", value: jsonWorkflow.actionPlan.nextCommand ?? "none", }, ], }; } catch (error) { const jsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson: "" }); return { apiName: "project-release-readiness-artifact-url-workflow", workflowVersion: 1, phase: "blocked", ready: false, artifactUrl, diagnosticsUrl, requireSavedSessionDiagnostics, 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, ...(diagnosticsUrl ? ["diagnostics-fetch"] : []), ], rows: [ { id: "fetch", label: "Artifact URL fetch", value: "blocked", }, { id: "json-workflow", label: "Artifact JSON workflow", value: "blocked", }, { id: "next-command", label: "Next command", value: jsonWorkflow.actionPlan.nextCommand ?? "none", }, ], }; } } export function createProjectReleaseReadinessArtifactUrlWorkflowSummaryViewModel( workflow = {}, ) { const missing = arrayOrEmpty(workflow?.missing); const promotionCandidateSummary = objectOrEmpty(workflow?.diagnosticsArtifact?.virtualHalPromotionCandidateSummary); const promotionCandidateReportRows = arrayOrEmpty( workflow?.diagnosticsArtifact?.virtualHalSimConfigPromotionCandidates?.rows, ); const evidenceReadyCandidateRows = promotionCandidateReportRows.filter((row) => row?.complete === true && row?.currentNodeInventoryStatus === "PASS" && row?.blockedKind === "-" && row?.targetBrowserEvidence === "explicit-browser-diagnostics" && row?.currentMatrixBrowserStatus === "explicit-browser-diagnostics" ); const preferredEvidenceReadyCandidate = evidenceReadyCandidateRows[0] ?? {}; const promotionCandidateSummaryReady = promotionCandidateSummary.ready === true; const validationRows = arrayOrEmpty(workflow?.validation?.rows); const hardBlockRuntimeLock = validationRows.find(({ id }) => id === "hard-block-runtime-lock")?.value; const promotedBlockedFamilyCount = validationRows.find(({ id }) => id === "promoted-blocked-family-count")?.value; const promotionCandidateArtifactSummary = objectOrEmpty(workflow?.validation?.promotionCandidateArtifactSummary); const promotionCandidateArtifactSummaryReady = workflow?.validation?.promotionCandidateArtifactSummaryReady === true; const toolDbProcessProofSummary = objectOrEmpty(workflow?.validation?.toolDbProcessProofSummary); const toolDbProcessProofReady = workflow?.validation?.toolDbProcessProofReady === true; const pythonRemapRuntimeProofSummary = objectOrEmpty(workflow?.validation?.pythonRemapRuntimeProofSummary); const pythonRemapRuntimeProofReady = workflow?.validation?.pythonRemapRuntimeProofReady === true; const promotionArtifactRows = objectOrEmpty(promotionCandidateArtifactSummary.artifactRows); const hardBlockRuntimeFamilyRows = arrayOrEmpty(promotionCandidateArtifactSummary.hardBlockRuntimeFamilyRows); const hardBlockRuntimeFamilySummaryRows = arrayOrEmpty( promotionCandidateArtifactSummary.hardBlockRuntimeFamilySummaryRows, ); const hardBlockRuntimeFamilyDetailRows = arrayOrEmpty( promotionCandidateArtifactSummary.hardBlockRuntimeFamilyDetailRows, ); const hardBlockRuntimeDetailPreviewRows = hardBlockRuntimeFamilyDetailRows.slice(0, 5); const hardBlockRuntimePreviewRows = hardBlockRuntimeFamilyRows.slice(0, 3); const evidenceExpansionRows = arrayOrEmpty( workflow?.diagnosticsArtifact?.virtualHalSimConfigEvidenceExpansion?.rows, ); const preferredEvidenceExpansion = evidenceExpansionRows[0] ?? {}; const evidenceExpansionPreviewRows = evidenceExpansionRows.slice(0, 3); const ready = workflow?.ready === true; const statusText = ready ? "Ready" : "Blocked"; const detailText = ready ? "Artifact URL workflow complete" : (missing.length > 0 ? missing.join(", ") : workflow?.fetchError ?? "artifact URL workflow blocked"); return { apiName: "project-release-readiness-artifact-url-workflow-summary-view-model", viewModelVersion: 1, phase: ready ? "ready" : "blocked", ready, title: "Project release artifact URL workflow", statusText, detailText, statusLine: `${statusText}: ${detailText}`, rows: [ { id: "artifact-url", label: "Artifact URL", value: workflow?.artifactUrl || "missing", }, { id: "fetch", label: "Fetch", value: workflow?.fetched === true ? `ready${workflow?.httpStatus ? ` (${workflow.httpStatus})` : ""}` : "blocked", }, { id: "json-workflow", label: "JSON workflow", value: workflow?.jsonWorkflow?.ready === true ? "ready" : "blocked", }, { id: "artifact-validation", label: "Artifact validation", value: workflow?.validation?.ready === true ? "ready" : "blocked", }, { id: "virtual-hal-promotion-families", label: "Virtual HAL promotion families", value: workflow?.validation?.virtualHalPromotionFamilySummary ?? "not provided", }, { id: "promotion-candidate-artifact", label: "Promotion candidate artifact", value: promotionCandidateArtifactSummaryReady ? promotionCandidateArtifactSummary.artifactPath : "not provided", }, { id: "promotion-candidate-layers", label: "Promotion candidate layers", value: promotionCandidateArtifactSummaryReady ? `evidence-ready=${promotionCandidateArtifactSummary.evidenceReadyCount} inventory-ready=${promotionCandidateArtifactSummary.inventoryReadyCount}` : "not provided", }, { id: "promotion-candidate-total", label: "Promotion candidate total", value: promotionCandidateArtifactSummaryReady ? `${promotionCandidateArtifactSummary.totalCandidateCount}` : "not provided", }, { id: "evidence-ready-candidate-rows", label: "Evidence-ready candidate rows", value: `${evidenceReadyCandidateRows.length}`, }, { id: "evidence-ready-candidate-preview", label: "Evidence-ready candidate preview", value: preferredEvidenceReadyCandidate.id ?? "not provided", }, { id: "evidence-ready-candidate-preview-gcode", label: "Evidence-ready candidate preview G-code", value: preferredEvidenceReadyCandidate.gcodePath ?? "not provided", }, { id: "evidence-ready-candidate-promotion-allowed", label: "Evidence-ready candidate promotion allowed", value: "0", }, { id: "evidence-ready-candidate-baseline-changing", label: "Evidence-ready candidate baseline changing", value: "no", }, { id: "promotion-candidate-artifact-rows", label: "Promotion candidate artifact rows", value: promotionCandidateArtifactSummaryReady ? `${promotionArtifactRows.promotionCandidates ?? "not provided"}` : "not provided", }, { id: "evidence-expansion-candidates", label: "Evidence expansion candidates", value: promotionCandidateArtifactSummaryReady ? `${promotionCandidateArtifactSummary.evidenceExpansionCandidateCount}` : "not provided", }, { id: "evidence-expansion-artifact-rows", label: "Evidence expansion artifact rows", value: promotionCandidateArtifactSummaryReady ? `${promotionArtifactRows.evidenceExpansion ?? "not provided"}` : "not provided", }, { id: "evidence-expansion-next-evidence", label: "Evidence expansion next evidence", value: promotionCandidateArtifactSummaryReady ? promotionCandidateArtifactSummary.evidenceExpansion.nextEvidence : "not provided", }, { id: "evidence-expansion-baseline-changing", label: "Evidence expansion baseline changing", value: promotionCandidateArtifactSummaryReady ? (promotionCandidateArtifactSummary.evidenceExpansion.baselineChanging ? "yes" : "no") : "not provided", }, { id: "evidence-expansion-preferred-candidate", label: "Evidence expansion preferred candidate", value: preferredEvidenceExpansion.id ?? "not provided", }, { id: "evidence-expansion-preferred-gcode", label: "Evidence expansion preferred G-code", value: preferredEvidenceExpansion.gcodePath ?? "not provided", }, { id: "evidence-expansion-preferred-source-count", label: "Evidence expansion preferred source count", value: Array.isArray(preferredEvidenceExpansion.sourceFiles) ? `${preferredEvidenceExpansion.sourceFiles.length}` : "not provided", }, { id: "evidence-expansion-candidate-list", label: "Evidence expansion candidate list", value: evidenceExpansionPreviewRows.length > 0 ? evidenceExpansionPreviewRows.map((row) => row.id).join(", ") : "not provided", }, { id: "evidence-expansion-gcode-list", label: "Evidence expansion G-code list", value: evidenceExpansionPreviewRows.length > 0 ? evidenceExpansionPreviewRows.map((row) => row.gcodePath).join(", ") : "not provided", }, { id: "evidence-expansion-source-count-list", label: "Evidence expansion source count list", value: evidenceExpansionPreviewRows.length > 0 ? evidenceExpansionPreviewRows.map((row) => Array.isArray(row.sourceFiles) ? `${row.sourceFiles.length}` : "0" ).join(", ") : "not provided", }, { id: "evidence-expansion-artifact", label: "Evidence expansion artifact", value: promotionCandidateArtifactSummaryReady ? promotionCandidateArtifactSummary.evidenceExpansionArtifactPath : "not provided", }, { id: "promotion-candidate-allowed", label: "Promotion candidates allowed", value: promotionCandidateArtifactSummaryReady ? `${promotionCandidateArtifactSummary.promotionAllowedCount}` : "not provided", }, { id: "hard-block-runtime-locked-rows", label: "Hard-block locked inventory rows", value: promotionCandidateArtifactSummaryReady ? `${hardBlockRuntimeFamilyRows.length}` : "not provided", }, { id: "hard-block-runtime-locked-preview", label: "Hard-block locked row preview", value: hardBlockRuntimePreviewRows.length > 0 ? hardBlockRuntimePreviewRows.map((row) => `${row.skipKind}:${row.path}`).join(", ") : "not provided", }, { id: "hard-block-runtime-promotion-allowed", label: "Hard-block promotions allowed", value: promotionCandidateArtifactSummaryReady ? `${promotionCandidateArtifactSummary.hardBlockRuntimePromotionAllowedCount ?? "not provided"}` : "not provided", }, { id: "hard-block-runtime-family-count", label: "Hard-block runtime families", value: promotionCandidateArtifactSummaryReady ? `${hardBlockRuntimeFamilySummaryRows.length}` : "not provided", }, { id: "hard-block-runtime-family-summary", label: "Hard-block runtime family summary", value: hardBlockRuntimeFamilySummaryRows.length > 0 ? hardBlockRuntimeFamilySummaryRows .map((row) => `${row.family}:${row.candidateCount} locked=${row.locked ? "yes" : "no"}`) .join(", ") : "not provided", }, { id: "hard-block-runtime-detail-row-count", label: "Hard-block detail rows", value: promotionCandidateArtifactSummaryReady ? `${hardBlockRuntimeFamilyDetailRows.length}` : "not provided", }, ...hardBlockRuntimeDetailPreviewRows.map((row, index) => ({ id: `hard-block-runtime-detail-preview-${index + 1}`, label: `Hard-block detail ${index + 1}`, value: `${row.family}:${row.path}; reason=${row.blockReason}; next=${row.nextProof}; promotion_allowed=${row.promotionAllowed ? "1" : "0"}`, family: row.family, path: row.path, blockReason: row.blockReason, nextProof: row.nextProof, promotionAllowed: row.promotionAllowed, })), ...hardBlockRuntimeFamilySummaryRows.map((row) => ({ id: `hard-block-runtime-family-${row.family}`, label: `Hard-block family ${row.family}`, value: [ `${row.candidateCount} locked rows`, `promotion_allowed=${row.promotionAllowedCount}`, `first=${row.firstPath ?? "not provided"}`, `reason=${row.firstBlockReason ?? "not provided"}`, `next=${row.nextProof ?? "not provided"}`, ].join("; "), firstPath: row.firstPath, firstBlockReason: row.firstBlockReason, nextProof: row.nextProof, })), ...hardBlockRuntimeFamilySummaryRows.map((row) => ({ id: `hard-block-runtime-family-${row.family}-paths`, label: `Hard-block family ${row.family} paths`, value: arrayOrEmpty(row.lockedPaths).length > 0 ? row.lockedPaths.join(", ") : "not provided", lockedPaths: arrayOrEmpty(row.lockedPaths), })), { id: "tool-db-process-proof", label: "Tool DB process proof", value: toolDbProcessProofReady ? "ready" : "not provided", }, { id: "tool-db-process-proof-detail", label: "Tool DB process proof detail", value: toolDbProcessProofReady ? `wasm=${toolDbProcessProofSummary.wasmProtocolReady ? "ready" : "missing"} browser=${toolDbProcessProofSummary.browserProtocolReady ? "ready" : "missing"} opfs=${toolDbProcessProofSummary.opfsPersistenceReady ? "ready" : "missing"} promotion_allowed=${toolDbProcessProofSummary.promotionAllowed ? "1" : "0"}` : "not provided", }, { id: "python-remap-runtime-proof", label: "Python remap runtime proof", value: pythonRemapRuntimeProofSummary.ready === true ? "ready" : "locked", }, { id: "python-remap-runtime-proof-detail", label: "Python remap runtime proof detail", value: pythonRemapRuntimeProofSummary.apiName ? `native=${pythonRemapRuntimeProofSummary.nativeLifecycleReady ? "ready" : "missing"} wasm=${pythonRemapRuntimeProofSummary.wasmLifecycleReady ? "ready" : "missing"} browser=${pythonRemapRuntimeProofSummary.browserLifecycleReady ? "ready" : "missing"} promotion_allowed=${pythonRemapRuntimeProofSummary.promotionAllowed ? "1" : "0"}` : "not provided", }, ...arrayOrEmpty(workflow?.validation?.virtualHalPromotionFamilyRows).map((row) => ({ id: `virtual-hal-promotion-family-${row.id}`, label: `Promotion family ${row.label}`, value: row.value, sourceFiles: row.sourceFiles, })), { id: "browser-diagnostics", label: "Browser diagnostics", value: workflow?.diagnosticsUrl ? (workflow?.diagnosticsValidation?.ready === true ? "ready" : "blocked") : "not requested", }, { id: "virtual-hal-promotion-candidate-summary", label: "Virtual HAL promotion candidate summary", value: workflow?.diagnosticsUrl ? (promotionCandidateSummaryReady ? "ready" : "not provided") : "not requested", }, { id: "virtual-hal-promotion-candidate", label: "Virtual HAL promotion candidate", value: promotionCandidateSummary.preferredCandidateId ?? "not provided", }, { id: "virtual-hal-promotion-candidate-ini", label: "Candidate INI", value: promotionCandidateSummary.preferredIniPath ?? "not provided", }, { id: "virtual-hal-promotion-candidate-gcode", label: "Candidate G-code", value: promotionCandidateSummary.preferredGcodePath ?? "not provided", }, { id: "virtual-hal-promotion-candidate-count", label: "Candidate readiness", value: Number.isFinite(promotionCandidateSummary.readyCandidateCount) && Number.isFinite(promotionCandidateSummary.candidateCount) ? `${promotionCandidateSummary.readyCandidateCount}/${promotionCandidateSummary.candidateCount} ready` : "not provided", }, { id: "virtual-hal-promotion-family-count", label: "Promotion family count", value: Number.isFinite(promotionCandidateSummary.familyCount) ? `${promotionCandidateSummary.familyCount} families` : "not provided", }, { id: "virtual-hal-promotion-source-file-count", label: "Promotion source files", value: Number.isFinite(promotionCandidateSummary.sourceFileCount) ? `${promotionCandidateSummary.sourceFileCount} source files` : "not provided", }, { id: "virtual-hal-promotion-browser-diagnostics-count", label: "Promotion browser diagnostics", value: Number.isFinite(promotionCandidateSummary.explicitBrowserDiagnosticsCount) ? `${promotionCandidateSummary.explicitBrowserDiagnosticsCount} diagnostics-ready` : "not provided", }, { id: "virtual-hal-promotion-candidate-baseline", label: "Candidate inventory baseline", value: promotionCandidateSummary.inventoryBaseline ?? "not provided", }, { id: "hard-block-runtime-lock", label: "Hard-block runtime lock", value: hardBlockRuntimeLock ?? "not provided", }, { id: "promoted-blocked-family-count", label: "Promoted blocked families", value: promotedBlockedFamilyCount ?? "not provided", }, { id: "saved-session-diagnostics", label: "Saved-session diagnostics", value: workflow?.diagnosticsUrl ? (workflow?.diagnosticsValidation?.hasSessionDiagnostics ? (workflow?.diagnosticsValidation?.sessionDiagnosticsReady === true ? "ready" : "blocked") : "not provided") : "not requested", }, { id: "next-command", label: "Next command", value: workflow?.actionPlan?.nextCommand ?? "none", }, { id: "missing", label: "Missing workflow evidence", value: missing.length > 0 ? missing.join(", ") : "none", }, ], }; } export function createProjectReleaseReadinessArtifactUrlWorkflowActionPlan( workflow = {}, ) { const missing = arrayOrEmpty(workflow?.missing); const ready = workflow?.ready === true; const validationCommands = arrayOrEmpty(workflow?.actionPlan?.commands); const inputActions = [ ...(missing.includes("artifact-url") ? [{ id: "provide-artifact-url", label: "Provide release readiness artifact URL", kind: "input", command: null, expectedOutput: null, }] : []), ...(missing.includes("fetch") ? [{ id: "provide-fetch", label: "Provide fetch implementation", kind: "input", command: null, expectedOutput: null, }] : []), ...(missing.includes("artifact-fetch") ? [{ id: "verify-artifact-url-fetch", label: "Verify release readiness artifact URL fetch", kind: "fetch", command: null, 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}`, label: command.label, kind: "command", command: command.command, expectedOutput: command.expectedOutput ?? null, })); const actions = ready ? [] : [...inputActions, ...commandActions].map((action, index) => ({ step: index + 1, ...action, })); const commands = actions.filter(({ command }) => typeof command === "string" && command.length > 0); const shellScript = commands.length > 0 ? [ "#!/usr/bin/env bash", "set -euo pipefail", "", ...commands.map(({ command }) => command), "", ].join("\n") : (ready ? "# Project release readiness artifact URL workflow is already ready.\n" : "# Project release readiness artifact URL workflow requires non-shell input.\n"); return { apiName: "project-release-readiness-artifact-url-workflow-action-plan", planVersion: 1, phase: ready ? "ready" : "blocked", ready, missing, actionCount: actions.length, commandCount: commands.length, nextActionId: actions[0]?.id ?? null, nextCommand: commands[0]?.command ?? null, actions, commands, shellScript, rows: actions.map(({ id, label, kind, command, expectedOutput }) => ({ id, label, kind, value: command ?? kind, expectedOutput, })), }; } export function createProjectReleaseReadinessArtifactValidation(artifact = {}) { const artifactObject = objectOrEmpty(artifact); const releaseGate = objectOrEmpty(artifactObject.releaseGate); const simConfigInventory = objectOrEmpty(artifactObject.simConfigInventory); const virtualHalSimConfigSourceCoverage = objectOrEmpty(artifactObject.virtualHalSimConfigSourceCoverage); const virtualHalSimConfigPromotionCandidates = objectOrEmpty(artifactObject.virtualHalSimConfigPromotionCandidates); const virtualHalSimConfigMacroLoadFixtures = objectOrEmpty(artifactObject.virtualHalSimConfigMacroLoadFixtures); const virtualHalMotionControllerMatrix = objectOrEmpty(artifactObject.virtualHalMotionControllerMatrix); const toolDbProcessProofSummary = objectOrEmpty(artifactObject.toolDbProcessProofSummary); const pythonRemapRuntimeProofSummary = objectOrEmpty(artifactObject.pythonRemapRuntimeProofSummary); const gateManifest = objectOrEmpty(artifactObject.gateManifest); const gateExecutionManifest = objectOrEmpty(artifactObject.gateExecutionManifest); const gateExecutionSummaryViewModel = objectOrEmpty(artifactObject.gateExecutionSummaryViewModel); const gateResultMatrix = objectOrEmpty(artifactObject.gateResultMatrix); const gateActionPlan = objectOrEmpty(artifactObject.gateActionPlan); const axisScreenshotArtifactSummary = objectOrEmpty(artifactObject.axisScreenshotArtifactSummary); const gates = arrayOrEmpty(artifactObject.gates); const manifestGateIds = arrayOrEmpty(gateManifest.gateIds); const executionRows = arrayOrEmpty(gateExecutionManifest.rows); const matrixRows = arrayOrEmpty(gateResultMatrix.rows); const actionPlanCommands = arrayOrEmpty(gateActionPlan.commands); const rows = arrayOrEmpty(artifactObject.rows); const expectedGateIds = createProjectReleaseGateManifest().gateIds; const gateCountReady = gates.length === REQUIRED_RELEASE_GATES.length; const gatesPassed = gateCountReady && gates.every(({ passed }) => passed === true); const manifestReady = gateManifest.apiName === "project-release-gate-manifest" && gateManifest.manifestVersion === 1 && gateManifest.gateCount === REQUIRED_RELEASE_GATES.length && manifestGateIds.join(",") === expectedGateIds.join(","); const matrixReady = gateResultMatrix.apiName === "project-release-gate-result-matrix" && gateResultMatrix.matrixVersion === 1 && gateResultMatrix.ready === true && gateResultMatrix.passedCount === REQUIRED_RELEASE_GATES.length && gateResultMatrix.unknownCount === 0 && matrixRows.length === REQUIRED_RELEASE_GATES.length; const executionManifestReady = gateExecutionManifest.apiName === "project-release-gate-execution-manifest" && gateExecutionManifest.manifestVersion === 1 && gateExecutionManifest.ready === true && gateExecutionManifest.passedCount === REQUIRED_RELEASE_GATES.length && gateExecutionManifest.unknownCount === 0 && executionRows.length === REQUIRED_RELEASE_GATES.length && executionRows.every(({ command, status }) => typeof command === "string" && status === "passed"); const executionSummaryReady = gateExecutionSummaryViewModel.apiName === "project-release-gate-execution-summary-view-model" && gateExecutionSummaryViewModel.viewModelVersion === 1 && gateExecutionSummaryViewModel.ready === true && gateExecutionSummaryViewModel.passedCount === REQUIRED_RELEASE_GATES.length && gateExecutionSummaryViewModel.unknownCount === 0 && gateExecutionSummaryViewModel.nextGateId === null && arrayOrEmpty(gateExecutionSummaryViewModel.gateRows).length === REQUIRED_RELEASE_GATES.length; const actionPlanReady = gateActionPlan.apiName === "project-release-gate-action-plan" && gateActionPlan.planVersion === 1 && gateActionPlan.ready === true && gateActionPlan.pendingCount === 0 && gateActionPlan.nextCommand === null && actionPlanCommands.length === 0; const virtualHalSimConfigSourceCoverageReady = isVirtualHalSimConfigSourceCoverageReady( virtualHalSimConfigSourceCoverage, ) && artifactObject.virtualHalSimConfigSourceCoverageReady === true; const virtualHalSimConfigPromotionCandidatesReady = isVirtualHalSimConfigPromotionCandidateReportReady( virtualHalSimConfigPromotionCandidates, ) && artifactObject.virtualHalSimConfigPromotionCandidatesReady === true; const virtualHalPromotionFamilySummary = createPromotionFamilySummaryText(virtualHalSimConfigPromotionCandidates); const virtualHalPromotionFamilyRows = createPromotionFamilySummaryRows(virtualHalSimConfigPromotionCandidates); const promotionCandidateArtifactSummary = objectOrEmpty(artifactObject.promotionCandidateArtifactSummary); const expectedPromotionCandidateArtifactSummary = createPromotionCandidateArtifactSummary({ candidateReport: virtualHalSimConfigPromotionCandidates, evidenceExpansionReport: artifactObject.virtualHalSimConfigEvidenceExpansion, inventory: simConfigInventory, blockedFamilies: arrayOrEmpty(artifactObject.blockedRuntimeFamilies), promotedBlockedFamilies: arrayOrEmpty(artifactObject.promotedBlockedFamilies), }); const artifactRows = objectOrEmpty(promotionCandidateArtifactSummary.artifactRows); const promotionCandidateArtifactSummaryReady = promotionCandidateArtifactSummary.apiName === expectedPromotionCandidateArtifactSummary.apiName && promotionCandidateArtifactSummary.summaryVersion === 1 && promotionCandidateArtifactSummary.ready === true && promotionCandidateArtifactSummary.artifactPath === expectedPromotionCandidateArtifactSummary.artifactPath && promotionCandidateArtifactSummary.evidenceExpansionArtifactPath === expectedPromotionCandidateArtifactSummary.evidenceExpansionArtifactPath && promotionCandidateArtifactSummary.layerCount === 2 && promotionCandidateArtifactSummary.evidenceReadyCount === expectedPromotionCandidateArtifactSummary.evidenceReadyCount && promotionCandidateArtifactSummary.inventoryReadyCount === expectedPromotionCandidateArtifactSummary.inventoryReadyCount && promotionCandidateArtifactSummary.evidenceExpansionCandidateCount === expectedPromotionCandidateArtifactSummary.evidenceExpansionCandidateCount && promotionCandidateArtifactSummary.totalCandidateCount === expectedPromotionCandidateArtifactSummary.totalCandidateCount && promotionCandidateArtifactSummary.promotionAllowedCount === 0 && promotionCandidateArtifactSummary.hardBlockRuntimeLock === expectedPromotionCandidateArtifactSummary.hardBlockRuntimeLock && promotionCandidateArtifactSummary.hardBlockRuntimePromotionAllowedCount === 0 && Number.isFinite(promotionCandidateArtifactSummary.hardBlockRuntimePromotionAllowedCount) && promotionCandidateArtifactSummary.inventoryBaseline === expectedPromotionCandidateArtifactSummary.inventoryBaseline && artifactRows.promotionCandidates === promotionCandidateArtifactSummary.evidenceReadyCount + promotionCandidateArtifactSummary.inventoryReadyCount && ( artifactRows.evidenceExpansion === 0 || artifactRows.evidenceExpansion === promotionCandidateArtifactSummary.evidenceExpansionCandidateCount ) && arrayOrEmpty(promotionCandidateArtifactSummary.layers).some((row) => row.id === "evidence-ready" && row.candidateCount === expectedPromotionCandidateArtifactSummary.evidenceReadyCount && row.virtualHalEvidenceReady === true && row.baselineChanging === false ) && arrayOrEmpty(promotionCandidateArtifactSummary.layers).some((row) => row.id === "inventory-ready" && row.candidateCount === expectedPromotionCandidateArtifactSummary.inventoryReadyCount && row.promotionAllowedCount === 0 && row.virtualHalEvidenceReady === false && row.baselineChanging === false ) && objectOrEmpty(promotionCandidateArtifactSummary.evidenceExpansion).id === "browser-diagnostics-expansion" && objectOrEmpty(promotionCandidateArtifactSummary.evidenceExpansion).candidateCount === expectedPromotionCandidateArtifactSummary.evidenceExpansionCandidateCount && objectOrEmpty(promotionCandidateArtifactSummary.evidenceExpansion).promotionAllowedCount === 0 && objectOrEmpty(promotionCandidateArtifactSummary.evidenceExpansion).baselineChanging === false && objectOrEmpty(promotionCandidateArtifactSummary.evidenceExpansion).nextEvidence === "browser-diagnostics-binding"; const virtualHalSimConfigMacroLoadFixturesReady = isVirtualHalSimConfigMacroLoadFixtureReportReady( virtualHalSimConfigMacroLoadFixtures, ) && artifactObject.virtualHalSimConfigMacroLoadFixturesReady === true; const virtualHalMotionControllerMatrixReady = isVirtualHalMotionControllerMatrixReady( virtualHalMotionControllerMatrix, ) && artifactObject.virtualHalMotionControllerMatrixReady === true; const expectedToolDbProcessProofSummary = createToolDbProcessProofSummary(toolDbProcessProofSummary); const toolDbProcessProofReady = toolDbProcessProofSummary.apiName === "tool-db-process-proof-summary" && toolDbProcessProofSummary.summaryVersion === 1 && toolDbProcessProofSummary.ready === true && toolDbProcessProofSummary.boundaryClass === "L4-TOOL-DB" && toolDbProcessProofSummary.path === "axis/db_demo/base.ngc" && toolDbProcessProofSummary.dbProgramPath === "./db_nonran.py" && toolDbProcessProofSummary.wasmProtocolReady === true && toolDbProcessProofSummary.browserProtocolReady === true && toolDbProcessProofSummary.opfsPersistenceReady === true && toolDbProcessProofSummary.tblFallbackSufficient === false && toolDbProcessProofSummary.promotionAllowed === false && toolDbProcessProofSummary.executionEnabled === false && arrayOrEmpty(toolDbProcessProofSummary.requiredCommands).join("\n") === expectedToolDbProcessProofSummary.requiredCommands.join("\n") && artifactObject.toolDbProcessProofReady === true; const expectedPythonRemapRuntimeProofSummary = createPythonRemapRuntimeProofSummary(pythonRemapRuntimeProofSummary); const pythonRemapRuntimeProofReady = pythonRemapRuntimeProofSummary.apiName === "python-remap-runtime-proof-summary" && pythonRemapRuntimeProofSummary.summaryVersion === 1 && pythonRemapRuntimeProofSummary.boundaryClass === "L4-PYTHON-REMAP" && pythonRemapRuntimeProofSummary.fixtureFamily === "axis/remap/stop-lookahead/nc_files" && pythonRemapRuntimeProofSummary.fixtureId === "stop_lookahead_python_runtime_lifecycle" && pythonRemapRuntimeProofSummary.iniPath === "axis/remap/stop-lookahead/demo.ini" && pythonRemapRuntimeProofSummary.pythonPathPrepend === "python" && pythonRemapRuntimeProofSummary.topLevelPath === "python/toplevel.py" && pythonRemapRuntimeProofSummary.callableName === "queuebuster" && pythonRemapRuntimeProofSummary.nativeProbeStatus === ( pythonRemapRuntimeProofSummary.nativeLifecycleReady ? "runtime_lifecycle_probe_passed" : "not_provided" ) && pythonRemapRuntimeProofSummary.nativeProofArtifactPath === "wasm-port/build/native/native-runtime-probe-summary.tsv" && pythonRemapRuntimeProofSummary.promotionAllowed === false && pythonRemapRuntimeProofSummary.executionEnabled === false && pythonRemapRuntimeProofSummary.bulkPromotionAllowed === false && pythonRemapRuntimeProofSummary.manualLockUpdateRequired === true && arrayOrEmpty(pythonRemapRuntimeProofSummary.requiredCommands).join("\n") === expectedPythonRemapRuntimeProofSummary.requiredCommands.join("\n") && artifactObject.pythonRemapRuntimeProofReady === pythonRemapRuntimeProofSummary.ready; const axisScreenshotArtifacts = arrayOrEmpty(axisScreenshotArtifactSummary.artifacts); const blockedRuntimeFamilies = arrayOrEmpty(artifactObject.blockedRuntimeFamilies); const promotedBlockedFamilies = arrayOrEmpty(artifactObject.promotedBlockedFamilies); const hardBlockRuntimeLockSummary = createHardBlockRuntimeLockSummary( blockedRuntimeFamilies, promotedBlockedFamilies, ); const axisScreenshotSummaryReady = !axisScreenshotArtifactSummary.apiName || axisScreenshotArtifacts.length === 0 || ( axisScreenshotArtifactSummary.apiName === "project-release-axis-screenshot-artifact-summary" && axisScreenshotArtifactSummary.summaryVersion === 1 && axisScreenshotArtifactSummary.ready === true && axisScreenshotArtifacts.length === 4 && arrayOrEmpty(axisScreenshotArtifactSummary.missingViewports).length === 0 && arrayOrEmpty(axisScreenshotArtifactSummary.undersizedViewports).length === 0 && axisScreenshotArtifacts.every((artifact) => artifact.apiName === "real-browser-simulation-axis-screenshot-artifact" && artifact.screenshotBytes >= 10000 && artifact.validatedBy === "browser_real_simulation_page_smoke" && ( artifact.fullDiagnosticsPath === null || ( artifact.fullDiagnosticsApiName === "real-browser-simulation-diagnostics-artifact" && artifact.previewRenderer === "threejs" && artifact.threePathPoints > 0 ) ) ) ); const missing = [ ...(artifactObject.apiName === PROJECT_RELEASE_READINESS_ARTIFACT_API ? [] : ["apiName"]), ...(artifactObject.reportVersion === PROJECT_RELEASE_READINESS_ARTIFACT_VERSION ? [] : ["reportVersion"]), ...(artifactObject.phase === "ready" ? [] : ["phase"]), ...(artifactObject.ready === true ? [] : ["ready"]), ...(Array.isArray(artifactObject.missing) && artifactObject.missing.length === 0 ? [] : ["missing"]), ...(releaseGate.command === "wasm-port/tests/host/verify_project_release_gate.sh" ? [] : ["releaseGate.command"]), ...(releaseGate.passed === true ? [] : ["releaseGate.passed"]), ...(releaseGate.expectedOutput === "project_release_gate=ok" ? [] : ["releaseGate.expectedOutput"]), ...(simConfigInventory.executed === DEFAULT_SIM_CONFIG_INVENTORY_BASELINE.executed ? [] : ["simConfigInventory.executed"]), ...(simConfigInventory.passed === DEFAULT_SIM_CONFIG_INVENTORY_BASELINE.passed ? [] : ["simConfigInventory.passed"]), ...(simConfigInventory.skipped === DEFAULT_SIM_CONFIG_INVENTORY_BASELINE.skipped ? [] : ["simConfigInventory.skipped"]), ...(simConfigInventory.unexpectedFail === DEFAULT_SIM_CONFIG_INVENTORY_BASELINE.unexpectedFail ? [] : ["simConfigInventory.unexpectedFail"]), ...(virtualHalSimConfigSourceCoverageReady ? [] : ["virtualHalSimConfigSourceCoverage"]), ...(virtualHalSimConfigPromotionCandidatesReady ? [] : ["virtualHalSimConfigPromotionCandidates"]), ...(promotionCandidateArtifactSummaryReady ? [] : ["promotionCandidateArtifactSummary"]), ...(virtualHalSimConfigMacroLoadFixturesReady ? [] : ["virtualHalSimConfigMacroLoadFixtures"]), ...(virtualHalMotionControllerMatrixReady ? [] : ["virtualHalMotionControllerMatrix"]), ...(toolDbProcessProofReady ? [] : ["toolDbProcessProofSummary"]), ...(arrayOrEmpty(artifactObject.blockedRuntimeFamilies).join(",") === BLOCKED_RUNTIME_FAMILIES.join(",") ? [] : ["blockedRuntimeFamilies"]), ...(arrayOrEmpty(artifactObject.promotedBlockedFamilies).length === 0 ? [] : ["promotedBlockedFamilies"]), ...(manifestReady ? [] : ["gateManifest"]), ...(executionManifestReady ? [] : ["gateExecutionManifest"]), ...(executionSummaryReady ? [] : ["gateExecutionSummaryViewModel"]), ...(matrixReady ? [] : ["gateResultMatrix"]), ...(actionPlanReady ? [] : ["gateActionPlan"]), ...(axisScreenshotSummaryReady ? [] : ["axisScreenshotArtifactSummary"]), ...(gateCountReady ? [] : ["gates.length"]), ...(gatesPassed ? [] : ["gates.passed"]), ...(rows.find(({ id, value }) => id === "project-release-gate" && value === "passed") ? [] : ["rows.project-release-gate"]), ]; return { apiName: "project-release-readiness-artifact-validation", validationVersion: 1, phase: missing.length === 0 ? "ready" : "blocked", ready: missing.length === 0, missing, artifactApiName: artifactObject.apiName ?? null, artifactVersion: artifactObject.reportVersion ?? null, gateCount: gates.length, expectedGateCount: REQUIRED_RELEASE_GATES.length, expectedGateIds, gateManifestReady: manifestReady, gateExecutionManifestReady: executionManifestReady, gateExecutionSummaryReady: executionSummaryReady, gateResultMatrixReady: matrixReady, gateActionPlanReady: actionPlanReady, virtualHalSimConfigSourceCoverageReady, virtualHalSimConfigPromotionCandidatesReady, virtualHalPromotionFamilySummary, virtualHalPromotionFamilyRows, promotionCandidateArtifactSummary, promotionCandidateArtifactSummaryReady, virtualHalSimConfigMacroLoadFixturesReady, virtualHalMotionControllerMatrixReady, toolDbProcessProofSummary, toolDbProcessProofReady, pythonRemapRuntimeProofSummary, pythonRemapRuntimeProofReady, axisScreenshotArtifactSummaryReady: axisScreenshotSummaryReady, axisScreenshotArtifactCount: axisScreenshotArtifacts.length, blockedRuntimeFamilies, rows: [ { id: "artifact", label: "Readiness artifact", value: artifactObject.apiName ?? "missing", }, { id: "project-release-gate", label: "Project release gate", value: releaseGate.passed === true ? "passed" : "missing", }, { id: "gate-manifest", label: "Gate manifest", value: manifestReady ? "ready" : "missing", }, { id: "gate-execution-manifest", label: "Gate execution manifest", value: executionManifestReady ? "ready" : "missing", }, { id: "gate-execution-summary", label: "Gate execution summary", value: executionSummaryReady ? "ready" : "missing", }, { id: "gate-result-matrix", label: "Gate result matrix", value: matrixReady ? "ready" : "missing", }, { id: "gate-action-plan", 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: "virtual-hal-sim-config-promotion-candidates", label: "Virtual HAL sim-config promotion candidates", value: virtualHalSimConfigPromotionCandidatesReady ? "ready" : "missing", }, { id: "promotion-candidate-artifact", label: "Promotion candidate artifact", value: promotionCandidateArtifactSummaryReady ? promotionCandidateArtifactSummary.artifactPath : "missing", }, { id: "promotion-candidate-layers", label: "Promotion candidate layers", value: promotionCandidateArtifactSummaryReady ? `evidence-ready=${promotionCandidateArtifactSummary.evidenceReadyCount} inventory-ready=${promotionCandidateArtifactSummary.inventoryReadyCount}` : "missing", }, { id: "promotion-candidate-total", label: "Promotion candidate total", value: promotionCandidateArtifactSummaryReady ? `${promotionCandidateArtifactSummary.totalCandidateCount}` : "missing", }, { id: "promotion-candidate-artifact-rows", label: "Promotion candidate artifact rows", value: promotionCandidateArtifactSummaryReady ? `${artifactRows.promotionCandidates}` : "missing", }, { id: "evidence-expansion-candidates", label: "Evidence expansion candidates", value: promotionCandidateArtifactSummaryReady ? `${promotionCandidateArtifactSummary.evidenceExpansionCandidateCount}` : "missing", }, { id: "evidence-expansion-artifact-rows", label: "Evidence expansion artifact rows", value: promotionCandidateArtifactSummaryReady ? `${artifactRows.evidenceExpansion}` : "missing", }, { id: "evidence-expansion-next-evidence", label: "Evidence expansion next evidence", value: promotionCandidateArtifactSummaryReady ? promotionCandidateArtifactSummary.evidenceExpansion.nextEvidence : "missing", }, { id: "evidence-expansion-baseline-changing", label: "Evidence expansion baseline changing", value: promotionCandidateArtifactSummaryReady ? (promotionCandidateArtifactSummary.evidenceExpansion.baselineChanging ? "yes" : "no") : "missing", }, { id: "evidence-expansion-artifact", label: "Evidence expansion artifact", value: promotionCandidateArtifactSummaryReady ? promotionCandidateArtifactSummary.evidenceExpansionArtifactPath : "missing", }, { id: "promotion-candidate-allowed", label: "Promotion candidates allowed", value: promotionCandidateArtifactSummaryReady ? `${promotionCandidateArtifactSummary.promotionAllowedCount}` : "missing", }, { id: "virtual-hal-promotion-families", label: "Virtual HAL promotion families", value: virtualHalPromotionFamilySummary, }, ...virtualHalPromotionFamilyRows.map((row) => ({ id: `virtual-hal-promotion-family-${row.id}`, label: `Promotion family ${row.label}`, value: row.value, sourceFiles: row.sourceFiles, })), { id: "virtual-hal-sim-config-macro-load-fixtures", label: "Virtual HAL sim-config macro/load fixtures", value: virtualHalSimConfigMacroLoadFixturesReady ? "ready" : "missing", }, { id: "virtual-hal-motion-controller-matrix", label: "Virtual HAL motion controller matrix", value: virtualHalMotionControllerMatrixReady ? "ready" : "missing", }, { id: "tool-db-process-proof", label: "Tool DB process proof", value: toolDbProcessProofReady ? "ready" : "missing", }, { id: "tool-db-process-proof-detail", label: "Tool DB process proof detail", value: toolDbProcessProofReady ? `wasm=${toolDbProcessProofSummary.wasmProtocolReady ? "ready" : "missing"} browser=${toolDbProcessProofSummary.browserProtocolReady ? "ready" : "missing"} opfs=${toolDbProcessProofSummary.opfsPersistenceReady ? "ready" : "missing"} promotion_allowed=${toolDbProcessProofSummary.promotionAllowed ? "1" : "0"}` : "missing", }, { id: "python-remap-runtime-proof", label: "Python remap runtime proof", value: pythonRemapRuntimeProofSummary.ready === true ? "ready" : "locked", }, { id: "python-remap-runtime-proof-detail", label: "Python remap runtime proof detail", value: pythonRemapRuntimeProofSummary.apiName ? `native=${pythonRemapRuntimeProofSummary.nativeLifecycleReady ? "ready" : "missing"} wasm=${pythonRemapRuntimeProofSummary.wasmLifecycleReady ? "ready" : "missing"} browser=${pythonRemapRuntimeProofSummary.browserLifecycleReady ? "ready" : "missing"} promotion_allowed=${pythonRemapRuntimeProofSummary.promotionAllowed ? "1" : "0"}` : "missing", }, { id: "blocked-runtime-families", label: "Blocked runtime families", value: promotedBlockedFamilies.length > 0 ? `promoted: ${promotedBlockedFamilies.join(", ")}` : (blockedRuntimeFamilies.join(", ") || "none"), }, { id: "hard-block-runtime-lock", label: "Hard-block runtime lock", value: hardBlockRuntimeLockSummary.lockValue, }, { id: "promoted-blocked-family-count", label: "Promoted blocked families", value: hardBlockRuntimeLockSummary.promotedCountValue, }, { id: "axis-screenshot-artifacts", label: "AXIS screenshot artifacts", value: axisScreenshotArtifacts.length > 0 ? `${axisScreenshotArtifacts.length} captured` : "not captured", }, { id: "validation", label: "Artifact validation", value: missing.length === 0 ? "ready" : missing.join(", "), }, ], }; }