上传真实浏览器仿真推进

结论:新增 LinuxCNC WASM 驱动的真实浏览器仿真页面,接入 browser smoke、release gate、SDK 与项目交付文档,并完成当前推进批次的验收记录。
This commit is contained in:
2026-06-16 20:59:21 +08:00
parent 19eabdf06e
commit 24e1fc18b1
39 changed files with 7563 additions and 59 deletions

View File

@@ -1,6 +1,18 @@
export { createLinuxCncIniSdk } from "./linuxcnc-ini.js";
export { createLinuxCncInterpSdk } from "./linuxcnc-interp.js";
export {
createProjectBatchAcceptanceActionPlan,
createProjectBatchAcceptanceCapabilityMatrix,
createProjectBatchAcceptanceChecklist,
createProjectBatchAcceptanceReport,
createProjectBatchAcceptanceReportJsonWorkflow,
createProjectBatchAcceptanceReportUrlWorkflowActionPlan,
createProjectBatchAcceptanceReportUrlWorkflowSummaryViewModel,
createProjectBatchAcceptanceReportValidationActionPlan,
createProjectBatchAcceptanceReportValidationSummaryViewModel,
createProjectBatchAcceptanceReportValidation,
createProjectBatchAcceptanceSummaryViewModel,
createProjectBatchAcceptanceWorkflow,
createProjectReleaseGateActionPlan,
createProjectReleaseGateExecutionManifest,
createProjectReleaseGateExecutionSummaryViewModel,
@@ -14,6 +26,7 @@ export {
createProjectReleaseReadinessArtifactValidationSummaryViewModel,
createProjectReleaseReadinessReport,
createProjectReleaseReadinessSummaryViewModel,
loadProjectBatchAcceptanceReportUrlWorkflow,
loadProjectReleaseReadinessArtifactUrlWorkflow,
parseProjectReleaseReadinessArtifactJson,
} from "./project-release-readiness.js";
@@ -109,8 +122,27 @@ export {
createIniPanelShellWorkflowOverviewEmbeddingMountRenderState,
createIniPanelShellWorkflowOverviewEmbeddingRenderState,
createIniPanelShellWorkflowOverviewEmbeddingReport,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomReadiness,
@@ -125,6 +157,14 @@ export {
isSupportedIniPanelShellSessionHandoffPackage,
isSupportedIniPanelShellSessionHandoffSummary,
loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl,
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract,
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness,
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
mountIniPanelShellSessionHandoff,
mountIniPanelShellWorkflowOverviewEmbedding,
mountIniPanelShellWorkflowOverviewEmbeddingMountState,

View File

@@ -46,6 +46,12 @@ const REQUIRED_RELEASE_GATES = [
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",
@@ -336,6 +342,864 @@ export function createProjectReleaseGateActionPlan({
};
}
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 = [],
} = {}) {
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 ready = capabilityMatrix.ready && batchGatePassed;
const missing = [
...capabilityMatrix.missing,
...(batchGatePassed ? [] : ["project-batch-acceptance"]),
];
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,
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: "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: "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 = [],
} = {}) {
const capabilityMatrix = createProjectBatchAcceptanceCapabilityMatrix({ capabilities });
const workflow = createProjectBatchAcceptanceWorkflow({
batchId,
capabilities,
gateResults,
observedOutputs,
});
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,
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 rows = arrayOrEmpty(reportObject.rows);
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"]),
...(rows.find(({ id, value }) => id === "checklist" && value === "3/3 passed")
? []
: ["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,
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: "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 = [],