新增项目发布 readiness SDK report

This commit is contained in:
2026-06-16 09:09:18 +08:00
parent d3ee5d49ff
commit ae3adf2d13
8 changed files with 287 additions and 4 deletions

View File

@@ -47,6 +47,7 @@ import {
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createMachineSessionSnapshotPayload,
createProjectReleaseReadinessReport,
createSessionSnapshot,
defaultMachinePaths,
gcodeFilenameFromProgramPath,
@@ -176,6 +177,20 @@ path but keeps the runner loop going after LinuxCNC reports an error, matching
upstream `rs274 -n 0` regression tests such as `tests/interp/oword-unwind`.
It does not implement or reinterpret LinuxCNC error semantics.
## Project release readiness export
`createProjectReleaseReadinessReport()` returns a machine-readable release
readiness report for CI dashboards and external SDK callers. The report lists
the required project release gate command, expected smoke outputs, the current
sim-config inventory baseline, and blocked runtime families. It is evidence
driven: the default report is `ready: false` until the caller supplies observed
gate output such as `project_release_gate=ok` or explicit gate results.
This helper does not execute shell commands and does not inspect or implement
CNC behavior. It only packages project-level release evidence and blocked
runtime policy that are already documented in `docs/project-release-handoff.md`
and `../PROJECT_COMPLETION_TRACKER.md`.
## OPFS/session persistence exports
The SDK entrypoint re-exports the OPFS/session persistence helpers used by the

View File

@@ -1,5 +1,6 @@
export { createLinuxCncIniSdk } from "./linuxcnc-ini.js";
export { createLinuxCncInterpSdk } from "./linuxcnc-interp.js";
export { createProjectReleaseReadinessReport } from "./project-release-readiness.js";
export {
analyzeIniRuntimeBoundaries,
planIniFileContextStaging,

View File

@@ -0,0 +1,154 @@
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: "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: 28,
passed: 28,
skipped: 131,
unexpectedFail: 0,
};
const BLOCKED_RUNTIME_FAMILIES = [
"L4-USER-M-PROCESS",
"L4-TOOL-DB",
"L4-PYTHON-REMAP",
];
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;
}
export function createProjectReleaseReadinessReport({
gateResults = {},
observedOutputs = [],
simConfigInventory = DEFAULT_SIM_CONFIG_INVENTORY_BASELINE,
blockedRuntimeFamilies = BLOCKED_RUNTIME_FAMILIES,
promotedRuntimeFamilies = [],
} = {}) {
const outputs = Array.isArray(observedOutputs) ? observedOutputs : [];
const gateRows = REQUIRED_RELEASE_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,
};
});
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 blockedRuntimeReady = promotedBlockedFamilies.length === 0;
const ready = releaseGatePassed && inventoryReady && blockedRuntimeReady;
const missing = [
...(releaseGatePassed ? [] : ["project-release-gate"]),
...(inventoryReady ? [] : ["sim-config-inventory"]),
...(blockedRuntimeReady ? [] : ["blocked-runtime-families"]),
];
return {
apiName: "project-release-readiness-report",
reportVersion: 1,
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,
blockedRuntimeFamilies: blockedFamilies,
promotedRuntimeFamilies: promotedFamilies,
promotedBlockedFamilies,
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: "blocked-runtime-families",
label: "Blocked runtime families",
value: blockedRuntimeReady ? blockedFamilies.join(", ") : `promoted: ${promotedBlockedFamilies.join(", ")}`,
},
],
};
}