Files
cnc_wams/wasm-port/runtime/ui/ini-panel/ui-shell.js
wangdequan 8a1c4699b1 按接续文件text31持续推进
结论:已将五项evidence expansion从API/smoke推进到real simulation diagnostics panel和release URL/INI workflow完整列表可见面;baseline保持82/82/77/0,promotionAllowed保持false。
2026-06-20 08:26:55 +08:00

6953 lines
264 KiB
JavaScript

import {
INI_PANEL_ENTRIES,
getIniPanelEntryByHref,
getIniPanelEntryManifest,
} from "./entry-manifest.js";
import {
createMachineSessionControlPageController,
} from "./control-page-controller.js";
import {
renderMachineSessionControlView,
} from "./control-view-renderer.js";
import {
controlPageStatusText,
createControlPageRefreshState,
refreshMachineSessionControlPage,
} from "./control-page-refresh-workflow.js";
import {
createControlPageSessionLoadState,
loadMachineSessionForControlPageWorkflow,
} from "./control-page-session-workflow.js";
import {
createMachineSessionReadinessFieldState,
machineSessionReadinessLogLines,
readMachineSessionReadinessWorkflow,
} from "./session-workflow.js";
import {
createMachineSessionReadonlyStatus,
createMachineSessionReadonlyStatusApiManifest,
readMachineSessionReadonlyStatus,
} from "./readonly-status-api.js";
import {
createMachineSessionPersistenceSummary,
} from "./panel-state-summary.js";
import {
createProjectReleaseGateExecutionSummaryViewModel,
createProjectReleaseReadinessArtifactJsonWorkflow,
createProjectReleaseReadinessArtifactUrlWorkflowActionPlan,
createProjectReleaseReadinessArtifactValidation,
createProjectReleaseReadinessArtifactValidationActionPlan,
createProjectReleaseReadinessArtifactValidationSummaryViewModel,
loadProjectReleaseReadinessArtifactUrlWorkflow,
parseProjectReleaseReadinessArtifactJson,
} from "../../sdk/src/project-release-readiness.js";
export {
controlPageStatusText,
createControlPageRefreshState,
refreshMachineSessionControlPage,
} from "./control-page-refresh-workflow.js";
export {
createControlPageSessionLoadState,
loadMachineSessionForControlPageWorkflow,
} from "./control-page-session-workflow.js";
export {
createMachineSessionReadinessFieldState,
machineSessionReadinessLogLines,
readMachineSessionReadinessWorkflow,
} from "./session-workflow.js";
export {
createMachineSessionReadonlyStatus,
createMachineSessionReadonlyStatusApiManifest,
readMachineSessionReadonlyStatus,
} from "./readonly-status-api.js";
export {
INI_PANEL_ENTRIES,
getIniPanelEntryByHref,
getIniPanelEntryManifest,
} from "./entry-manifest.js";
export {
createMachineSessionControlPageController,
} from "./control-page-controller.js";
export {
renderMachineSessionControlView,
} from "./control-view-renderer.js";
export {
createMachineSessionControlView,
createMachineSessionPersistenceDisplayViewModel,
createMachineSessionPersistenceRenderState,
createMachineSessionPersistenceSummary,
createMachineSessionStateBundle,
createMachineSessionStateReport,
createMachineSessionStateReportExport,
createMachineSessionWorkflowOverview,
createMachineSessionWorkflowStatus,
} from "./panel-state-summary.js";
export {
createProjectReleaseGateExecutionSummaryViewModel,
createProjectReleaseReadinessArtifactJsonWorkflow,
createProjectReleaseReadinessArtifactUrlWorkflowActionPlan,
createProjectReleaseReadinessArtifactValidation,
createProjectReleaseReadinessArtifactValidationActionPlan,
createProjectReleaseReadinessArtifactValidationSummaryViewModel,
loadProjectReleaseReadinessArtifactUrlWorkflow,
parseProjectReleaseReadinessArtifactJson,
} from "../../sdk/src/project-release-readiness.js";
export function getVisibleIniPanelEntries() {
return getIniPanelEntryManifest();
}
export function createIniPanelLauncherLinkViewModel(entries = getVisibleIniPanelEntries()) {
return entries.map(({ id, href, title }) => ({
entryId: id,
href,
label: title,
}));
}
export function createIniPanelLaunchApiSchema() {
return {
apiName: "ini-panel-launch",
manifestVersion: 1,
fields: [
"apiName",
"manifestVersion",
"methods",
"visibleEntries",
"targetPages",
"controlPageApiMethods",
"persistenceCapabilities",
],
};
}
export function isSupportedIniPanelLaunchApiManifest(manifest, schema = createIniPanelLaunchApiSchema()) {
if (!manifest || typeof manifest !== "object") {
return false;
}
if (manifest.apiName !== schema.apiName || manifest.manifestVersion !== schema.manifestVersion) {
return false;
}
return schema.fields.every((fieldName) => Object.hasOwn(manifest, fieldName));
}
export function createControlPageBrowserApiSchema() {
return {
apiName: "ini-panel-control-page",
manifestVersion: 1,
fields: [
"apiName",
"manifestVersion",
"methods",
"contract",
"readonlyStatusApiManifest",
],
};
}
export function isSupportedIniPanelControlPageApiManifest(
manifest,
schema = createControlPageBrowserApiSchema(),
) {
if (!manifest || typeof manifest !== "object") {
return false;
}
if (manifest.apiName !== schema.apiName || manifest.manifestVersion !== schema.manifestVersion) {
return false;
}
return schema.fields.every((fieldName) => Object.hasOwn(manifest, fieldName));
}
export function createIniPanelLaunchApiManifest(entries = getVisibleIniPanelEntries()) {
const schema = createIniPanelLaunchApiSchema();
return {
apiName: schema.apiName,
manifestVersion: schema.manifestVersion,
methods: [
"isSupportedLaunchApiManifest",
"getLaunchApiSchema",
"getLaunchApiManifest",
"getShellIntegrationSchema",
"getShellIntegrationManifest",
"getShellIntegrationReadiness",
"getShellSessionHandoffSummarySchema",
"getShellSessionHandoffSummary",
"isSupportedShellSessionHandoffSummary",
"getShellSessionHandoffCompatibilityReport",
"getShellSessionHandoffDisplayViewModel",
"getShellSessionHandoffSnapshot",
"getShellSessionHandoffRenderState",
"getShellSessionHandoffActionPlan",
"getShellSessionHandoffChecklist",
"getShellSessionHandoffPackageSchema",
"getShellSessionHandoffPackage",
"getShellSessionHandoffPackageReport",
"getShellSessionHandoffPackageDisplayViewModel",
"getShellSessionHandoffPackageRenderState",
"getShellSessionHandoffPackageMountState",
"getShellSessionHandoffPackageMountDisplayViewModel",
"getShellSessionHandoffPackageMountRenderState",
"getShellSessionHandoffMountDomContract",
"getShellSessionHandoffMountDomReadiness",
"renderShellSessionHandoffMountState",
"mountShellSessionHandoff",
"mountShellSessionHandoffFromControlPage",
"readShellSessionHandoffStatusFromControlPage",
"getMachineSessionPersistenceSummary",
"getShellSessionHandoffWorkflowSummary",
"getShellSessionReadinessWorkflowReport",
"getShellApiSurfaceInventory",
"getShellSessionHandoffWorkflowDisplayViewModel",
"getShellSessionHandoffWorkflowRenderState",
"getShellSessionHandoffWorkflowDomContract",
"getShellSessionHandoffWorkflowDomReadiness",
"renderShellSessionHandoffWorkflowState",
"mountShellSessionHandoffWorkflow",
"getWorkflowOverviewContract",
"getWorkflowOverviewReadiness",
"mountWorkflowOverviewEmbedding",
"runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"loadWorkflowOverviewReleaseReadinessArtifactUrl",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState",
"getWorkflowOverviewPromotionFamilyRowsRenderState",
"getWorkflowOverviewPromotionFamilySourceFilterViewModel",
"getWorkflowOverviewPromotionFamilySourceFilterDomContract",
"getWorkflowOverviewPromotionFamilySourceFilterDomReadiness",
"getWorkflowOverviewPromotionFamilySourceFilterSelectionActionPlan",
"handleWorkflowOverviewPromotionFamilySourceFilterSelectionChange",
"bindWorkflowOverviewPromotionFamilySourceFilterSelectionControls",
"renderWorkflowOverviewPromotionFamilySourceFilterState",
"mountWorkflowOverviewPromotionFamilySourceFilterState",
"getWorkflowOverviewPromotionFamilyRowsDomContract",
"getWorkflowOverviewPromotionFamilyRowsDomReadiness",
"renderWorkflowOverviewPromotionFamilyRowsState",
"mountWorkflowOverviewPromotionFamilyRowsState",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"getWorkflowOverviewEmbeddingReport",
"getWorkflowOverviewEmbeddingDisplayViewModel",
"getWorkflowOverviewEmbeddingRenderState",
"getWorkflowOverviewEmbeddingDomContract",
"getWorkflowOverviewEmbeddingDomReadiness",
"renderWorkflowOverviewEmbeddingState",
"mountWorkflowOverviewEmbeddingState",
"getWorkflowOverviewEmbeddingMountDisplayViewModel",
"getWorkflowOverviewEmbeddingMountRenderState",
"getWorkflowOverviewEmbeddingMountDomContract",
"getWorkflowOverviewEmbeddingMountDomReadiness",
"renderWorkflowOverviewEmbeddingMountState",
"mountWorkflowOverviewEmbeddingMountState",
"isSupportedShellSessionHandoffPackage",
"getLauncherLinks",
"getControlPageApiMethods",
],
visibleEntries: entries.map(({ id, href, title }) => ({
id,
href,
title,
})),
targetPages: entries.map(({ id, href }) => ({
entryId: id,
href,
})),
controlPageApiMethods: createControlPageBrowserApiMethods(),
persistenceCapabilities: [
{
id: "machine-files",
label: "Machine text files",
scope: "opfs",
},
{
id: "session-snapshot",
label: "Machine session snapshot",
scope: "opfs",
},
{
id: "readonly-status",
label: "Read-only machine session status",
scope: "control-page",
},
],
};
}
export function createIniPanelShellControlPageContract() {
const readonlyStatusApiManifest = createMachineSessionReadonlyStatusApiManifest();
return {
methodNames: [
"createController",
"loadSessionState",
"readStatus",
"refresh",
"renderView",
],
readonlyStatusApiManifest,
readonlyStatusApiMethodNames: Object.keys(readonlyStatusApiManifest.methods),
readonlyStatusApiStatusFields: readonlyStatusApiManifest.statusFields,
relatedControlPageMethods: readonlyStatusApiManifest.relatedControlPageMethods,
};
}
export function createControlPageBrowserApiMethods() {
return [
"isSupportedControlPageApiManifest",
"getControlPageApiSchema",
"getControlPageApiManifest",
"getControlPageApiMethods",
"getControlPageContract",
"getControlView",
"getPanelApi",
"loadControlPageSessionState",
"readControlPageStatus",
"refreshControlPage",
"renderControlPage",
];
}
export function createControlPageBrowserApiManifest() {
const schema = createControlPageBrowserApiSchema();
const contract = createIniPanelShellControlPageContract();
return {
apiName: schema.apiName,
manifestVersion: schema.manifestVersion,
methods: createControlPageBrowserApiMethods(),
contract,
readonlyStatusApiManifest: contract.readonlyStatusApiManifest,
};
}
export function createIniPanelShellIntegrationSchema() {
return {
apiName: "ini-panel-shell-integration",
manifestVersion: 1,
fields: [
"apiName",
"manifestVersion",
"pages",
"launcherLinks",
"launchApiSchema",
"launchApiManifest",
"controlPageApiSchema",
"controlPageApiManifest",
"compatibility",
"persistenceCapabilities",
],
};
}
export function isSupportedIniPanelShellIntegrationManifest(
manifest,
schema = createIniPanelShellIntegrationSchema(),
) {
if (!manifest || typeof manifest !== "object") {
return false;
}
if (manifest.apiName !== schema.apiName || manifest.manifestVersion !== schema.manifestVersion) {
return false;
}
return schema.fields.every((fieldName) => Object.hasOwn(manifest, fieldName));
}
export function createIniPanelShellIntegrationManifest(entries = getVisibleIniPanelEntries()) {
const schema = createIniPanelShellIntegrationSchema();
const launchApiSchema = createIniPanelLaunchApiSchema();
const launchApiManifest = createIniPanelLaunchApiManifest(entries);
const controlPageApiSchema = createControlPageBrowserApiSchema();
const controlPageApiManifest = createControlPageBrowserApiManifest();
return {
apiName: schema.apiName,
manifestVersion: schema.manifestVersion,
pages: entries.map(({ id, href, title }) => ({
id,
href,
title,
})),
launcherLinks: createIniPanelLauncherLinkViewModel(entries),
launchApiSchema,
launchApiManifest,
controlPageApiSchema,
controlPageApiManifest,
compatibility: {
launchApiManifest: isSupportedIniPanelLaunchApiManifest(launchApiManifest, launchApiSchema),
controlPageApiManifest: isSupportedIniPanelControlPageApiManifest(
controlPageApiManifest,
controlPageApiSchema,
),
},
persistenceCapabilities: launchApiManifest.persistenceCapabilities,
};
}
export function createIniPanelShellIntegrationReadiness(
manifest = createIniPanelShellIntegrationManifest(),
) {
const integrationManifestSupported = isSupportedIniPanelShellIntegrationManifest(manifest);
const launchApiManifestSupported = integrationManifestSupported
&& isSupportedIniPanelLaunchApiManifest(manifest.launchApiManifest, manifest.launchApiSchema);
const controlPageApiManifestSupported = integrationManifestSupported
&& isSupportedIniPanelControlPageApiManifest(
manifest.controlPageApiManifest,
manifest.controlPageApiSchema,
);
const compatibility = integrationManifestSupported && manifest.compatibility
? {
launchApiManifest: Boolean(manifest.compatibility.launchApiManifest),
controlPageApiManifest: Boolean(manifest.compatibility.controlPageApiManifest),
}
: {
launchApiManifest: false,
controlPageApiManifest: false,
};
const checks = {
integrationManifestSupported,
launchApiManifestSupported,
controlPageApiManifestSupported,
launchCompatibility: compatibility.launchApiManifest,
controlPageCompatibility: compatibility.controlPageApiManifest,
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
phase: ready ? "ready" : "blocked",
ready,
checks,
missing,
counts: {
pages: Array.isArray(manifest?.pages) ? manifest.pages.length : 0,
launcherLinks: Array.isArray(manifest?.launcherLinks) ? manifest.launcherLinks.length : 0,
launchMethods: Array.isArray(manifest?.launchApiManifest?.methods)
? manifest.launchApiManifest.methods.length
: 0,
controlPageMethods: Array.isArray(manifest?.controlPageApiManifest?.methods)
? manifest.controlPageApiManifest.methods.length
: 0,
persistenceCapabilities: Array.isArray(manifest?.persistenceCapabilities)
? manifest.persistenceCapabilities.length
: 0,
},
apiNames: {
integration: manifest?.apiName ?? null,
launch: manifest?.launchApiManifest?.apiName ?? null,
controlPage: manifest?.controlPageApiManifest?.apiName ?? null,
},
};
}
export function createIniPanelShellIntegrationWorkflowPlan({
manifest = createIniPanelShellIntegrationManifest(),
readiness = createIniPanelShellIntegrationReadiness(manifest),
controlEntryId = "control-view",
} = {}) {
const targetPage = manifest?.launchApiManifest?.targetPages?.find(
(page) => page.entryId === controlEntryId,
) ?? null;
const requiredLaunchApiMethods = [
"getShellIntegrationManifest",
"getShellIntegrationReadiness",
];
const requiredControlPageApiMethods = [
"getControlPageApiManifest",
"loadControlPageSessionState",
"readControlPageStatus",
];
const launchMethods = Array.isArray(manifest?.launchApiManifest?.methods)
? manifest.launchApiManifest.methods
: [];
const controlPageMethods = Array.isArray(manifest?.controlPageApiManifest?.methods)
? manifest.controlPageApiManifest.methods
: [];
const missingLaunchApiMethods = requiredLaunchApiMethods.filter(
(methodName) => !launchMethods.includes(methodName),
);
const missingControlPageApiMethods = requiredControlPageApiMethods.filter(
(methodName) => !controlPageMethods.includes(methodName),
);
const missing = [
...readiness.missing,
...(targetPage ? [] : ["controlTargetPage"]),
...missingLaunchApiMethods.map((methodName) => `launchApi.${methodName}`),
...missingControlPageApiMethods.map((methodName) => `controlPageApi.${methodName}`),
];
const ready = readiness.ready && missing.length === 0;
return {
phase: ready ? "ready" : "blocked",
ready,
controlEntryId,
targetPage,
readiness,
requiredLaunchApiMethods,
requiredControlPageApiMethods,
missingLaunchApiMethods,
missingControlPageApiMethods,
missing,
readonlyStatusHandoff: {
loadSessionStateMethod: "loadControlPageSessionState",
readStatusMethod: "readControlPageStatus",
expectedStatusFields: manifest?.controlPageApiManifest?.readonlyStatusApiManifest?.statusFields ?? [],
},
};
}
export function createIniPanelShellSessionHandoffSummarySchema() {
return {
apiName: "ini-panel-shell-session-handoff-summary",
summaryVersion: 1,
fields: [
"apiName",
"summaryVersion",
"phase",
"ready",
"targetPage",
"readiness",
"persistenceCapabilities",
"readonlyStatusFields",
"handoffMethods",
"blockingReasons",
],
};
}
export function isSupportedIniPanelShellSessionHandoffSummary(
summary,
schema = createIniPanelShellSessionHandoffSummarySchema(),
) {
if (!summary || typeof summary !== "object") {
return false;
}
if (summary.apiName !== schema.apiName || summary.summaryVersion !== schema.summaryVersion) {
return false;
}
return schema.fields.every((fieldName) => Object.hasOwn(summary, fieldName));
}
export function createIniPanelShellSessionHandoffSummary({
manifest = createIniPanelShellIntegrationManifest(),
readiness = createIniPanelShellIntegrationReadiness(manifest),
workflowPlan = createIniPanelShellIntegrationWorkflowPlan({ manifest, readiness }),
} = {}) {
const schema = createIniPanelShellSessionHandoffSummarySchema();
const persistenceCapabilities = Array.isArray(manifest?.persistenceCapabilities)
? manifest.persistenceCapabilities.map(({ id, label, scope }) => ({ id, label, scope }))
: [];
const readonlyStatusFields = Array.isArray(workflowPlan?.readonlyStatusHandoff?.expectedStatusFields)
? [...workflowPlan.readonlyStatusHandoff.expectedStatusFields]
: [];
return {
apiName: schema.apiName,
summaryVersion: schema.summaryVersion,
phase: workflowPlan.ready ? "ready" : "blocked",
ready: Boolean(workflowPlan.ready),
targetPage: workflowPlan.targetPage,
readiness: {
phase: readiness.phase,
missing: [...readiness.missing],
counts: { ...readiness.counts },
apiNames: { ...readiness.apiNames },
},
persistenceCapabilities,
readonlyStatusFields,
handoffMethods: {
loadSessionState: workflowPlan.readonlyStatusHandoff.loadSessionStateMethod,
readStatus: workflowPlan.readonlyStatusHandoff.readStatusMethod,
},
blockingReasons: [...workflowPlan.missing],
};
}
export function createIniPanelShellSessionHandoffCompatibilityReport(
summary = createIniPanelShellSessionHandoffSummary(),
schema = createIniPanelShellSessionHandoffSummarySchema(),
) {
const summaryObject = summary && typeof summary === "object" ? summary : {};
const missingFields = schema.fields.filter((fieldName) => !Object.hasOwn(summaryObject, fieldName));
const mismatchFields = [
...(summaryObject.apiName === schema.apiName ? [] : ["apiName"]),
...(summaryObject.summaryVersion === schema.summaryVersion ? [] : ["summaryVersion"]),
];
const summarySupported = missingFields.length === 0 && mismatchFields.length === 0;
const blockingReasons = Array.isArray(summaryObject.blockingReasons)
? [...summaryObject.blockingReasons]
: [];
const handoffReady = summarySupported && summaryObject.ready === true && blockingReasons.length === 0;
return {
apiName: "ini-panel-shell-session-handoff-compatibility-report",
reportVersion: 1,
phase: handoffReady ? "ready" : "blocked",
compatible: handoffReady,
summarySupported,
handoffReady,
schema: {
apiName: schema.apiName,
summaryVersion: schema.summaryVersion,
fields: [...schema.fields],
},
summary: {
apiName: summaryObject.apiName ?? null,
summaryVersion: summaryObject.summaryVersion ?? null,
phase: summaryObject.phase ?? null,
ready: summaryObject.ready ?? false,
},
missingFields,
mismatchFields,
blockingReasons,
};
}
export function createIniPanelShellSessionHandoffDisplayViewModel(
report = createIniPanelShellSessionHandoffCompatibilityReport(),
) {
const missingFields = Array.isArray(report?.missingFields) ? report.missingFields : [];
const mismatchFields = Array.isArray(report?.mismatchFields) ? report.mismatchFields : [];
const blockingReasons = Array.isArray(report?.blockingReasons) ? report.blockingReasons : [];
const problems = [...missingFields, ...mismatchFields, ...blockingReasons];
return {
phase: report?.phase === "ready" ? "ready" : "blocked",
title: "Shell handoff compatibility",
statusText: report?.compatible ? "Ready" : "Blocked",
detailText: problems.length === 0 ? "No blocking reasons" : problems.join(", "),
rows: [
{
id: "summary-supported",
label: "Summary schema",
value: report?.summarySupported ? "supported" : "blocked",
},
{
id: "handoff-ready",
label: "Handoff readiness",
value: report?.handoffReady ? "ready" : "blocked",
},
{
id: "missing-fields",
label: "Missing fields",
value: missingFields.length === 0 ? "none" : missingFields.join(", "),
},
{
id: "mismatch-fields",
label: "Mismatched fields",
value: mismatchFields.length === 0 ? "none" : mismatchFields.join(", "),
},
{
id: "blocking-reasons",
label: "Blocking reasons",
value: blockingReasons.length === 0 ? "none" : blockingReasons.join(", "),
},
],
};
}
export function createIniPanelShellSessionHandoffSnapshot({
readiness = createIniPanelShellIntegrationReadiness(),
summary = createIniPanelShellSessionHandoffSummary(),
compatibilityReport = createIniPanelShellSessionHandoffCompatibilityReport(summary),
displayViewModel = createIniPanelShellSessionHandoffDisplayViewModel(compatibilityReport),
} = {}) {
return {
apiName: "ini-panel-shell-session-handoff-snapshot",
snapshotVersion: 1,
phase: compatibilityReport.phase,
ready: Boolean(compatibilityReport.compatible),
readiness,
summary,
compatibilityReport,
displayViewModel,
};
}
export function createIniPanelShellSessionHandoffRenderState(
snapshot = createIniPanelShellSessionHandoffSnapshot(),
) {
const displayViewModel = snapshot?.displayViewModel && typeof snapshot.displayViewModel === "object"
? snapshot.displayViewModel
: createIniPanelShellSessionHandoffDisplayViewModel(snapshot?.compatibilityReport);
const rows = Array.isArray(displayViewModel.rows)
? displayViewModel.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const ready = snapshot?.ready === true && displayViewModel.phase === "ready";
const statusText = displayViewModel.statusText ?? (ready ? "Ready" : "Blocked");
const detailText = displayViewModel.detailText ?? "No blocking reasons";
return {
apiName: "ini-panel-shell-session-handoff-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: displayViewModel.title ?? "Shell handoff compatibility",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
},
};
}
export function createIniPanelShellSessionHandoffActionPlan({
snapshot = createIniPanelShellSessionHandoffSnapshot(),
renderState = createIniPanelShellSessionHandoffRenderState(snapshot),
} = {}) {
const summary = snapshot?.summary && typeof snapshot.summary === "object" ? snapshot.summary : {};
const handoffMethods = summary.handoffMethods && typeof summary.handoffMethods === "object"
? summary.handoffMethods
: {};
const blockingReasons = Array.isArray(summary.blockingReasons)
? [...summary.blockingReasons]
: [];
const displayRows = Array.isArray(renderState?.rows) ? renderState.rows.map(({ id, label, value }) => ({
id,
label,
value,
})) : [];
const ready = snapshot?.ready === true && renderState?.ready === true && blockingReasons.length === 0;
return {
apiName: "ini-panel-shell-session-handoff-action-plan",
planVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
statusLine: renderState?.statusLine ?? "Blocked: No handoff render state",
targetPage: summary.targetPage ?? null,
requiredMethods: {
loadSessionState: handoffMethods.loadSessionState ?? null,
readStatus: handoffMethods.readStatus ?? null,
},
blockingReasons,
displayRows,
nextSteps: ready
? [
{
id: "open-control-page",
label: "Open control page target",
targetPage: summary.targetPage ?? null,
},
{
id: "read-readonly-status",
label: "Read readonly status",
methods: {
loadSessionState: handoffMethods.loadSessionState ?? null,
readStatus: handoffMethods.readStatus ?? null,
},
},
]
: [
{
id: "resolve-blockers",
label: "Resolve handoff blockers",
blockingReasons,
displayRows,
},
],
};
}
export function createIniPanelShellSessionHandoffChecklist({
actionPlan = createIniPanelShellSessionHandoffActionPlan(),
renderState = createIniPanelShellSessionHandoffRenderState(),
} = {}) {
const displayRows = Array.isArray(actionPlan?.displayRows)
? actionPlan.displayRows.map(({ id, label, value }) => ({ id, label, value }))
: [];
const blockingReasons = Array.isArray(actionPlan?.blockingReasons)
? [...actionPlan.blockingReasons]
: [];
const targetPageReady = Boolean(actionPlan?.targetPage?.href);
const loadMethodReady = Boolean(actionPlan?.requiredMethods?.loadSessionState);
const readMethodReady = Boolean(actionPlan?.requiredMethods?.readStatus);
const ready = actionPlan?.ready === true
&& renderState?.ready === true
&& targetPageReady
&& loadMethodReady
&& readMethodReady
&& blockingReasons.length === 0;
const checks = [
{
id: "render-state",
label: "Render state",
status: renderState?.ready ? "pass" : "blocked",
value: renderState?.statusLine ?? "missing",
},
{
id: "target-page",
label: "Control target",
status: targetPageReady ? "pass" : "blocked",
value: actionPlan?.targetPage?.href ?? "missing",
},
{
id: "load-session-method",
label: "Load session method",
status: loadMethodReady ? "pass" : "blocked",
value: actionPlan?.requiredMethods?.loadSessionState ?? "missing",
},
{
id: "read-status-method",
label: "Read status method",
status: readMethodReady ? "pass" : "blocked",
value: actionPlan?.requiredMethods?.readStatus ?? "missing",
},
{
id: "blocking-reasons",
label: "Blocking reasons",
status: blockingReasons.length === 0 ? "pass" : "blocked",
value: blockingReasons.length === 0 ? "none" : blockingReasons.join(", "),
},
];
return {
apiName: "ini-panel-shell-session-handoff-checklist",
checklistVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
statusLine: actionPlan?.statusLine ?? renderState?.statusLine ?? "Blocked: No handoff action plan",
checks,
displayRows,
nextStepIds: Array.isArray(actionPlan?.nextSteps)
? actionPlan.nextSteps.map(({ id }) => id)
: [],
blockingReasons,
};
}
export function createIniPanelShellSessionHandoffPackage({
shellIntegrationManifest = createIniPanelShellIntegrationManifest(),
launchApiManifest = shellIntegrationManifest.launchApiManifest ?? createIniPanelLaunchApiManifest(),
controlPageApiManifest = shellIntegrationManifest.controlPageApiManifest ?? createControlPageBrowserApiManifest(),
snapshot = createIniPanelShellSessionHandoffSnapshot(),
renderState = createIniPanelShellSessionHandoffRenderState(snapshot),
actionPlan = createIniPanelShellSessionHandoffActionPlan({ snapshot, renderState }),
checklist = createIniPanelShellSessionHandoffChecklist({ actionPlan, renderState }),
} = {}) {
return {
apiName: "ini-panel-shell-session-handoff-package",
packageVersion: 1,
phase: checklist.phase,
ready: Boolean(checklist.ready),
statusLine: checklist.statusLine,
manifests: {
shellIntegration: shellIntegrationManifest,
launchApi: launchApiManifest,
controlPageApi: controlPageApiManifest,
launchMethods: Array.isArray(launchApiManifest?.methods) ? [...launchApiManifest.methods] : [],
controlPageMethods: Array.isArray(controlPageApiManifest?.methods) ? [...controlPageApiManifest.methods] : [],
},
snapshot,
renderState,
actionPlan,
checklist,
};
}
export function createIniPanelShellSessionHandoffPackageSchema() {
return {
apiName: "ini-panel-shell-session-handoff-package",
packageVersion: 1,
fields: [
"apiName",
"packageVersion",
"phase",
"ready",
"statusLine",
"manifests",
"snapshot",
"renderState",
"actionPlan",
"checklist",
],
manifestFields: [
"shellIntegration",
"launchApi",
"controlPageApi",
"launchMethods",
"controlPageMethods",
],
};
}
export function isSupportedIniPanelShellSessionHandoffPackage(
handoffPackage,
schema = createIniPanelShellSessionHandoffPackageSchema(),
) {
if (!handoffPackage || typeof handoffPackage !== "object") {
return false;
}
if (handoffPackage.apiName !== schema.apiName || handoffPackage.packageVersion !== schema.packageVersion) {
return false;
}
if (!schema.fields.every((fieldName) => Object.hasOwn(handoffPackage, fieldName))) {
return false;
}
const manifests = handoffPackage.manifests;
if (!manifests || typeof manifests !== "object") {
return false;
}
return schema.manifestFields.every((fieldName) => Object.hasOwn(manifests, fieldName));
}
export function createIniPanelShellSessionHandoffPackageReport(
handoffPackage = createIniPanelShellSessionHandoffPackage(),
schema = createIniPanelShellSessionHandoffPackageSchema(),
) {
const packageObject = handoffPackage && typeof handoffPackage === "object" ? handoffPackage : {};
const manifests = packageObject.manifests && typeof packageObject.manifests === "object"
? packageObject.manifests
: {};
const missingPackageFields = schema.fields.filter((fieldName) => !Object.hasOwn(packageObject, fieldName));
const missingManifestFields = schema.manifestFields.filter((fieldName) => !Object.hasOwn(manifests, fieldName));
const mismatchFields = [
...(packageObject.apiName === schema.apiName ? [] : ["apiName"]),
...(packageObject.packageVersion === schema.packageVersion ? [] : ["packageVersion"]),
];
const blockingReasons = Array.isArray(packageObject?.checklist?.blockingReasons)
? [...packageObject.checklist.blockingReasons]
: [];
const packageSupported = missingPackageFields.length === 0
&& missingManifestFields.length === 0
&& mismatchFields.length === 0;
const ready = packageSupported && packageObject.ready === true && blockingReasons.length === 0;
return {
apiName: "ini-panel-shell-session-handoff-package-report",
reportVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
packageSupported,
packageReady: ready,
statusLine: packageObject.statusLine ?? (ready ? "Ready: No blocking reasons" : "Blocked: Package unsupported"),
schema: {
apiName: schema.apiName,
packageVersion: schema.packageVersion,
fields: [...schema.fields],
manifestFields: [...schema.manifestFields],
},
package: {
apiName: packageObject.apiName ?? null,
packageVersion: packageObject.packageVersion ?? null,
phase: packageObject.phase ?? null,
ready: packageObject.ready ?? false,
},
missingPackageFields,
missingManifestFields,
mismatchFields,
blockingReasons,
rows: [
{
id: "package-supported",
label: "Package schema",
value: packageSupported ? "supported" : "blocked",
},
{
id: "package-ready",
label: "Package readiness",
value: ready ? "ready" : "blocked",
},
{
id: "missing-package-fields",
label: "Missing package fields",
value: missingPackageFields.length === 0 ? "none" : missingPackageFields.join(", "),
},
{
id: "missing-manifest-fields",
label: "Missing manifest fields",
value: missingManifestFields.length === 0 ? "none" : missingManifestFields.join(", "),
},
{
id: "mismatch-fields",
label: "Mismatched fields",
value: mismatchFields.length === 0 ? "none" : mismatchFields.join(", "),
},
{
id: "blocking-reasons",
label: "Blocking reasons",
value: blockingReasons.length === 0 ? "none" : blockingReasons.join(", "),
},
],
};
}
export function createIniPanelShellSessionHandoffPackageDisplayViewModel(
report = createIniPanelShellSessionHandoffPackageReport(),
) {
const missingPackageFields = Array.isArray(report?.missingPackageFields) ? report.missingPackageFields : [];
const missingManifestFields = Array.isArray(report?.missingManifestFields) ? report.missingManifestFields : [];
const mismatchFields = Array.isArray(report?.mismatchFields) ? report.mismatchFields : [];
const blockingReasons = Array.isArray(report?.blockingReasons) ? report.blockingReasons : [];
const problems = [
...missingPackageFields,
...missingManifestFields,
...mismatchFields,
...blockingReasons,
];
return {
phase: report?.phase === "ready" ? "ready" : "blocked",
title: "Shell handoff package",
statusText: report?.ready ? "Ready" : "Blocked",
detailText: problems.length === 0 ? "No blocking reasons" : problems.join(", "),
rows: Array.isArray(report?.rows)
? report.rows.map(({ id, label, value }) => ({
id,
label,
value,
}))
: [],
};
}
export function createIniPanelShellSessionHandoffPackageRenderState(
displayViewModel = createIniPanelShellSessionHandoffPackageDisplayViewModel(),
) {
const rows = Array.isArray(displayViewModel?.rows)
? displayViewModel.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const ready = displayViewModel?.phase === "ready" && displayViewModel?.statusText === "Ready";
const statusText = displayViewModel?.statusText ?? (ready ? "Ready" : "Blocked");
const detailText = displayViewModel?.detailText ?? "No blocking reasons";
return {
apiName: "ini-panel-shell-session-handoff-package-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: displayViewModel?.title ?? "Shell handoff package",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "package",
},
};
}
export function createIniPanelShellSessionHandoffPackageMountState({
handoffPackage = createIniPanelShellSessionHandoffPackage(),
packageRenderState = createIniPanelShellSessionHandoffPackageRenderState(),
sessionLoadState = createControlPageSessionLoadState({ phase: "waiting-panel" }),
} = {}) {
const actionPlan = handoffPackage?.actionPlan && typeof handoffPackage.actionPlan === "object"
? handoffPackage.actionPlan
: {};
const requiredMethods = actionPlan.requiredMethods && typeof actionPlan.requiredMethods === "object"
? actionPlan.requiredMethods
: {};
const targetPage = actionPlan.targetPage ?? null;
const blockingReasons = [
...(Array.isArray(actionPlan.blockingReasons) ? actionPlan.blockingReasons : []),
...(sessionLoadState?.phase === "error" ? ["controlPageSessionError"] : []),
];
const packageReady = handoffPackage?.ready === true && packageRenderState?.ready === true;
const targetReady = Boolean(targetPage?.href);
const methodsReady = Boolean(requiredMethods.loadSessionState && requiredMethods.readStatus);
const sessionReady = sessionLoadState?.phase === "ready";
const ready = packageReady && targetReady && methodsReady && sessionReady && blockingReasons.length === 0;
return {
apiName: "ini-panel-shell-session-handoff-package-mount-state",
mountStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
packageReady,
targetReady,
methodsReady,
sessionReady,
statusLine: ready
? "Ready: Control page session mounted"
: `Blocked: ${blockingReasons.length === 0 ? sessionLoadState?.phase ?? "waiting-panel" : blockingReasons.join(", ")}`,
packageRenderState,
targetPage,
requiredMethods: {
loadSessionState: requiredMethods.loadSessionState ?? null,
readStatus: requiredMethods.readStatus ?? null,
},
sessionLoadState,
blockingReasons,
checks: [
{
id: "package-render-state",
label: "Package render state",
status: packageReady ? "pass" : "blocked",
value: packageRenderState?.statusLine ?? "missing",
},
{
id: "target-page",
label: "Control target",
status: targetReady ? "pass" : "blocked",
value: targetPage?.href ?? "missing",
},
{
id: "required-methods",
label: "Readonly methods",
status: methodsReady ? "pass" : "blocked",
value: methodsReady
? `${requiredMethods.loadSessionState}, ${requiredMethods.readStatus}`
: "missing",
},
{
id: "session-load-state",
label: "Session load state",
status: sessionReady ? "pass" : "blocked",
value: sessionLoadState?.phase ?? "missing",
},
{
id: "blocking-reasons",
label: "Blocking reasons",
status: blockingReasons.length === 0 ? "pass" : "blocked",
value: blockingReasons.length === 0 ? "none" : blockingReasons.join(", "),
},
],
};
}
export function createIniPanelShellSessionHandoffPackageMountDisplayViewModel(
mountState = createIniPanelShellSessionHandoffPackageMountState(),
) {
const checks = Array.isArray(mountState?.checks) ? mountState.checks : [];
const blockingChecks = checks.filter(({ status }) => status !== "pass");
const blockingReasons = Array.isArray(mountState?.blockingReasons) ? mountState.blockingReasons : [];
const problems = [
...blockingReasons,
...blockingChecks.map(({ id }) => id),
];
return {
phase: mountState?.phase === "ready" ? "ready" : "blocked",
title: "Shell handoff mount",
statusText: mountState?.ready ? "Ready" : "Blocked",
detailText: problems.length === 0 ? "No blocking reasons" : problems.join(", "),
rows: checks.map(({ id, label, status, value }) => ({
id,
label,
value,
status,
})),
};
}
export function createIniPanelShellSessionHandoffPackageMountRenderState(
displayViewModel = createIniPanelShellSessionHandoffPackageMountDisplayViewModel(),
) {
const rows = Array.isArray(displayViewModel?.rows)
? displayViewModel.rows.map(({ id, label, value, status }) => ({
id,
label,
value: value == null ? "" : String(value),
status: status ?? "blocked",
}))
: [];
const ready = displayViewModel?.phase === "ready" && displayViewModel?.statusText === "Ready";
const statusText = displayViewModel?.statusText ?? (ready ? "Ready" : "Blocked");
const detailText = displayViewModel?.detailText ?? "No blocking reasons";
return {
apiName: "ini-panel-shell-session-handoff-package-mount-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: displayViewModel?.title ?? "Shell handoff mount",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "mount",
},
};
}
export function createIniPanelShellSessionHandoffMountDomContract({
rowDatasetPrefix = "handoffMount",
selectors = {},
} = {}) {
const mountSelector = selectors.mount ?? "[data-handoff-mount]";
const statusSelector = selectors.status ?? "[data-handoff-mount-status]";
const rowsSelector = selectors.rows ?? "[data-handoff-mount-rows]";
return {
apiName: "ini-panel-shell-session-handoff-mount-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: ["rendered", "statusLine", "rowCount", "rowIds", "dataset"],
};
}
export function createIniPanelShellSessionHandoffMountDomReadiness({
rowDatasetPrefix = "handoffMount",
contract = createIniPanelShellSessionHandoffMountDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-session-handoff-mount-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellSessionHandoffMountState(
renderState = createIniPanelShellSessionHandoffPackageMountRenderState(),
{
rowDatasetPrefix = "handoffMount",
contract = createIniPanelShellSessionHandoffMountDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellSessionHandoffMountDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Shell handoff mount DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope ?? "mount";
statusNode.textContent = renderState?.statusLine ?? "Blocked: No mount render state";
rowsNode.replaceChildren();
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = row.status;
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = row.status;
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellSessionHandoff({
renderState = createIniPanelShellSessionHandoffPackageMountRenderState(),
rowDatasetPrefix = "handoffMount",
contract = createIniPanelShellSessionHandoffMountDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellSessionHandoffMountDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-session-handoff-mount-workflow",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellSessionHandoffMountState(renderState, {
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
return {
apiName: "ini-panel-shell-session-handoff-mount-workflow",
workflowVersion: 1,
phase: renderState?.ready ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-session-handoff-mount-workflow",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "mount workflow error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function mountIniPanelShellSessionHandoffFromControlPage({
controlPageApi = null,
sessionLoadState = null,
loadSessionStateMethod = "loadControlPageSessionState",
handoffPackage = createIniPanelShellSessionHandoffPackage(),
packageRenderState = createIniPanelShellSessionHandoffPackageRenderState(),
rowDatasetPrefix = "handoffMount",
contract = createIniPanelShellSessionHandoffMountDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
let observedSessionLoadState = sessionLoadState;
let sessionLoadError = null;
if (!observedSessionLoadState) {
const loadSessionState = controlPageApi?.[loadSessionStateMethod];
if (typeof loadSessionState === "function") {
try {
observedSessionLoadState = loadSessionState.call(controlPageApi);
} catch (error) {
sessionLoadError = error?.message ?? String(error);
observedSessionLoadState = createControlPageSessionLoadState({
phase: "error",
error: sessionLoadError,
});
}
} else {
observedSessionLoadState = createControlPageSessionLoadState({ phase: "waiting-api" });
}
}
const mountState = createIniPanelShellSessionHandoffPackageMountState({
handoffPackage,
packageRenderState,
sessionLoadState: observedSessionLoadState,
});
const mountDisplayViewModel = createIniPanelShellSessionHandoffPackageMountDisplayViewModel(mountState);
const mountRenderState = createIniPanelShellSessionHandoffPackageMountRenderState(mountDisplayViewModel);
const mountWorkflow = mountIniPanelShellSessionHandoff({
renderState: mountRenderState,
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
return {
apiName: "ini-panel-shell-session-handoff-control-page-mount-workflow",
workflowVersion: 1,
phase: mountWorkflow.phase,
ready: mountWorkflow.ready,
statusLine: mountWorkflow.statusLine,
loadSessionStateMethod,
sessionLoadState: observedSessionLoadState,
sessionLoadError,
mountState,
mountDisplayViewModel,
mountRenderState,
mountWorkflow,
};
}
export function readIniPanelShellSessionHandoffStatusFromControlPage({
controlPageApi = null,
readonlyStatus = null,
readStatusMethod = "readControlPageStatus",
handoffSummary = createIniPanelShellSessionHandoffSummary(),
expectedStatusFields = handoffSummary?.readonlyStatusFields ?? [],
} = {}) {
let observedStatus = readonlyStatus;
let readError = null;
if (!observedStatus) {
const readStatus = controlPageApi?.[readStatusMethod];
if (typeof readStatus === "function") {
try {
observedStatus = readStatus.call(controlPageApi);
} catch (error) {
readError = error?.message ?? String(error);
observedStatus = null;
}
} else {
readError = `Missing ${readStatusMethod}`;
observedStatus = null;
}
}
const statusObject = observedStatus && typeof observedStatus === "object" ? observedStatus : {};
const expectedFields = Array.isArray(expectedStatusFields) ? [...expectedStatusFields] : [];
const presentStatusFields = expectedFields.filter((fieldName) => Object.hasOwn(statusObject, fieldName));
const missingStatusFields = expectedFields.filter((fieldName) => !Object.hasOwn(statusObject, fieldName));
const ready = !readError && missingStatusFields.length === 0;
return {
apiName: "ini-panel-shell-session-handoff-readonly-status-result",
resultVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
statusLine: ready
? "Ready: readonly status fields available"
: `Blocked: ${readError ?? missingStatusFields.join(", ")}`,
readStatusMethod,
expectedStatusFields: expectedFields,
presentStatusFields,
missingStatusFields,
readonlyStatus: observedStatus,
readError,
};
}
export function createIniPanelShellSessionHandoffWorkflowSummary({
mountWorkflow = {
phase: "blocked",
ready: false,
statusLine: "Blocked: mount workflow unavailable",
},
controlPageMountWorkflow = {
phase: "blocked",
ready: false,
statusLine: "Blocked: control-page mount workflow unavailable",
},
readonlyStatusResult = {
phase: "blocked",
ready: false,
statusLine: "Blocked: readonly status unavailable",
missingStatusFields: [],
},
persistenceSummary = null,
apiSurfaceInventory = null,
} = {}) {
const sessionReadiness = readonlyStatusResult?.readonlyStatus?.sessionReadiness ?? null;
const sessionReadinessMissing = Array.isArray(sessionReadiness?.missing)
? [...sessionReadiness.missing]
: [];
const sessionReadinessValue = sessionReadiness
? `${sessionReadiness.ready ? "ready" : "blocked"}${
sessionReadinessMissing.length > 0 ? `: ${sessionReadinessMissing.join(", ")}` : ""
}`
: "missing";
const blockingReasons = [];
if (mountWorkflow?.ready !== true) {
blockingReasons.push(`mount:${mountWorkflow?.phase ?? "blocked"}`);
}
if (controlPageMountWorkflow?.ready !== true) {
blockingReasons.push(`control-page-mount:${controlPageMountWorkflow?.phase ?? "blocked"}`);
}
if (readonlyStatusResult?.ready !== true) {
const readonlyDetail = readonlyStatusResult?.readError
?? (
Array.isArray(readonlyStatusResult?.missingStatusFields)
&& readonlyStatusResult.missingStatusFields.length > 0
? readonlyStatusResult.missingStatusFields.join(", ")
: readonlyStatusResult?.phase ?? "blocked"
);
blockingReasons.push(`readonly-status:${readonlyDetail}`);
}
const ready = blockingReasons.length === 0;
const apiSurfaceRows = Array.isArray(apiSurfaceInventory?.rows)
? apiSurfaceInventory.rows
: [];
const apiSurfaceValue = apiSurfaceInventory
? (
apiSurfaceInventory.ready
? `ready: ${apiSurfaceRows.length} rows`
: `blocked: ${apiSurfaceInventory.phase ?? "unknown"}`
)
: "missing";
const apiSurfaceCounts = apiSurfaceInventory?.counts && typeof apiSurfaceInventory.counts === "object"
? { ...apiSurfaceInventory.counts }
: null;
const persistenceRows = Array.isArray(persistenceSummary?.rows)
? persistenceSummary.rows
: [];
const persistenceMissing = Array.isArray(persistenceSummary?.missing)
? persistenceSummary.missing
: [];
const persistenceValue = persistenceSummary
? (
persistenceSummary.ready
? `ready: ${persistenceRows.length} rows`
: `${persistenceSummary.phase ?? "waiting"}: ${persistenceMissing.length} missing`
)
: "missing";
return {
apiName: "ini-panel-shell-session-handoff-workflow-summary",
summaryVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
statusLine: ready
? "Ready: shell handoff end-to-end workflow available"
: `Blocked: ${blockingReasons.join("; ")}`,
mountWorkflow: {
phase: mountWorkflow?.phase ?? "blocked",
ready: mountWorkflow?.ready === true,
statusLine: mountWorkflow?.statusLine ?? null,
},
controlPageMountWorkflow: {
phase: controlPageMountWorkflow?.phase ?? "blocked",
ready: controlPageMountWorkflow?.ready === true,
statusLine: controlPageMountWorkflow?.statusLine ?? null,
},
readonlyStatusResult: {
phase: readonlyStatusResult?.phase ?? "blocked",
ready: readonlyStatusResult?.ready === true,
statusLine: readonlyStatusResult?.statusLine ?? null,
missingStatusFields: Array.isArray(readonlyStatusResult?.missingStatusFields)
? [...readonlyStatusResult.missingStatusFields]
: [],
},
sessionReadiness: sessionReadiness
? {
phase: sessionReadiness.phase ?? (sessionReadiness.ready ? "ready" : "blocked"),
ready: sessionReadiness.ready === true,
missing: sessionReadinessMissing,
}
: null,
apiSurfaceInventory: apiSurfaceInventory
? {
phase: apiSurfaceInventory.phase ?? (apiSurfaceInventory.ready ? "ready" : "blocked"),
ready: apiSurfaceInventory.ready === true,
counts: apiSurfaceCounts,
apiNames: apiSurfaceInventory.apiNames ? { ...apiSurfaceInventory.apiNames } : null,
}
: null,
persistenceSummary: persistenceSummary
? {
phase: persistenceSummary.phase ?? (persistenceSummary.ready ? "ready" : "waiting"),
ready: persistenceSummary.ready === true,
counts: persistenceSummary.counts ? { ...persistenceSummary.counts } : null,
missing: persistenceMissing,
}
: null,
blockingReasons,
rows: [
{
id: "mount-workflow",
label: "Mount workflow",
value: mountWorkflow?.statusLine ?? "missing",
},
{
id: "control-page-mount-workflow",
label: "Control-page mount workflow",
value: controlPageMountWorkflow?.statusLine ?? "missing",
},
{
id: "readonly-status-workflow",
label: "Readonly status workflow",
value: readonlyStatusResult?.statusLine ?? "missing",
},
{
id: "session-readiness",
label: "Session readiness",
value: sessionReadinessValue,
},
{
id: "readonly-status-missing-fields",
label: "Readonly missing fields",
value: Array.isArray(readonlyStatusResult?.missingStatusFields)
&& readonlyStatusResult.missingStatusFields.length > 0
? readonlyStatusResult.missingStatusFields.join(", ")
: "none",
},
{
id: "persistence-summary",
label: "Persistence summary",
value: persistenceValue,
},
{
id: "api-surface-inventory",
label: "API surface inventory",
value: apiSurfaceValue,
},
{
id: "blocking-reasons",
label: "Blocking reasons",
value: blockingReasons.length > 0 ? blockingReasons.join("; ") : "none",
},
],
};
}
export function createIniPanelShellSessionHandoffWorkflowDisplayViewModel(
workflowSummary = createIniPanelShellSessionHandoffWorkflowSummary(),
) {
const blockingReasons = Array.isArray(workflowSummary?.blockingReasons)
? workflowSummary.blockingReasons
: [];
return {
phase: workflowSummary?.phase === "ready" ? "ready" : "blocked",
title: "Shell handoff workflow",
statusText: workflowSummary?.ready ? "Ready" : "Blocked",
detailText: blockingReasons.length > 0 ? blockingReasons.join(", ") : "No blocking reasons",
rows: Array.isArray(workflowSummary?.rows)
? workflowSummary.rows.map(({ id, label, value }) => ({
id,
label,
value,
}))
: [],
};
}
export function createIniPanelShellSessionReadinessWorkflowReport({
workflowSummary = null,
readonlyStatusResult = null,
} = {}) {
const sessionReadiness = workflowSummary?.sessionReadiness
?? readonlyStatusResult?.readonlyStatus?.sessionReadiness
?? null;
const missing = Array.isArray(sessionReadiness?.missing)
? [...sessionReadiness.missing]
: [];
const ready = sessionReadiness?.ready === true;
const phase = sessionReadiness ? (ready ? "ready" : "blocked") : "blocked";
const statusLine = sessionReadiness
? (
ready
? "Ready: session readiness available"
: `Blocked: ${missing.length > 0 ? missing.join(", ") : "session readiness blocked"}`
)
: "Blocked: session readiness unavailable";
return {
apiName: "ini-panel-shell-session-readiness-workflow-report",
reportVersion: 1,
phase,
ready,
statusLine,
sessionReadiness: sessionReadiness
? {
phase: sessionReadiness.phase ?? phase,
ready,
missing,
}
: null,
missing,
rows: [
{
id: "session-readiness",
label: "Session readiness",
value: sessionReadiness ? (ready ? "ready" : "blocked") : "missing",
},
{
id: "session-readiness-phase",
label: "Session readiness phase",
value: sessionReadiness?.phase ?? "missing",
},
{
id: "session-readiness-missing",
label: "Session readiness missing",
value: missing.length > 0 ? missing.join(", ") : "none",
},
],
};
}
export function createIniPanelShellApiSurfaceInventory({
launchApiManifest = createIniPanelLaunchApiManifest(),
controlPageApiManifest = createControlPageBrowserApiManifest(),
workflowOverviewContract = createIniPanelShellWorkflowOverviewContract(),
sessionReadinessWorkflowReport = createIniPanelShellSessionReadinessWorkflowReport(),
persistenceSummary = createMachineSessionPersistenceSummary(),
} = {}) {
const launchMethods = Array.isArray(launchApiManifest?.methods) ? launchApiManifest.methods : [];
const controlPageMethods = Array.isArray(controlPageApiManifest?.methods) ? controlPageApiManifest.methods : [];
const workflowOverviewMethods = Array.isArray(workflowOverviewContract?.methodNames)
? workflowOverviewContract.methodNames
: [];
const persistenceCapabilities = Array.isArray(launchApiManifest?.persistenceCapabilities)
? launchApiManifest.persistenceCapabilities
: [];
const sessionReadinessRows = Array.isArray(sessionReadinessWorkflowReport?.rows)
? sessionReadinessWorkflowReport.rows
: [];
const persistenceSummaryRows = Array.isArray(persistenceSummary?.rows)
? persistenceSummary.rows
: [];
const ready = Boolean(
launchApiManifest?.apiName
&& controlPageApiManifest?.apiName
&& workflowOverviewContract?.apiName
&& sessionReadinessWorkflowReport?.apiName
&& persistenceSummary?.apiName,
);
return {
apiName: "ini-panel-shell-api-surface-inventory",
inventoryVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
counts: {
launchMethods: launchMethods.length,
controlPageMethods: controlPageMethods.length,
workflowOverviewMethods: workflowOverviewMethods.length,
persistenceCapabilities: persistenceCapabilities.length,
sessionReadinessRows: sessionReadinessRows.length,
persistenceSummaryRows: persistenceSummaryRows.length,
},
apiNames: {
launch: launchApiManifest?.apiName ?? null,
controlPage: controlPageApiManifest?.apiName ?? null,
workflowOverview: workflowOverviewContract?.apiName ?? null,
sessionReadinessReport: sessionReadinessWorkflowReport?.apiName ?? null,
persistenceSummary: persistenceSummary?.apiName ?? null,
},
entries: [
{
id: "launch-api",
label: "Launch API",
apiName: launchApiManifest?.apiName ?? null,
count: launchMethods.length,
},
{
id: "control-page-api",
label: "Control-page API",
apiName: controlPageApiManifest?.apiName ?? null,
count: controlPageMethods.length,
},
{
id: "workflow-overview-api",
label: "Workflow overview API",
apiName: workflowOverviewContract?.apiName ?? null,
count: workflowOverviewMethods.length,
},
{
id: "session-readiness-report",
label: "Session readiness report",
apiName: sessionReadinessWorkflowReport?.apiName ?? null,
count: sessionReadinessRows.length,
},
{
id: "persistence-summary",
label: "Persistence summary",
apiName: persistenceSummary?.apiName ?? null,
count: persistenceSummaryRows.length,
},
{
id: "persistence-capabilities",
label: "Persistence capabilities",
apiName: launchApiManifest?.apiName ?? null,
count: persistenceCapabilities.length,
},
],
rows: [
{
id: "launch-methods",
label: "Launch methods",
value: String(launchMethods.length),
},
{
id: "control-page-methods",
label: "Control-page methods",
value: String(controlPageMethods.length),
},
{
id: "workflow-overview-methods",
label: "Workflow overview methods",
value: String(workflowOverviewMethods.length),
},
{
id: "session-readiness-report",
label: "Session readiness report",
value: sessionReadinessWorkflowReport?.apiName ?? "missing",
},
{
id: "persistence-summary",
label: "Persistence summary",
value: persistenceSummary?.apiName ?? "missing",
},
{
id: "persistence-capabilities",
label: "Persistence capabilities",
value: String(persistenceCapabilities.length),
},
],
};
}
export function createIniPanelShellSessionHandoffWorkflowRenderState(
displayViewModel = createIniPanelShellSessionHandoffWorkflowDisplayViewModel(),
) {
const rows = Array.isArray(displayViewModel?.rows)
? displayViewModel.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const ready = displayViewModel?.phase === "ready" && displayViewModel?.statusText === "Ready";
const statusText = displayViewModel?.statusText ?? (ready ? "Ready" : "Blocked");
const detailText = displayViewModel?.detailText ?? "No blocking reasons";
return {
apiName: "ini-panel-shell-session-handoff-workflow-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: displayViewModel?.title ?? "Shell handoff workflow",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow",
},
};
}
export function createIniPanelShellSessionHandoffWorkflowDomContract({
rowDatasetPrefix = "handoffWorkflow",
selectors = {},
} = {}) {
const mountSelector = selectors.mount ?? "[data-handoff-workflow]";
const statusSelector = selectors.status ?? "[data-handoff-workflow-status]";
const rowsSelector = selectors.rows ?? "[data-handoff-workflow-rows]";
return {
apiName: "ini-panel-shell-session-handoff-workflow-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: ["rendered", "statusLine", "rowCount", "rowIds", "dataset"],
};
}
export function createIniPanelShellWorkflowOverviewContract() {
return {
pageHref: "./workflow-overview.html",
entryId: "workflow-overview",
apiName: "linuxCncIniPanelWorkflowOverviewApi",
methodNames: [
"getWorkflowOverviewRenderState",
"getWorkflowOverviewDisplayViewModel",
"getWorkflowOverviewSummary",
"getWorkflowOverviewSessionReadinessReport",
"getWorkflowOverviewApiSurfaceInventory",
"getWorkflowOverviewPersistenceSummary",
"validateWorkflowOverviewReleaseReadinessArtifactJson",
"runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState",
"loadWorkflowOverviewReleaseReadinessArtifactUrl",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState",
"getWorkflowOverviewPromotionFamilyRowsRenderState",
"getWorkflowOverviewPromotionFamilySourceFilterViewModel",
"getWorkflowOverviewPromotionFamilySourceFilterDomContract",
"getWorkflowOverviewPromotionFamilySourceFilterDomReadiness",
"getWorkflowOverviewPromotionFamilySourceFilterSelectionActionPlan",
"handleWorkflowOverviewPromotionFamilySourceFilterSelectionChange",
"bindWorkflowOverviewPromotionFamilySourceFilterSelectionControls",
"renderWorkflowOverviewPromotionFamilySourceFilterState",
"mountWorkflowOverviewPromotionFamilySourceFilterState",
"getWorkflowOverviewPromotionFamilyRowsDomContract",
"getWorkflowOverviewPromotionFamilyRowsDomReadiness",
"renderWorkflowOverviewPromotionFamilyRowsState",
"mountWorkflowOverviewPromotionFamilyRowsState",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract",
"getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState",
"getWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlan",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract",
"getWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract",
"getWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState",
"getWorkflowOverviewReleaseReadinessArtifactDisplayViewModel",
"getWorkflowOverviewReleaseReadinessArtifactRenderState",
"getWorkflowOverviewReleaseReadinessArtifactDomContract",
"getWorkflowOverviewReleaseReadinessArtifactDomReadiness",
"renderWorkflowOverviewReleaseReadinessArtifactState",
"mountWorkflowOverviewReleaseReadinessArtifactState",
"getWorkflowOverviewDomContract",
"getWorkflowOverviewDomReadiness",
"renderWorkflowOverview",
"mountWorkflowOverview",
"createWorkflowOverviewRenderState",
],
};
}
export function validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson(artifactJson) {
try {
const artifact = parseProjectReleaseReadinessArtifactJson(artifactJson);
const validation = createProjectReleaseReadinessArtifactValidation(artifact);
const actionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(validation);
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-validation",
validationVersion: 1,
phase: validation.ready ? "ready" : "blocked",
ready: validation.ready,
missing: [...validation.missing],
error: null,
artifactApiName: validation.artifactApiName,
artifactVersion: validation.artifactVersion,
gateCount: validation.gateCount,
validation,
gateExecutionSummaryViewModel: artifact.gateExecutionSummaryViewModel
?? createProjectReleaseGateExecutionSummaryViewModel(artifact.gateExecutionManifest),
actionPlan,
rows: [...validation.rows],
};
} catch (error) {
const actionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(
createProjectReleaseReadinessArtifactValidation({}),
);
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-validation",
validationVersion: 1,
phase: "blocked",
ready: false,
missing: ["artifact-json"],
error: error?.message ?? "Unable to parse release readiness artifact JSON",
artifactApiName: null,
artifactVersion: null,
gateCount: 0,
validation: null,
gateExecutionSummaryViewModel: null,
actionPlan,
rows: [
{
id: "artifact-json",
label: "Readiness artifact JSON",
value: "blocked",
},
],
};
}
}
export function runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow({
artifactJson = "",
} = {}) {
const jsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson });
const validation = validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson(artifactJson);
const validationSummaryViewModel =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(validation);
const gateExecutionSummaryViewModel =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel(validation);
const actionPlan =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan(validation);
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-json-workflow",
workflowVersion: 1,
phase: jsonWorkflow.ready ? "ready" : "blocked",
ready: jsonWorkflow.ready,
parsed: jsonWorkflow.parsed,
parseError: jsonWorkflow.parseError,
artifactApiName: jsonWorkflow.artifactApiName,
missing: [...jsonWorkflow.missing],
jsonWorkflow,
validation,
validationSummaryViewModel,
gateExecutionSummaryViewModel,
actionPlan,
rows: [
{
id: "parse",
label: "Artifact JSON parse",
value: jsonWorkflow.parsed ? "ready" : "blocked",
},
{
id: "validation-summary",
label: "Validation summary",
value: validationSummaryViewModel.statusLine,
},
{
id: "gate-execution-summary",
label: "Gate execution summary",
value: gateExecutionSummaryViewModel.statusLine,
},
{
id: "next-command",
label: "Next command",
value: actionPlan.nextCommand ?? "none",
},
],
statusLine: jsonWorkflow.ready
? "Ready: Artifact JSON workflow complete"
: `Blocked: ${jsonWorkflow.missing.join(", ")}`,
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel(
workflow = {},
) {
const missing = Array.isArray(workflow?.missing) ? workflow.missing : [];
const ready = workflow?.ready === true;
const statusText = ready ? "Ready" : "Blocked";
const detailText = ready
? "Artifact JSON workflow complete"
: (missing.length > 0 ? missing.join(", ") : workflow?.parseError ?? "artifact JSON workflow blocked");
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-json-workflow-summary-view-model",
viewModelVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: "Release artifact JSON workflow",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows: [
{
id: "parse",
label: "Artifact JSON parse",
value: workflow?.parsed === true ? "ready" : "blocked",
},
{
id: "validation-summary",
label: "Validation summary",
value: workflow?.validationSummaryViewModel?.statusLine ?? "missing",
},
{
id: "gate-execution-summary",
label: "Gate execution summary",
value: workflow?.gateExecutionSummaryViewModel?.statusLine ?? "missing",
},
{
id: "action-plan",
label: "Action plan",
value: workflow?.actionPlan?.ready === true
? "ready"
: (workflow?.actionPlan?.nextActionId ?? "missing"),
},
{
id: "missing",
label: "Missing workflow evidence",
value: missing.length > 0 ? missing.join(", ") : "none",
},
],
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan(
workflow = {},
) {
return workflow?.actionPlan
?? createProjectReleaseReadinessArtifactValidationActionPlan(workflow?.validation?.validation);
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState(
summaryViewModel = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel(),
) {
const rows = Array.isArray(summaryViewModel?.rows)
? summaryViewModel.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const ready = summaryViewModel?.phase === "ready" && summaryViewModel?.statusText === "Ready";
const statusText = summaryViewModel?.statusText ?? (ready ? "Ready" : "Blocked");
const detailText = summaryViewModel?.detailText ?? "artifact JSON workflow blocked";
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-json-workflow-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: summaryViewModel?.title ?? "Release artifact JSON workflow",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-release-readiness-artifact-json-workflow",
},
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactJsonWorkflow",
selectors = {},
} = {}) {
const mountSelector = selectors.mount ?? "[data-workflow-overview-release-readiness-artifact-json-workflow]";
const statusSelector = selectors.status
?? "[data-workflow-overview-release-readiness-artifact-json-workflow-status]";
const rowsSelector = selectors.rows
?? "[data-workflow-overview-release-readiness-artifact-json-workflow-rows]";
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-json-workflow-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: ["rendered", "statusLine", "rowCount", "rowIds", "dataset"],
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactJsonWorkflow",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-json-workflow-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState(
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState(),
{
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactJsonWorkflow",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview release readiness artifact JSON workflow DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope
?? "workflow-overview-release-readiness-artifact-json-workflow";
statusNode.textContent = renderState?.statusLine
?? "Blocked: No release readiness artifact JSON workflow render state";
rowsNode.replaceChildren();
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState({
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState(),
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactJsonWorkflow",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-json-workflow-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState(
renderState,
{
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
},
);
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-json-workflow-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-json-workflow-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "release readiness artifact JSON workflow DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export async function loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl({
artifactUrl = "",
diagnosticsUrl = "",
fetchRef = globalThis.fetch,
mount = false,
mountOptions = {},
} = {}) {
const missing = [
...(artifactUrl ? [] : ["artifact-url"]),
...(typeof fetchRef === "function" ? [] : ["fetch"]),
];
if (missing.length > 0) {
const actionPlan = createProjectReleaseReadinessArtifactUrlWorkflowActionPlan({
ready: false,
missing,
});
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow",
workflowVersion: 1,
phase: "blocked",
ready: false,
artifactUrl,
diagnosticsUrl,
httpStatus: null,
diagnosticsHttpStatus: null,
missing,
error: null,
diagnosticsError: null,
validation: null,
diagnosticsValidation: null,
validationSummaryViewModel: null,
gateExecutionSummaryViewModel: null,
actionPlan,
displayViewModel: null,
renderState: null,
mountResult: null,
statusLine: `Blocked: ${missing.join(", ")}`,
};
}
try {
const urlWorkflow = await loadProjectReleaseReadinessArtifactUrlWorkflow({
artifactUrl,
diagnosticsUrl,
fetchRef,
});
const httpStatus = urlWorkflow.httpStatus;
if (urlWorkflow.fetched !== true || urlWorkflow.jsonWorkflow?.parsed !== true) {
const actionPlan = createProjectReleaseReadinessArtifactUrlWorkflowActionPlan(urlWorkflow);
const error = urlWorkflow.fetchError
?? urlWorkflow.jsonWorkflow?.parseError
?? (httpStatus ? `HTTP ${httpStatus}` : "artifact URL workflow blocked");
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow",
workflowVersion: 1,
phase: "blocked",
ready: false,
artifactUrl,
diagnosticsUrl,
httpStatus,
diagnosticsHttpStatus: urlWorkflow.diagnosticsHttpStatus ?? null,
missing: urlWorkflow.missing ?? ["artifact-url"],
error,
diagnosticsError: urlWorkflow.diagnosticsFetchError ?? null,
validation: null,
diagnosticsValidation: urlWorkflow.diagnosticsValidation ?? null,
diagnosticsArtifact: urlWorkflow.diagnosticsArtifact ?? null,
validationSummaryViewModel: null,
gateExecutionSummaryViewModel: null,
actionPlan,
displayViewModel: null,
renderState: null,
mountResult: null,
urlWorkflow,
statusLine: httpStatus && urlWorkflow.fetchError ? `Blocked: HTTP ${httpStatus}` : `Blocked: ${error}`,
};
}
const validation = validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson(
JSON.stringify(urlWorkflow.jsonWorkflow.artifact),
);
const gateExecutionSummaryViewModel =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel(
validation,
);
const validationSummaryViewModel =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(
validation,
);
const displayViewModel = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel(
validation,
);
const renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState(
displayViewModel,
);
const mountResult = mount
? mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactState({
renderState,
...mountOptions,
})
: null;
const mountMissing = mount && mountResult?.ready !== true
? (mountResult?.domReadiness?.missing ?? ["release-readiness-artifact-dom"])
: [];
const workflowMissing = [
...validation.missing,
...(urlWorkflow.diagnosticsUrl && urlWorkflow.diagnosticsValidation?.ready !== true
? (urlWorkflow.diagnosticsValidation?.missing ?? ["browser-diagnostics"])
.map((item) => `diagnostics.${item}`)
: []),
...mountMissing,
];
const ready = validation.ready === true &&
(!urlWorkflow.diagnosticsUrl || urlWorkflow.diagnosticsValidation?.ready === true) &&
(!mount || mountResult?.ready === true);
const validationActionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(
validation.validation,
);
const actionPlan = createProjectReleaseReadinessArtifactUrlWorkflowActionPlan({
ready,
missing: workflowMissing,
actionPlan: validationActionPlan,
});
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow",
workflowVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
artifactUrl,
diagnosticsUrl,
httpStatus,
diagnosticsHttpStatus: urlWorkflow.diagnosticsHttpStatus ?? null,
missing: workflowMissing,
error: null,
diagnosticsError: urlWorkflow.diagnosticsFetchError ?? null,
validation,
diagnosticsValidation: urlWorkflow.diagnosticsValidation ?? null,
diagnosticsArtifact: urlWorkflow.diagnosticsArtifact ?? null,
validationSummaryViewModel,
gateExecutionSummaryViewModel,
actionPlan,
displayViewModel,
renderState,
mountResult,
urlWorkflow,
statusLine: ready ? renderState.statusLine : `Blocked: ${workflowMissing.join(", ")}`,
};
} catch (error) {
const actionPlan = createProjectReleaseReadinessArtifactUrlWorkflowActionPlan({
ready: false,
missing: ["artifact-fetch"],
});
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow",
workflowVersion: 1,
phase: "blocked",
ready: false,
artifactUrl,
diagnosticsUrl,
httpStatus: null,
diagnosticsHttpStatus: null,
missing: ["artifact-url"],
error: error?.message ?? String(error),
diagnosticsError: null,
validation: null,
diagnosticsValidation: null,
validationSummaryViewModel: null,
gateExecutionSummaryViewModel: null,
actionPlan,
displayViewModel: null,
renderState: null,
mountResult: null,
statusLine: `Blocked: ${error?.message ?? "release readiness artifact URL load error"}`,
};
}
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(
workflow = {},
) {
const missing = Array.isArray(workflow?.missing) ? workflow.missing : [];
const promotionCandidateSummary = (
workflow?.diagnosticsArtifact?.virtualHalPromotionCandidateSummary
?? workflow?.urlWorkflow?.diagnosticsArtifact?.virtualHalPromotionCandidateSummary
?? {}
);
const promotionCandidateReportRows = (
workflow?.diagnosticsArtifact?.virtualHalSimConfigPromotionCandidates?.rows
?? workflow?.urlWorkflow?.diagnosticsArtifact?.virtualHalSimConfigPromotionCandidates?.rows
?? []
);
const evidenceReadyCandidateRows = Array.isArray(promotionCandidateReportRows)
? 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 = Array.isArray(workflow?.validation?.rows)
? workflow.validation.rows
: (Array.isArray(workflow?.validation?.validation?.rows) ? workflow.validation.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 = (
workflow?.validation?.promotionCandidateArtifactSummary
?? workflow?.validation?.validation?.promotionCandidateArtifactSummary
?? {}
);
const promotionArtifactRows = promotionCandidateArtifactSummary.artifactRows ?? {};
const hardBlockRuntimeFamilyRows = Array.isArray(promotionCandidateArtifactSummary.hardBlockRuntimeFamilyRows)
? promotionCandidateArtifactSummary.hardBlockRuntimeFamilyRows
: [];
const hardBlockRuntimeFamilySummaryRows = Array.isArray(promotionCandidateArtifactSummary.hardBlockRuntimeFamilySummaryRows)
? promotionCandidateArtifactSummary.hardBlockRuntimeFamilySummaryRows
: [];
const hardBlockRuntimeFamilyDetailRows = Array.isArray(promotionCandidateArtifactSummary.hardBlockRuntimeFamilyDetailRows)
? promotionCandidateArtifactSummary.hardBlockRuntimeFamilyDetailRows
: [];
const hardBlockRuntimeDetailPreviewRows = hardBlockRuntimeFamilyDetailRows.slice(0, 5);
const hardBlockRuntimePreviewRows = hardBlockRuntimeFamilyRows.slice(0, 3);
const evidenceExpansion = promotionCandidateArtifactSummary.evidenceExpansion ?? {};
const evidenceExpansionRows = (
workflow?.diagnosticsArtifact?.virtualHalSimConfigEvidenceExpansion?.rows
?? workflow?.urlWorkflow?.diagnosticsArtifact?.virtualHalSimConfigEvidenceExpansion?.rows
?? []
);
const preferredEvidenceExpansion = Array.isArray(evidenceExpansionRows)
? (evidenceExpansionRows[0] ?? {})
: {};
const evidenceExpansionPreviewRows = Array.isArray(evidenceExpansionRows)
? evidenceExpansionRows.slice(0, 3)
: [];
const evidenceExpansionFullRows = Array.isArray(evidenceExpansionRows)
? evidenceExpansionRows
: [];
const ready = workflow?.ready === true;
const promotionFamilyRows = (
workflow?.validation?.virtualHalPromotionFamilyRows
?? workflow?.validation?.validation?.virtualHalPromotionFamilyRows
?? []
).map((row) => ({
id: `virtual-hal-promotion-family-${row.id}`,
label: `Promotion family ${row.label}`,
value: row.value,
sourceFiles: Array.isArray(row.sourceFiles) ? row.sourceFiles : [],
}));
const statusText = ready ? "Ready" : "Blocked";
const detailText = ready
? "Artifact URL workflow complete"
: (missing.length > 0 ? missing.join(", ") : workflow?.error ?? "artifact URL workflow blocked");
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-summary-view-model",
viewModelVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: "Release artifact URL workflow",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows: [
{
id: "artifact-url",
label: "Artifact URL",
value: workflow?.artifactUrl || "missing",
},
{
id: "http-status",
label: "HTTP status",
value: workflow?.httpStatus == null ? "none" : String(workflow.httpStatus),
},
{
id: "diagnostics-url",
label: "Diagnostics URL",
value: workflow?.diagnosticsUrl || "not requested",
},
{
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: "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: "virtual-hal-promotion-candidate-baseline",
label: "Candidate inventory baseline",
value: promotionCandidateSummary.inventoryBaseline ?? "not provided",
},
{
id: "evidence-expansion-next-evidence",
label: "Evidence expansion next evidence",
value: evidenceExpansion.nextEvidence ?? "not provided",
},
{
id: "promotion-candidate-artifact-rows",
label: "Promotion candidate artifact rows",
value: promotionArtifactRows.promotionCandidates == null
? "not provided"
: `${promotionArtifactRows.promotionCandidates}`,
},
{
id: "evidence-expansion-artifact-rows",
label: "Evidence expansion artifact rows",
value: promotionArtifactRows.evidenceExpansion == null
? "not provided"
: `${promotionArtifactRows.evidenceExpansion}`,
},
{
id: "evidence-expansion-baseline-changing",
label: "Evidence expansion baseline changing",
value: evidenceExpansion.baselineChanging === true
? "yes"
: (evidenceExpansion.baselineChanging === false ? "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-full-candidate-list",
label: "Evidence expansion full candidate list",
value: evidenceExpansionFullRows.length > 0
? evidenceExpansionFullRows.map((row) => row.id).join(", ")
: "not provided",
},
{
id: "evidence-expansion-full-gcode-list",
label: "Evidence expansion full G-code list",
value: evidenceExpansionFullRows.length > 0
? evidenceExpansionFullRows.map((row) => row.gcodePath).join(", ")
: "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: "hard-block-runtime-locked-rows",
label: "Hard-block locked inventory rows",
value: `${hardBlockRuntimeFamilyRows.length}`,
},
{
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: promotionCandidateArtifactSummary.hardBlockRuntimePromotionAllowedCount == null
? "not provided"
: `${promotionCandidateArtifactSummary.hardBlockRuntimePromotionAllowedCount}`,
},
{
id: "hard-block-runtime-family-count",
label: "Hard-block runtime families",
value: `${hardBlockRuntimeFamilySummaryRows.length}`,
},
{
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: `${hardBlockRuntimeFamilyDetailRows.length}`,
},
...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: Array.isArray(row.lockedPaths) && row.lockedPaths.length > 0
? row.lockedPaths.join(", ")
: "not provided",
lockedPaths: Array.isArray(row.lockedPaths) ? row.lockedPaths : [],
})),
{
id: "virtual-hal-promotion-families",
label: "Virtual HAL promotion families",
value: workflow?.validation?.virtualHalPromotionFamilySummary
?? workflow?.validation?.validation?.virtualHalPromotionFamilySummary
?? "not provided",
},
...promotionFamilyRows,
{
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: "diagnostics-status",
label: "Diagnostics HTTP status",
value: workflow?.diagnosticsHttpStatus == null ? "none" : String(workflow.diagnosticsHttpStatus),
},
{
id: "validation-summary",
label: "Validation summary",
value: workflow?.validationSummaryViewModel?.statusLine ?? "missing",
},
{
id: "gate-execution-summary",
label: "Gate execution summary",
value: workflow?.gateExecutionSummaryViewModel?.statusLine ?? "missing",
},
{
id: "action-plan",
label: "Action plan",
value: workflow?.actionPlan?.ready === true
? "ready"
: (workflow?.actionPlan?.nextActionId ?? "missing"),
},
{
id: "render-state",
label: "Render state",
value: workflow?.renderState?.statusLine ?? "missing",
},
{
id: "mount-result",
label: "Mount result",
value: workflow?.mountResult
? (workflow.mountResult.ready ? "ready" : workflow.mountResult.statusLine)
: "not requested",
},
{
id: "missing",
label: "Missing workflow evidence",
value: missing.length > 0 ? missing.join(", ") : "none",
},
],
promotionFamilyRows,
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan(
workflow = {},
) {
return workflow?.actionPlan
?? createProjectReleaseReadinessArtifactUrlWorkflowActionPlan(workflow);
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanRenderState(
actionPlan = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan(),
) {
const actionRows = Array.isArray(actionPlan?.rows)
? actionPlan.rows.map(({ id, label, value }) => ({
id: `action-${id}`,
label,
value: value == null ? "" : String(value),
}))
: [];
const ready = actionPlan?.ready === true;
const statusText = ready ? "Ready" : "Blocked";
const detailText = ready
? "Artifact URL workflow action plan complete"
: (actionPlan?.nextCommand ?? actionPlan?.nextActionId ?? "artifact URL workflow action required");
const rows = [
{
id: "action-count",
label: "Action count",
value: String(actionPlan?.actionCount ?? actionRows.length),
},
{
id: "next-action",
label: "Next action",
value: actionPlan?.nextActionId ?? "none",
},
{
id: "next-command",
label: "Next command",
value: actionPlan?.nextCommand ?? "none",
},
...actionRows,
];
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-action-plan-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: "Release artifact URL workflow action plan",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
actionRows,
nextActionId: actionPlan?.nextActionId ?? null,
nextCommand: actionPlan?.nextCommand ?? null,
shellScript: actionPlan?.shellScript ?? "",
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-release-readiness-artifact-url-workflow-action-plan",
},
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanDomContract({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
selectors = {},
} = {}) {
const mountSelector = selectors.mount
?? "[data-workflow-overview-release-readiness-artifact-url-workflow-action-plan]";
const statusSelector = selectors.status
?? "[data-workflow-overview-release-readiness-artifact-url-workflow-action-plan-status]";
const rowsSelector = selectors.rows
?? "[data-workflow-overview-release-readiness-artifact-url-workflow-action-plan-rows]";
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-action-plan-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: ["rendered", "statusLine", "rowCount", "rowIds", "dataset"],
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanDomReadiness({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-action-plan-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanState(
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanRenderState(),
{
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview release readiness artifact URL workflow action plan DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope
?? "workflow-overview-release-readiness-artifact-url-workflow-action-plan";
statusNode.textContent = renderState?.statusLine
?? "Blocked: No release artifact URL workflow action-plan render state";
rowsNode.replaceChildren();
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanState({
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanRenderState(),
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-action-plan-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlanState(
renderState,
{
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
},
);
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-action-plan-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-action-plan-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "release artifact URL workflow action-plan DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState(
summaryViewModel = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(),
) {
const rows = Array.isArray(summaryViewModel?.rows)
? summaryViewModel.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const ready = summaryViewModel?.phase === "ready" && summaryViewModel?.statusText === "Ready";
const statusText = summaryViewModel?.statusText ?? (ready ? "Ready" : "Blocked");
const detailText = summaryViewModel?.detailText ?? "artifact URL workflow blocked";
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: summaryViewModel?.title ?? "Release artifact URL workflow",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-release-readiness-artifact-url-workflow",
},
};
}
function classifyPromotionFamilySource(sourceFile = "") {
const normalized = String(sourceFile);
if (normalized.includes("/remap_subs/") || normalized.includes("/nc_subroutines/")) {
return "remap-subroutine";
}
if (normalized.endsWith(".ini")) {
return "ini";
}
if (normalized.endsWith(".ngc")) {
return "gcode";
}
return "source";
}
function countPromotionFamilySourceKinds(sourceFiles = []) {
return sourceFiles.reduce((counts, sourceFile) => {
const sourceKind = classifyPromotionFamilySource(sourceFile);
return {
...counts,
[sourceKind]: (counts[sourceKind] ?? 0) + 1,
};
}, {});
}
function formatPromotionFamilySourceKindCounts(counts = {}) {
return ["ini", "gcode", "remap-subroutine", "source"]
.filter((kind) => Number(counts[kind] ?? 0) > 0)
.map((kind) => `${kind}=${counts[kind]}`)
.join(" ");
}
function normalizePromotionFamilySourceKindFilter(sourceKind = "all") {
const normalized = String(sourceKind || "all");
return ["all", "ini", "gcode", "remap-subroutine", "source"].includes(normalized)
? normalized
: "all";
}
function normalizePromotionFamilyFilter(familyId = "all", rows = []) {
const normalized = String(familyId || "all");
return normalized === "all" || rows.some((row) => row.id === normalized)
? normalized
: "all";
}
export function createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState(
summaryViewModel = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(),
) {
const summaryRows = Array.isArray(summaryViewModel?.promotionFamilyRows)
? summaryViewModel.promotionFamilyRows
: (Array.isArray(summaryViewModel?.rows) ? summaryViewModel.rows : []);
const rows = Array.isArray(summaryRows)
? summaryRows
.filter(({ id }) => String(id).startsWith("virtual-hal-promotion-family-"))
.map(({ id, label, value, sourceFiles }) => {
const familySourceFiles = Array.isArray(sourceFiles) ? sourceFiles : [];
const sourceKindCounts = countPromotionFamilySourceKinds(familySourceFiles);
const sourceKindSummary = formatPromotionFamilySourceKindCounts(sourceKindCounts);
return {
id,
label,
value: value == null ? "" : String(value),
sourceFiles: familySourceFiles,
sourceKindCounts,
sourceKindSummary,
};
})
: [];
const sourceRows = rows.flatMap((row) =>
row.sourceFiles.map((sourceFile, index) => ({
id: `${row.id}-source-${index + 1}`,
familyId: row.id,
label: `Source ${index + 1}`,
value: sourceFile,
sourceKind: classifyPromotionFamilySource(sourceFile),
manifestBacked: true,
status: "manifest-backed",
}))
);
const candidateRows = sourceRows
.filter((row) => row.sourceKind === "gcode")
.map((row, index) => ({
id: `evidence-candidate-${index + 1}`,
familyId: row.familyId,
label: `Evidence candidate ${index + 1}`,
value: row.value,
candidateStatus: "evidence-ready",
promotionAllowed: false,
baselineChanging: false,
sourceKind: row.sourceKind,
manifestBacked: row.manifestBacked,
}));
const ready = rows.length > 0 && rows.every(({ value }) => String(value).includes("diagnostics=ready"));
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-rows-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: "Promotion family diagnostics",
statusText: ready ? "Ready" : "Blocked",
detailText: ready ? `${rows.length} promotion families ready` : "promotion family rows missing",
statusLine: `${ready ? "Ready" : "Blocked"}: ${ready ? `${rows.length} promotion families ready` : "promotion family rows missing"}`,
rows,
sourceRows,
candidateRows,
sourceFileCount: sourceRows.length,
candidateCount: candidateRows.length,
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-promotion-family-rows",
},
};
}
export function createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(
renderState = createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState(),
{ sourceKind = "all", familyId = "all" } = {},
) {
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const sourceRows = Array.isArray(renderState?.sourceRows) ? renderState.sourceRows : [];
const selectedFamilyId = normalizePromotionFamilyFilter(familyId, rows);
const familyScopedSourceRows = selectedFamilyId === "all"
? sourceRows
: sourceRows.filter((sourceRow) => sourceRow.familyId === selectedFamilyId);
const sourceKindCounts = familyScopedSourceRows.reduce((counts, sourceRow) => ({
...counts,
[sourceRow.sourceKind]: (counts[sourceRow.sourceKind] ?? 0) + 1,
}), {});
const totalSourceFileCount = sourceRows.length;
const scopedSourceFileCount = familyScopedSourceRows.length;
const selectedSourceKind = normalizePromotionFamilySourceKindFilter(sourceKind);
const filteredSourceRows = selectedSourceKind === "all"
? familyScopedSourceRows
: familyScopedSourceRows.filter((sourceRow) => sourceRow.sourceKind === selectedSourceKind);
const candidateRows = Array.isArray(renderState?.candidateRows) ? renderState.candidateRows : [];
const filteredCandidateRows = selectedFamilyId === "all"
? candidateRows
: candidateRows.filter((candidateRow) => candidateRow.familyId === selectedFamilyId);
const familyFilters = [
{
id: "all",
label: "All",
selected: selectedFamilyId === "all",
count: totalSourceFileCount,
},
...rows.map((row) => ({
id: row.id,
label: row.label,
selected: selectedFamilyId === row.id,
count: sourceRows.filter((sourceRow) => sourceRow.familyId === row.id).length,
})),
];
const sourceKindFilters = ["all", "ini", "gcode", "remap-subroutine", "source"]
.map((kind) => ({
id: kind,
label: kind === "all" ? "All" : kind,
selected: kind === selectedSourceKind,
count: kind === "all" ? scopedSourceFileCount : Number(sourceKindCounts[kind] ?? 0),
}))
.filter((filter) => filter.id === "all" || filter.count > 0);
const familyRows = rows
.filter((row) => selectedFamilyId === "all" || row.id === selectedFamilyId)
.map((row) => {
const familySourceRows = filteredSourceRows.filter((sourceRow) => sourceRow.familyId === row.id);
const familySourceKindCounts = familySourceRows.reduce((counts, sourceRow) => ({
...counts,
[sourceRow.sourceKind]: (counts[sourceRow.sourceKind] ?? 0) + 1,
}), {});
return {
id: row.id,
label: row.label,
value: row.value,
sourceFileCount: familySourceRows.length,
sourceKindCounts: familySourceKindCounts,
sourceKindSummary: formatPromotionFamilySourceKindCounts(familySourceKindCounts),
sourceRows: familySourceRows,
};
})
.filter((row) => row.sourceFileCount > 0);
const ready = renderState?.ready === true && totalSourceFileCount > 0;
const selectedCount = filteredSourceRows.length;
const selectedCandidateCount = filteredCandidateRows.length;
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-source-filter-view-model",
viewModelVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
selectedFamilyId,
selectedSourceKind,
statusText: ready ? "Ready" : "Blocked",
detailText: ready
? `${selectedCount}/${totalSourceFileCount} source files selected`
: "promotion family source rows missing",
statusLine: `${ready ? "Ready" : "Blocked"}: ${ready ? `${selectedCount}/${totalSourceFileCount} source files selected` : "promotion family source rows missing"}`,
familyFilters,
sourceKindFilters,
sourceKindCounts,
totalSourceFileCount,
scopedSourceFileCount,
filteredSourceFileCount: selectedCount,
totalCandidateCount: candidateRows.length,
filteredCandidateCount: selectedCandidateCount,
familyRows,
sourceRows: filteredSourceRows,
candidateRows: filteredCandidateRows,
};
}
export function createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract({
rowDatasetPrefix = "workflowOverviewPromotionFamilySourceFilter",
selectors = {},
} = {}) {
const mountSelector = selectors.mount ?? "[data-workflow-overview-promotion-family-source-filter]";
const statusSelector = selectors.status ?? "[data-workflow-overview-promotion-family-source-filter-status]";
const controlsSelector = selectors.controls ?? "[data-workflow-overview-promotion-family-source-filter-controls]";
const rowsSelector = selectors.rows ?? "[data-workflow-overview-promotion-family-source-filter-rows]";
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-source-filter-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "controls", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
controls: controlsSelector,
rows: rowsSelector,
},
mountDatasetKeys: [
"handoffPhase",
"handoffReady",
"handoffScope",
"selectedFamilyId",
"selectedSourceKind",
],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: [
"rendered",
"statusLine",
"rowCount",
"controlCount",
"filterRowCount",
"sourceFileCount",
"dataset",
],
};
}
export function createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomReadiness({
rowDatasetPrefix = "workflowOverviewPromotionFamilySourceFilter",
contract = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
controlsNode = documentRef?.querySelector?.(contract.selectors.controls),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
controls: Boolean(controlsNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-source-filter-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
function readPromotionFamilySourceFilterControlValue(
controlsNode,
rowDatasetPrefix,
controlId,
fallbackValue = "all",
) {
const nodes = Array.from(controlsNode?.children ?? []);
const selectNode = nodes.find((node) => node?.dataset?.[`${rowDatasetPrefix}Select`] === controlId);
return selectNode?.value ?? selectNode?.dataset?.[`${rowDatasetPrefix}Value`] ?? fallbackValue;
}
export function createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionActionPlan(
renderState = createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState(),
{
familyId = "all",
sourceKind = "all",
previousViewModel = null,
} = {},
) {
const nextViewModel = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(
renderState,
{ familyId, sourceKind },
);
const changed = previousViewModel === null ||
previousViewModel.selectedFamilyId !== nextViewModel.selectedFamilyId ||
previousViewModel.selectedSourceKind !== nextViewModel.selectedSourceKind;
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-source-filter-selection-action-plan",
actionPlanVersion: 1,
phase: nextViewModel.ready ? "ready" : "blocked",
ready: nextViewModel.ready,
changed,
selectedFamilyId: nextViewModel.selectedFamilyId,
selectedSourceKind: nextViewModel.selectedSourceKind,
filteredSourceFileCount: nextViewModel.filteredSourceFileCount,
scopedSourceFileCount: nextViewModel.scopedSourceFileCount,
totalSourceFileCount: nextViewModel.totalSourceFileCount,
statusLine: changed
? `Ready: source filter changed to ${nextViewModel.selectedFamilyId} / ${nextViewModel.selectedSourceKind}`
: "Ready: source filter unchanged",
nextViewModel,
};
}
export function handleIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionChange({
renderState = createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState(),
viewModel = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(renderState),
rowDatasetPrefix = "workflowOverviewPromotionFamilySourceFilter",
contract = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
controlsNode = documentRef?.querySelector?.(contract.selectors.controls),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
render = false,
} = {}) {
const selectedFamilyId = readPromotionFamilySourceFilterControlValue(
controlsNode,
contract.rowDatasetPrefix,
"family",
viewModel?.selectedFamilyId ?? "all",
);
const selectedSourceKind = readPromotionFamilySourceFilterControlValue(
controlsNode,
contract.rowDatasetPrefix,
"source-kind",
viewModel?.selectedSourceKind ?? "all",
);
const actionPlan = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionActionPlan(
renderState,
{
familyId: selectedFamilyId,
sourceKind: selectedSourceKind,
previousViewModel: viewModel,
},
);
const renderResult = render
? renderIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState(actionPlan.nextViewModel, {
contract,
documentRef,
mountNode,
statusNode,
controlsNode,
rowsNode,
})
: null;
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-source-filter-selection-change",
workflowVersion: 1,
phase: actionPlan.phase,
ready: actionPlan.ready,
statusLine: actionPlan.statusLine,
selectedFamilyId: actionPlan.selectedFamilyId,
selectedSourceKind: actionPlan.selectedSourceKind,
actionPlan,
viewModel: actionPlan.nextViewModel,
renderResult,
};
}
export function bindIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionControls({
renderState = createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState(),
viewModel = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(renderState),
rowDatasetPrefix = "workflowOverviewPromotionFamilySourceFilter",
contract = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
controlsNode = documentRef?.querySelector?.(contract.selectors.controls),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
render = true,
onChange = null,
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
controlsNode,
rowsNode,
});
const selectNodes = Array.from(controlsNode?.children ?? [])
.filter((node) => typeof node?.dataset?.[`${contract.rowDatasetPrefix}Select`] === "string");
if (!domReadiness.ready || selectNodes.length === 0) {
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-source-filter-selection-controls-binding",
bindingVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.ready ? "selector controls missing" : domReadiness.missing.join(", ")}`,
boundControlCount: 0,
controlIds: [],
domReadiness,
lastChange: null,
triggerChange: () => null,
unbind: () => ({ unbound: 0 }),
};
}
const binding = {
apiName: "ini-panel-shell-workflow-overview-promotion-family-source-filter-selection-controls-binding",
bindingVersion: 1,
phase: "ready",
ready: true,
statusLine: `Ready: ${selectNodes.length} selector controls bound`,
boundControlCount: selectNodes.length,
controlIds: selectNodes.map((node) => node.dataset[`${contract.rowDatasetPrefix}Select`]),
domReadiness,
lastChange: null,
triggerChange: null,
unbind: null,
};
const handleChange = () => {
const changeResult = handleIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionChange({
renderState,
viewModel,
contract,
documentRef,
mountNode,
statusNode,
controlsNode,
rowsNode,
render,
});
binding.lastChange = changeResult;
if (typeof onChange === "function") {
onChange(changeResult);
}
return changeResult;
};
const unbinders = selectNodes.map((node) => {
if (typeof node.addEventListener === "function") {
node.addEventListener("change", handleChange);
return () => node.removeEventListener?.("change", handleChange);
}
node.onchange = handleChange;
return () => {
if (node.onchange === handleChange) {
node.onchange = null;
}
};
});
binding.triggerChange = handleChange;
binding.unbind = () => {
for (const unbind of unbinders) {
unbind();
}
return { unbound: unbinders.length };
};
return binding;
}
export function renderIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState(
viewModel = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(),
{
rowDatasetPrefix = "workflowOverviewPromotionFamilySourceFilter",
contract = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
controlsNode = documentRef?.querySelector?.(contract.selectors.controls),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
controlsNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview promotion family source filter DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = viewModel?.phase ?? "blocked";
mountNode.dataset.handoffReady = viewModel?.ready === true ? "true" : "false";
mountNode.dataset.handoffScope = "workflow-overview-promotion-family-source-filter";
mountNode.dataset.selectedFamilyId = viewModel?.selectedFamilyId ?? "all";
mountNode.dataset.selectedSourceKind = viewModel?.selectedSourceKind ?? "all";
statusNode.textContent = viewModel?.statusLine ?? "Blocked: promotion family source filter missing";
controlsNode.replaceChildren();
rowsNode.replaceChildren();
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
const controlSpecs = [
{
id: "family",
label: "Family",
value: viewModel?.selectedFamilyId ?? "all",
optionRows: Array.isArray(viewModel?.familyFilters) ? viewModel.familyFilters : [],
},
{
id: "source-kind",
label: "Source kind",
value: viewModel?.selectedSourceKind ?? "all",
optionRows: Array.isArray(viewModel?.sourceKindFilters) ? viewModel.sourceKindFilters : [],
},
];
for (const controlSpec of controlSpecs) {
const label = documentRef.createElement("label");
label.dataset[`${effectiveRowDatasetPrefix}Control`] = controlSpec.id;
label.dataset[`${effectiveRowDatasetPrefix}ControlValue`] = controlSpec.value;
label.textContent = controlSpec.label;
const select = documentRef.createElement("select");
select.dataset[`${effectiveRowDatasetPrefix}Select`] = controlSpec.id;
select.dataset[`${effectiveRowDatasetPrefix}Value`] = controlSpec.value;
select.value = controlSpec.value;
for (const optionRow of controlSpec.optionRows) {
const option = documentRef.createElement("option");
option.dataset[`${effectiveRowDatasetPrefix}Option`] = optionRow.id;
option.dataset[`${effectiveRowDatasetPrefix}Count`] = String(optionRow.count ?? 0);
option.dataset[`${effectiveRowDatasetPrefix}Selected`] = optionRow.selected ? "true" : "false";
option.value = optionRow.id;
option.textContent = `${optionRow.label}: ${optionRow.count ?? 0}`;
if (optionRow.selected === true) {
option.selected = true;
}
select.append(option);
}
controlsNode.append(label, select);
}
const filterRows = [
...(Array.isArray(viewModel?.familyFilters) ? viewModel.familyFilters : []).map((filter) => ({
...filter,
rowType: "family-filter",
id: `family-${filter.id}`,
value: filter.id,
})),
...(Array.isArray(viewModel?.sourceKindFilters) ? viewModel.sourceKindFilters : []).map((filter) => ({
...filter,
rowType: "source-kind-filter",
id: `source-kind-${filter.id}`,
value: filter.id,
})),
];
const sourceRows = Array.isArray(viewModel?.sourceRows) ? viewModel.sourceRows : [];
const candidateRows = Array.isArray(viewModel?.candidateRows) ? viewModel.candidateRows : [];
const rows = [
...filterRows,
...sourceRows.map((sourceRow) => ({
...sourceRow,
rowType: "source-row",
})),
...candidateRows.map((candidateRow) => ({
...candidateRow,
rowType: "candidate-row",
})),
];
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Type`] = row.rowType;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = viewModel?.ready === true ? "pass" : "blocked";
if (row.selected != null) {
term.dataset[`${effectiveRowDatasetPrefix}Selected`] = row.selected ? "true" : "false";
}
if (row.familyId) {
term.dataset[`${effectiveRowDatasetPrefix}Family`] = row.familyId;
}
if (row.sourceKind) {
term.dataset[`${effectiveRowDatasetPrefix}SourceKind`] = row.sourceKind;
}
if (row.candidateStatus) {
term.dataset[`${effectiveRowDatasetPrefix}CandidateStatus`] = row.candidateStatus;
term.dataset[`${effectiveRowDatasetPrefix}PromotionAllowed`] = row.promotionAllowed ? "1" : "0";
term.dataset[`${effectiveRowDatasetPrefix}BaselineChanging`] = row.baselineChanging ? "yes" : "no";
}
term.textContent = row.label ?? row.id;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.value ?? row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Type`] = row.rowType;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = viewModel?.ready === true ? "pass" : "blocked";
if (row.selected != null) {
detail.dataset[`${effectiveRowDatasetPrefix}Selected`] = row.selected ? "true" : "false";
}
if (row.familyId) {
detail.dataset[`${effectiveRowDatasetPrefix}Family`] = row.familyId;
}
if (row.sourceKind) {
detail.dataset[`${effectiveRowDatasetPrefix}SourceKind`] = row.sourceKind;
}
if (row.candidateStatus) {
detail.dataset[`${effectiveRowDatasetPrefix}CandidateStatus`] = row.candidateStatus;
detail.dataset[`${effectiveRowDatasetPrefix}PromotionAllowed`] = row.promotionAllowed ? "1" : "0";
detail.dataset[`${effectiveRowDatasetPrefix}BaselineChanging`] = row.baselineChanging ? "yes" : "no";
}
detail.textContent = row.rowType === "source-row"
? row.value
: (
row.rowType === "candidate-row"
? row.value
: `${row.value}: ${row.count ?? 0}${row.selected ? " selected" : ""}`
);
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
controlCount: controlSpecs.length,
filterRowCount: filterRows.length,
sourceFileCount: sourceRows.length,
candidateCount: candidateRows.length,
rowIds: rows.map(({ id }) => id),
sourceRowIds: sourceRows.map(({ id }) => id),
candidateRowIds: candidateRows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
selectedFamilyId: mountNode.dataset.selectedFamilyId,
selectedSourceKind: mountNode.dataset.selectedSourceKind,
},
};
}
export function mountIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState({
viewModel = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel(),
rowDatasetPrefix = "workflowOverviewPromotionFamilySourceFilter",
contract = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
controlsNode = documentRef?.querySelector?.(contract.selectors.controls),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
controlsNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-source-filter-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
viewModel,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState(viewModel, {
contract,
documentRef,
mountNode,
statusNode,
controlsNode,
rowsNode,
});
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-source-filter-dom-mount",
workflowVersion: 1,
phase: viewModel?.phase === "ready" ? "ready" : "blocked",
ready: viewModel?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
viewModel,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-source-filter-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "promotion family source filter DOM mount error"}`,
contract,
domReadiness,
viewModel,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomContract({
rowDatasetPrefix = "workflowOverviewPromotionFamily",
selectors = {},
} = {}) {
const mountSelector = selectors.mount ?? "[data-workflow-overview-promotion-family-rows]";
const statusSelector = selectors.status ?? "[data-workflow-overview-promotion-family-rows-status]";
const rowsSelector = selectors.rows ?? "[data-workflow-overview-promotion-family-row-list]";
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-rows-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: ["rendered", "statusLine", "rowCount", "rowIds", "sourceFileCount", "dataset"],
};
}
export function createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomReadiness({
rowDatasetPrefix = "workflowOverviewPromotionFamily",
contract = createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-rows-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellWorkflowOverviewPromotionFamilyRowsState(
renderState = createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState(),
{
rowDatasetPrefix = "workflowOverviewPromotionFamily",
contract = createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview promotion family rows DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope
?? "workflow-overview-promotion-family-rows";
statusNode.textContent = renderState?.statusLine ?? "Blocked: promotion family rows missing";
rowsNode.replaceChildren();
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const sourceRows = Array.isArray(renderState?.sourceRows) ? renderState.sourceRows : [];
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
for (const row of [...rows, ...sourceRows]) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
if (row.sourceKindSummary) {
term.dataset[`${effectiveRowDatasetPrefix}SourceKindCounts`] = row.sourceKindSummary;
}
if (row.familyId) {
term.dataset[`${effectiveRowDatasetPrefix}Family`] = row.familyId;
}
if (row.sourceKind) {
term.dataset[`${effectiveRowDatasetPrefix}SourceKind`] = row.sourceKind;
term.dataset[`${effectiveRowDatasetPrefix}ManifestBacked`] = row.manifestBacked ? "true" : "false";
}
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
if (row.sourceKindSummary) {
detail.dataset[`${effectiveRowDatasetPrefix}SourceKindCounts`] = row.sourceKindSummary;
}
if (row.familyId) {
detail.dataset[`${effectiveRowDatasetPrefix}Family`] = row.familyId;
}
if (row.sourceKind) {
detail.dataset[`${effectiveRowDatasetPrefix}SourceKind`] = row.sourceKind;
detail.dataset[`${effectiveRowDatasetPrefix}ManifestBacked`] = row.manifestBacked ? "true" : "false";
detail.dataset[`${effectiveRowDatasetPrefix}SourceStatus`] = row.status ?? "manifest-backed";
}
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
detail.textContent = row.sourceKindSummary ? `${row.value}; ${row.sourceKindSummary}` : row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length + sourceRows.length,
rowIds: rows.map(({ id }) => id),
sourceFileCount: sourceRows.length,
sourceRowIds: sourceRows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellWorkflowOverviewPromotionFamilyRowsState({
renderState = createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState(),
rowDatasetPrefix = "workflowOverviewPromotionFamily",
contract = createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-rows-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewPromotionFamilyRowsState(renderState, {
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-rows-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-promotion-family-rows-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "promotion family rows DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
function findWorkflowOverviewRowValue(summaryViewModel = {}, rowId = "") {
const row = Array.isArray(summaryViewModel?.rows)
? summaryViewModel.rows.find(({ id }) => id === rowId)
: null;
return row?.value ?? null;
}
export function createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownViewModel(
summaryViewModel = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(),
{
diagnosticsArtifact = null,
candidateId = findWorkflowOverviewRowValue(summaryViewModel, "virtual-hal-promotion-candidate"),
} = {},
) {
const candidateReport = diagnosticsArtifact?.virtualHalSimConfigPromotionCandidates ?? null;
const candidateRows = Array.isArray(candidateReport?.rows) ? candidateReport.rows : [];
const candidate = candidateRows.find((row) => row.id === candidateId) ?? null;
const requiredReports = Array.isArray(candidate?.requiredVirtualHalReports)
? candidate.requiredVirtualHalReports
: [];
const sourceFiles = Array.isArray(candidate?.sourceFiles) ? candidate.sourceFiles : [];
const blockedFamilyExcluded = candidate?.blockedKind === "-" && candidate?.blockedKindExcluded === true;
const nodeInventoryReady = candidate?.currentNodeInventoryStatus === "PASS" && candidate?.nodeStatusReady === true;
const browserEvidenceReady = candidate?.targetBrowserEvidence === "explicit-browser-diagnostics" &&
candidate?.currentMatrixBrowserStatus === "explicit-browser-diagnostics";
const virtualHalReportsReady = requiredReports.length > 0 &&
Array.isArray(candidateReport?.availableVirtualHalReports) &&
requiredReports.every((reportId) => candidateReport.availableVirtualHalReports.includes(reportId));
const complete = candidate?.complete === true &&
blockedFamilyExcluded &&
nodeInventoryReady &&
browserEvidenceReady &&
virtualHalReportsReady &&
sourceFiles.length > 0;
const summaryCandidateId = candidateId ?? "not provided";
const candidateEvidenceReady = candidate?.complete === true &&
blockedFamilyExcluded &&
nodeInventoryReady &&
browserEvidenceReady;
const promotionCandidateLayers =
findWorkflowOverviewRowValue(summaryViewModel, "promotion-candidate-layers") ??
(candidateEvidenceReady ? "evidence-ready" : "not provided");
const promotionCandidateAllowed =
findWorkflowOverviewRowValue(summaryViewModel, "promotion-candidate-allowed") ??
(candidateEvidenceReady ? "0" : "not provided");
const promotionBaselineChanging = promotionCandidateAllowed === "0"
? "no"
: (promotionCandidateAllowed === "not provided" ? "not provided" : "yes");
const rows = [
{
id: "candidate",
label: "Candidate",
value: summaryCandidateId,
},
{
id: "ini",
label: "INI",
value: candidate?.iniPath ?? findWorkflowOverviewRowValue(summaryViewModel, "virtual-hal-promotion-candidate-ini") ?? "not provided",
},
{
id: "gcode",
label: "G-code",
value: candidate?.gcodePath ?? findWorkflowOverviewRowValue(summaryViewModel, "virtual-hal-promotion-candidate-gcode") ?? "not provided",
},
{
id: "node-inventory",
label: "Node inventory",
value: nodeInventoryReady ? "PASS" : (candidate?.currentNodeInventoryStatus ?? "not provided"),
},
{
id: "browser-evidence",
label: "Browser evidence",
value: browserEvidenceReady ? "explicit-browser-diagnostics" : (candidate?.targetBrowserEvidence ?? "not provided"),
},
{
id: "blocked-family-exclusion",
label: "Blocked-family exclusion",
value: blockedFamilyExcluded ? "passed" : (candidate?.blockedKind ?? "not provided"),
},
{
id: "candidate-layer",
label: "Candidate layer",
value: promotionCandidateLayers.includes("evidence-ready")
? "evidence-ready"
: promotionCandidateLayers,
},
{
id: "inventory-promotion-allowed",
label: "Inventory promotion allowed",
value: promotionCandidateAllowed,
},
{
id: "inventory-baseline-changing",
label: "Inventory baseline changing",
value: promotionBaselineChanging,
},
{
id: "virtual-hal-reports",
label: "Required virtual HAL reports",
value: requiredReports.length > 0 ? requiredReports.join(", ") : "not provided",
},
{
id: "source-files",
label: "Source files",
value: `${sourceFiles.length}`,
},
{
id: "inventory-baseline",
label: "Inventory baseline",
value: findWorkflowOverviewRowValue(summaryViewModel, "virtual-hal-promotion-candidate-baseline") ?? "not provided",
},
];
const sourceRows = sourceFiles.map((sourceFile, index) => ({
id: `source-${index + 1}`,
label: `Source ${index + 1}`,
value: sourceFile,
sourceKind: classifyPromotionFamilySource(sourceFile),
manifestBacked: candidate?.manifestChecked === true,
}));
const evidenceRows = candidateRows.map((row, index) => ({
id: `evidence-${index + 1}`,
label: row.id ?? `Evidence ${index + 1}`,
value: row.gcodePath ?? "not provided",
familyId: row.simConfigTarget ?? "not provided",
sourceFileCount: Array.isArray(row.sourceFiles) ? row.sourceFiles.length : 0,
manifestBacked: row.manifestChecked === true,
status: row.complete === true &&
row.currentNodeInventoryStatus === "PASS" &&
row.blockedKind === "-" &&
row.targetBrowserEvidence === "explicit-browser-diagnostics"
? "evidence-ready"
: "blocked",
}));
return {
apiName: "ini-panel-shell-workflow-overview-promotion-candidate-drilldown-view-model",
viewModelVersion: 1,
phase: complete ? "ready" : "blocked",
ready: complete,
title: "Promotion candidate drilldown",
statusText: complete ? "Ready" : "Blocked",
detailText: complete
? `${summaryCandidateId} source-derived browser evidence ready`
: `${summaryCandidateId} drilldown evidence incomplete`,
statusLine: `${complete ? "Ready" : "Blocked"}: ${complete ? `${summaryCandidateId} source-derived browser evidence ready` : `${summaryCandidateId} drilldown evidence incomplete`}`,
candidateId: summaryCandidateId,
candidate,
rows,
sourceRows,
evidenceRows,
sourceFileCount: sourceRows.length,
evidenceRowCount: evidenceRows.length,
requiredReports,
blockedFamilyExcluded,
nodeInventoryReady,
browserEvidenceReady,
virtualHalReportsReady,
dataset: {
handoffPhase: complete ? "ready" : "blocked",
handoffReady: complete ? "true" : "false",
handoffScope: "workflow-overview-promotion-candidate-drilldown",
candidateId: summaryCandidateId,
},
};
}
export function createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownRenderState(
viewModel = createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownViewModel(),
) {
const rows = [
...(Array.isArray(viewModel?.rows) ? viewModel.rows : []),
...(Array.isArray(viewModel?.sourceRows) ? viewModel.sourceRows : []).map((row) => ({
...row,
label: `${row.label} (${row.sourceKind})`,
})),
...(Array.isArray(viewModel?.evidenceRows) ? viewModel.evidenceRows : []).map((row) => ({
...row,
label: `${row.label} (${row.familyId})`,
evidenceReady: row.status === "evidence-ready",
})),
].map(({ id, label, value, sourceKind, manifestBacked, familyId, sourceFileCount, evidenceReady }) => ({
id,
label,
value: value == null ? "" : String(value),
...(sourceKind ? { sourceKind } : {}),
...(familyId ? { familyId } : {}),
...(sourceFileCount != null ? { sourceFileCount: Number(sourceFileCount) } : {}),
...(evidenceReady != null ? { evidenceReady: evidenceReady === true } : {}),
...(manifestBacked != null ? { manifestBacked: manifestBacked === true } : {}),
}));
const ready = viewModel?.ready === true;
return {
apiName: "ini-panel-shell-workflow-overview-promotion-candidate-drilldown-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: viewModel?.title ?? "Promotion candidate drilldown",
statusText: viewModel?.statusText ?? (ready ? "Ready" : "Blocked"),
detailText: viewModel?.detailText ?? "promotion candidate drilldown missing",
statusLine: viewModel?.statusLine ?? `${ready ? "Ready" : "Blocked"}: promotion candidate drilldown`,
candidateId: viewModel?.candidateId ?? "not provided",
rows,
rowCount: rows.length,
sourceFileCount: viewModel?.sourceFileCount ?? 0,
evidenceRowCount: viewModel?.evidenceRowCount ?? 0,
dataset: viewModel?.dataset ?? {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-promotion-candidate-drilldown",
candidateId: viewModel?.candidateId ?? "not provided",
},
};
}
export function createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomContract({
rowDatasetPrefix = "workflowOverviewPromotionCandidateDrilldown",
selectors = {},
} = {}) {
const mountSelector = selectors.mount ?? "[data-workflow-overview-promotion-candidate-drilldown]";
const statusSelector = selectors.status ?? "[data-workflow-overview-promotion-candidate-drilldown-status]";
const rowsSelector = selectors.rows ?? "[data-workflow-overview-promotion-candidate-drilldown-rows]";
return {
apiName: "ini-panel-shell-workflow-overview-promotion-candidate-drilldown-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope", "candidateId"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
};
}
export function createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomReadiness({
rowDatasetPrefix = "workflowOverviewPromotionCandidateDrilldown",
contract = createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-promotion-candidate-drilldown-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellWorkflowOverviewPromotionCandidateDrilldownState(
renderState = createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownRenderState(),
{
rowDatasetPrefix = "workflowOverviewPromotionCandidateDrilldown",
contract = createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview promotion candidate drilldown DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope
?? "workflow-overview-promotion-candidate-drilldown";
mountNode.dataset.candidateId = renderState?.candidateId ?? renderState?.dataset?.candidateId ?? "not provided";
statusNode.textContent = renderState?.statusLine ?? "Blocked: promotion candidate drilldown missing";
rowsNode.replaceChildren();
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
if (row.sourceKind) {
term.dataset[`${effectiveRowDatasetPrefix}SourceKind`] = row.sourceKind;
term.dataset[`${effectiveRowDatasetPrefix}ManifestBacked`] = row.manifestBacked ? "true" : "false";
}
if (row.familyId) {
term.dataset[`${effectiveRowDatasetPrefix}FamilyId`] = row.familyId;
term.dataset[`${effectiveRowDatasetPrefix}EvidenceReady`] = row.evidenceReady ? "true" : "false";
term.dataset[`${effectiveRowDatasetPrefix}SourceFileCount`] = String(row.sourceFileCount ?? 0);
term.dataset[`${effectiveRowDatasetPrefix}ManifestBacked`] = row.manifestBacked ? "true" : "false";
}
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
if (row.sourceKind) {
detail.dataset[`${effectiveRowDatasetPrefix}SourceKind`] = row.sourceKind;
detail.dataset[`${effectiveRowDatasetPrefix}ManifestBacked`] = row.manifestBacked ? "true" : "false";
}
if (row.familyId) {
detail.dataset[`${effectiveRowDatasetPrefix}FamilyId`] = row.familyId;
detail.dataset[`${effectiveRowDatasetPrefix}EvidenceReady`] = row.evidenceReady ? "true" : "false";
detail.dataset[`${effectiveRowDatasetPrefix}SourceFileCount`] = String(row.sourceFileCount ?? 0);
detail.dataset[`${effectiveRowDatasetPrefix}ManifestBacked`] = row.manifestBacked ? "true" : "false";
}
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
sourceFileCount: rows.filter(({ sourceKind }) => Boolean(sourceKind)).length,
evidenceRowCount: rows.filter(({ familyId }) => Boolean(familyId)).length,
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
candidateId: mountNode.dataset.candidateId,
},
};
}
export function mountIniPanelShellWorkflowOverviewPromotionCandidateDrilldownState({
renderState = createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownRenderState(),
rowDatasetPrefix = "workflowOverviewPromotionCandidateDrilldown",
contract = createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-promotion-candidate-drilldown-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewPromotionCandidateDrilldownState(renderState, {
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
return {
apiName: "ini-panel-shell-workflow-overview-promotion-candidate-drilldown-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-promotion-candidate-drilldown-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "promotion candidate drilldown DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function createIniPanelShellWorkflowOverviewHardBlockDrilldownViewModel(
summaryViewModel = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(),
{
validation = null,
} = {},
) {
const summary = validation?.promotionCandidateArtifactSummary ?? {};
const detailRows = Array.isArray(summary.hardBlockRuntimeFamilyDetailRows)
? summary.hardBlockRuntimeFamilyDetailRows
: [];
const familyRows = Array.isArray(summary.hardBlockRuntimeFamilySummaryRows)
? summary.hardBlockRuntimeFamilySummaryRows
: [];
const promotionAllowedCount = Number(summary.hardBlockRuntimePromotionAllowedCount ?? 0);
const ready = detailRows.length > 0 && promotionAllowedCount === 0;
const rows = [
{
id: "detail-row-count",
label: "Hard-block detail rows",
value: `${detailRows.length}`,
},
{
id: "family-count",
label: "Hard-block families",
value: `${familyRows.length}`,
},
{
id: "promotion-allowed",
label: "Promotion allowed",
value: `${promotionAllowedCount}`,
},
{
id: "inventory-baseline",
label: "Inventory baseline",
value: findWorkflowOverviewRowValue(summaryViewModel, "virtual-hal-promotion-candidate-baseline")
?? summary.inventoryBaseline
?? "not provided",
},
];
const familyDetailRows = detailRows.map((row, index) => ({
id: row.id ?? `hard-block-detail-${index + 1}`,
label: `${row.family} ${index + 1}`,
value: row.path ?? "not provided",
family: row.family ?? "not provided",
path: row.path ?? "not provided",
blockReason: row.blockReason ?? "not provided",
nextProof: row.nextProof ?? "not provided",
promotionAllowed: row.promotionAllowed === true,
}));
return {
apiName: "ini-panel-shell-workflow-overview-hard-block-drilldown-view-model",
viewModelVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: "Hard-block drilldown",
statusText: ready ? "Ready" : "Blocked",
detailText: ready
? `${detailRows.length} locked rows grouped by ${familyRows.length} families`
: "hard-block detail rows missing",
statusLine: `${ready ? "Ready" : "Blocked"}: ${ready ? `${detailRows.length} locked rows grouped by ${familyRows.length} families` : "hard-block detail rows missing"}`,
rows,
detailRows: familyDetailRows,
rowCount: rows.length + familyDetailRows.length,
detailRowCount: familyDetailRows.length,
familyCount: familyRows.length,
promotionAllowedCount,
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-hard-block-drilldown",
},
};
}
export function createIniPanelShellWorkflowOverviewHardBlockDrilldownRenderState(
viewModel = createIniPanelShellWorkflowOverviewHardBlockDrilldownViewModel(),
) {
const rows = [
...(Array.isArray(viewModel?.rows) ? viewModel.rows : []),
...(Array.isArray(viewModel?.detailRows) ? viewModel.detailRows : []).map((row) => ({
...row,
label: `${row.family}: ${row.path}`,
value: `${row.blockReason}; next=${row.nextProof}; promotion_allowed=${row.promotionAllowed ? "1" : "0"}`,
hardBlockDetail: true,
})),
].map(({ id, label, value, family, path, blockReason, nextProof, promotionAllowed, hardBlockDetail }) => ({
id,
label,
value: value == null ? "" : String(value),
...(family ? { family } : {}),
...(path ? { path } : {}),
...(blockReason ? { blockReason } : {}),
...(nextProof ? { nextProof } : {}),
...(promotionAllowed != null ? { promotionAllowed: promotionAllowed === true } : {}),
...(hardBlockDetail != null ? { hardBlockDetail: hardBlockDetail === true } : {}),
}));
const ready = viewModel?.ready === true;
return {
apiName: "ini-panel-shell-workflow-overview-hard-block-drilldown-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: viewModel?.title ?? "Hard-block drilldown",
statusText: viewModel?.statusText ?? (ready ? "Ready" : "Blocked"),
detailText: viewModel?.detailText ?? "hard-block drilldown missing",
statusLine: viewModel?.statusLine ?? `${ready ? "Ready" : "Blocked"}: hard-block drilldown`,
rows,
rowCount: rows.length,
detailRowCount: viewModel?.detailRowCount ?? 0,
familyCount: viewModel?.familyCount ?? 0,
promotionAllowedCount: viewModel?.promotionAllowedCount ?? 0,
dataset: viewModel?.dataset ?? {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-hard-block-drilldown",
},
};
}
export function createIniPanelShellWorkflowOverviewHardBlockDrilldownDomContract({
rowDatasetPrefix = "workflowOverviewHardBlockDrilldown",
selectors = {},
} = {}) {
return {
apiName: "ini-panel-shell-workflow-overview-hard-block-drilldown-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: selectors.mount ?? "[data-workflow-overview-hard-block-drilldown]",
status: selectors.status ?? "[data-workflow-overview-hard-block-drilldown-status]",
rows: selectors.rows ?? "[data-workflow-overview-hard-block-drilldown-rows]",
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
};
}
export function createIniPanelShellWorkflowOverviewHardBlockDrilldownDomReadiness({
rowDatasetPrefix = "workflowOverviewHardBlockDrilldown",
contract = createIniPanelShellWorkflowOverviewHardBlockDrilldownDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-hard-block-drilldown-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellWorkflowOverviewHardBlockDrilldownState(
renderState = createIniPanelShellWorkflowOverviewHardBlockDrilldownRenderState(),
{
rowDatasetPrefix = "workflowOverviewHardBlockDrilldown",
contract = createIniPanelShellWorkflowOverviewHardBlockDrilldownDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewHardBlockDrilldownDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview hard-block drilldown DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope
?? "workflow-overview-hard-block-drilldown";
statusNode.textContent = renderState?.statusLine ?? "Blocked: hard-block drilldown missing";
rowsNode.replaceChildren();
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
if (row.family) {
term.dataset[`${effectiveRowDatasetPrefix}Family`] = row.family;
term.dataset[`${effectiveRowDatasetPrefix}Path`] = row.path ?? "";
term.dataset[`${effectiveRowDatasetPrefix}PromotionAllowed`] = row.promotionAllowed ? "1" : "0";
term.dataset[`${effectiveRowDatasetPrefix}HardBlockDetail`] = row.hardBlockDetail ? "true" : "false";
}
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
if (row.family) {
detail.dataset[`${effectiveRowDatasetPrefix}Family`] = row.family;
detail.dataset[`${effectiveRowDatasetPrefix}Path`] = row.path ?? "";
detail.dataset[`${effectiveRowDatasetPrefix}PromotionAllowed`] = row.promotionAllowed ? "1" : "0";
detail.dataset[`${effectiveRowDatasetPrefix}HardBlockDetail`] = row.hardBlockDetail ? "true" : "false";
}
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
detailRowCount: rows.filter(({ hardBlockDetail }) => hardBlockDetail === true).length,
familyCount: renderState?.familyCount ?? 0,
promotionAllowedCount: renderState?.promotionAllowedCount ?? 0,
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellWorkflowOverviewHardBlockDrilldownState({
renderState = createIniPanelShellWorkflowOverviewHardBlockDrilldownRenderState(),
rowDatasetPrefix = "workflowOverviewHardBlockDrilldown",
contract = createIniPanelShellWorkflowOverviewHardBlockDrilldownDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewHardBlockDrilldownDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-hard-block-drilldown-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewHardBlockDrilldownState(renderState, {
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
return {
apiName: "ini-panel-shell-workflow-overview-hard-block-drilldown-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-hard-block-drilldown-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "hard-block drilldown DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactUrlWorkflow",
selectors = {},
} = {}) {
const mountSelector = selectors.mount ?? "[data-workflow-overview-release-readiness-artifact-url-workflow]";
const statusSelector = selectors.status
?? "[data-workflow-overview-release-readiness-artifact-url-workflow-status]";
const rowsSelector = selectors.rows
?? "[data-workflow-overview-release-readiness-artifact-url-workflow-rows]";
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: ["rendered", "statusLine", "rowCount", "rowIds", "dataset"],
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactUrlWorkflow",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState(
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState(),
{
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactUrlWorkflow",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview release readiness artifact URL workflow DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope
?? "workflow-overview-release-readiness-artifact-url-workflow";
statusNode.textContent = renderState?.statusLine
?? "Blocked: No release readiness artifact URL workflow render state";
rowsNode.replaceChildren();
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState({
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState(),
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactUrlWorkflow",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState(
renderState,
{
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
},
);
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-url-workflow-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "release readiness artifact URL workflow DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan(
validation = validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson("{}"),
) {
return validation?.actionPlan
?? createProjectReleaseReadinessArtifactValidationActionPlan(validation?.validation);
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState(
actionPlan = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan(),
) {
const rows = Array.isArray(actionPlan?.rows)
? actionPlan.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const commandRows = Array.isArray(actionPlan?.commands)
? actionPlan.commands.map((command) => ({
id: `command-${command.id}`,
label: command.label ?? command.id,
value: command.command ?? "",
}))
: [];
const ready = actionPlan?.ready === true;
const statusText = ready ? "Ready" : "Blocked";
const detailText = ready
? "Artifact validation action plan complete"
: (actionPlan?.nextCommand ?? "artifact validation action required");
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-validation-action-plan-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: "Release artifact validation action plan",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows: [...rows, ...commandRows],
commandRows,
nextActionId: actionPlan?.nextActionId ?? null,
nextCommand: actionPlan?.nextCommand ?? null,
shellScript: actionPlan?.shellScript ?? "",
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-release-readiness-artifact-validation-action-plan",
},
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactValidationActionPlan",
selectors = {},
} = {}) {
const mountSelector = selectors.mount
?? "[data-workflow-overview-release-readiness-artifact-validation-action-plan]";
const statusSelector = selectors.status
?? "[data-workflow-overview-release-readiness-artifact-validation-action-plan-status]";
const rowsSelector = selectors.rows
?? "[data-workflow-overview-release-readiness-artifact-validation-action-plan-rows]";
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-validation-action-plan-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: ["rendered", "statusLine", "rowCount", "rowIds", "dataset"],
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactValidationActionPlan",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-validation-action-plan-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState(
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState(),
{
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactValidationActionPlan",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview release readiness artifact validation action plan DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope
?? "workflow-overview-release-readiness-artifact-validation-action-plan";
statusNode.textContent = renderState?.statusLine
?? "Blocked: No release artifact validation action-plan render state";
rowsNode.replaceChildren();
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState({
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState(),
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactValidationActionPlan",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-validation-action-plan-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState(
renderState,
{
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
},
);
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-validation-action-plan-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-validation-action-plan-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "release artifact validation action-plan DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel(
validation = validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson("{}"),
) {
if (validation?.gateExecutionSummaryViewModel) {
return validation.gateExecutionSummaryViewModel;
}
return createProjectReleaseGateExecutionSummaryViewModel(
validation?.validation?.artifact?.gateExecutionManifest,
);
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel(
workflow = {},
) {
return workflow?.gateExecutionSummaryViewModel
?? createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel(
workflow?.validation,
);
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState(
summaryViewModel = createProjectReleaseGateExecutionSummaryViewModel(),
) {
const summaryRows = Array.isArray(summaryViewModel?.rows)
? summaryViewModel.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const gateRows = Array.isArray(summaryViewModel?.gateRows)
? summaryViewModel.gateRows.map((row) => ({
id: `gate-${row.id}`,
label: row.label ?? row.id,
value: `${row.status ?? (row.passed ? "passed" : "unknown")}: ${row.evidence ?? "missing"}`,
}))
: [];
const ready = summaryViewModel?.phase === "ready" && summaryViewModel?.ready === true;
const statusText = summaryViewModel?.statusText ?? (ready ? "Ready" : "Waiting");
const detailText = summaryViewModel?.detailText ?? "release gate evidence missing";
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-gate-execution-summary-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "waiting",
ready,
title: summaryViewModel?.title ?? "Project release gate execution",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows: [...summaryRows, ...gateRows],
gateRows,
dataset: {
handoffPhase: ready ? "ready" : "waiting",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-release-readiness-artifact-gate-execution-summary",
},
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactGateExecutionSummary",
selectors = {},
} = {}) {
const mountSelector = selectors.mount
?? "[data-workflow-overview-release-readiness-artifact-gate-execution-summary]";
const statusSelector = selectors.status
?? "[data-workflow-overview-release-readiness-artifact-gate-execution-summary-status]";
const rowsSelector = selectors.rows
?? "[data-workflow-overview-release-readiness-artifact-gate-execution-summary-rows]";
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-gate-execution-summary-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: ["rendered", "statusLine", "rowCount", "rowIds", "dataset"],
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactGateExecutionSummary",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-gate-execution-summary-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState(
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState(),
{
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactGateExecutionSummary",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview release readiness artifact gate execution summary DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "waiting";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope
?? "workflow-overview-release-readiness-artifact-gate-execution-summary";
statusNode.textContent = renderState?.statusLine
?? "Waiting: No release gate execution summary render state";
rowsNode.replaceChildren();
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "waiting";
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "waiting";
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState({
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState(),
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifactGateExecutionSummary",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract({
rowDatasetPrefix,
}),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-gate-execution-summary-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState(
renderState,
{
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
},
);
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-gate-execution-summary-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "waiting",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-gate-execution-summary-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "release gate execution summary DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel(
validation = validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson("{}"),
) {
const missing = Array.isArray(validation?.missing) ? validation.missing : [];
const rows = Array.isArray(validation?.rows)
? validation.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
return {
phase: validation?.phase === "ready" ? "ready" : "blocked",
title: "Release readiness artifact",
statusText: validation?.ready ? "Ready" : "Blocked",
detailText: validation?.ready
? "No blocking reasons"
: (missing.length > 0 ? missing.join(", ") : validation?.error ?? "artifact validation blocked"),
rows,
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel(
validation = validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson("{}"),
) {
return createProjectReleaseReadinessArtifactValidationSummaryViewModel(
validation?.validation ?? validation,
);
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState(
displayViewModel = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDisplayViewModel(),
) {
const rows = Array.isArray(displayViewModel?.rows)
? displayViewModel.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const ready = displayViewModel?.phase === "ready" && displayViewModel?.statusText === "Ready";
const statusText = displayViewModel?.statusText ?? (ready ? "Ready" : "Blocked");
const detailText = displayViewModel?.detailText ?? "No blocking reasons";
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: displayViewModel?.title ?? "Release readiness artifact",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-release-readiness-artifact",
},
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifact",
selectors = {},
} = {}) {
const mountSelector = selectors.mount ?? "[data-workflow-overview-release-readiness-artifact]";
const statusSelector = selectors.status ?? "[data-workflow-overview-release-readiness-artifact-status]";
const rowsSelector = selectors.rows ?? "[data-workflow-overview-release-readiness-artifact-rows]";
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: ["rendered", "statusLine", "rowCount", "rowIds", "dataset"],
};
}
export function createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomReadiness({
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifact",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactState(
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState(),
{
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifact",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview release readiness artifact DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope
?? "workflow-overview-release-readiness-artifact";
statusNode.textContent = renderState?.statusLine ?? "Blocked: No release readiness artifact render state";
rowsNode.replaceChildren();
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactState({
renderState = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactRenderState(),
rowDatasetPrefix = "workflowOverviewReleaseReadinessArtifact",
contract = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewReleaseReadinessArtifactDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactState(renderState, {
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-release-readiness-artifact-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "release readiness artifact DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function createIniPanelShellWorkflowOverviewReadiness({
overviewApi = null,
contract = createIniPanelShellWorkflowOverviewContract(),
} = {}) {
const methodNames = Array.isArray(contract?.methodNames) ? contract.methodNames : [];
const missing = methodNames.filter((methodName) => typeof overviewApi?.[methodName] !== "function");
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
contract,
};
}
export function createIniPanelShellSessionHandoffWorkflowDomReadiness({
rowDatasetPrefix = "handoffWorkflow",
contract = createIniPanelShellSessionHandoffWorkflowDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-session-handoff-workflow-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellSessionHandoffWorkflowState(
renderState = createIniPanelShellSessionHandoffWorkflowRenderState(),
{
rowDatasetPrefix = "handoffWorkflow",
contract = createIniPanelShellSessionHandoffWorkflowDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellSessionHandoffWorkflowDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Shell handoff workflow DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope ?? "workflow";
statusNode.textContent = renderState?.statusLine ?? "Blocked: No workflow render state";
rowsNode.replaceChildren();
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellSessionHandoffWorkflow({
renderState = createIniPanelShellSessionHandoffWorkflowRenderState(),
rowDatasetPrefix = "handoffWorkflow",
contract = createIniPanelShellSessionHandoffWorkflowDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellSessionHandoffWorkflowDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-session-handoff-workflow-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellSessionHandoffWorkflowState(renderState, {
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
return {
apiName: "ini-panel-shell-session-handoff-workflow-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-session-handoff-workflow-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "workflow DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function mountIniPanelShellWorkflowOverviewEmbedding({
overviewApi = null,
contract = createIniPanelShellWorkflowOverviewContract(),
mountOptions = {},
} = {}) {
const readiness = createIniPanelShellWorkflowOverviewReadiness({
overviewApi,
contract,
});
if (!readiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-embedding",
embeddingVersion: 1,
phase: "blocked",
ready: false,
pageHref: contract.pageHref,
contract,
readiness,
renderState: null,
mountResult: null,
error: null,
};
}
try {
const renderState = overviewApi.getWorkflowOverviewRenderState();
const mountResult = overviewApi.mountWorkflowOverview(mountOptions);
return {
apiName: "ini-panel-shell-workflow-overview-embedding",
embeddingVersion: 1,
phase: mountResult?.phase ?? "blocked",
ready: mountResult?.ready === true,
pageHref: contract.pageHref,
contract,
readiness,
renderState,
mountResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-embedding",
embeddingVersion: 1,
phase: "blocked",
ready: false,
pageHref: contract.pageHref,
contract,
readiness,
renderState: null,
mountResult: null,
error: error?.message ?? String(error),
};
}
}
export function createIniPanelShellWorkflowOverviewEmbeddingReport(
embeddingResult = mountIniPanelShellWorkflowOverviewEmbedding(),
contract = createIniPanelShellWorkflowOverviewContract(),
) {
const result = embeddingResult && typeof embeddingResult === "object" ? embeddingResult : {};
const readiness = result.readiness && typeof result.readiness === "object" ? result.readiness : {};
const resultContract = result.contract && typeof result.contract === "object" ? result.contract : contract;
const mountResult = result.mountResult && typeof result.mountResult === "object" ? result.mountResult : {};
const renderResult = mountResult.renderResult && typeof mountResult.renderResult === "object"
? mountResult.renderResult
: {};
const missingMethods = Array.isArray(readiness.missing) ? [...readiness.missing] : [];
const error = result.error ?? mountResult.error ?? null;
const overviewReady = readiness.ready === true;
const embeddingReady = result.ready === true;
const mountPhase = mountResult.phase ?? null;
const mountReady = mountResult.ready === true;
const renderRowCount = Number.isFinite(renderResult.rowCount) ? renderResult.rowCount : 0;
const blockingReasons = [
...missingMethods.map((methodName) => `missing:${methodName}`),
...(embeddingReady ? [] : [`embedding:${result.phase ?? "blocked"}`]),
...(mountPhase && !mountReady ? [`mount:${mountPhase}`] : []),
...(error ? [`error:${error}`] : []),
];
const ready = overviewReady && embeddingReady && mountReady && !error && blockingReasons.length === 0;
const statusLine = ready
? "Ready: No blocking reasons"
: `Blocked: ${blockingReasons.length > 0 ? blockingReasons.join(", ") : "workflow overview embedding unavailable"}`;
return {
apiName: "ini-panel-shell-workflow-overview-embedding-report",
reportVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
overviewReady,
embeddingReady,
mountReady,
statusLine,
pageHref: result.pageHref ?? resultContract.pageHref ?? null,
contract: resultContract,
missingMethods,
mountPhase,
renderRowCount,
error,
blockingReasons,
rows: [
{
id: "overview-api",
label: "Overview API",
value: overviewReady ? "ready" : "blocked",
},
{
id: "missing-methods",
label: "Missing methods",
value: missingMethods.length === 0 ? "none" : missingMethods.join(", "),
},
{
id: "embedding-ready",
label: "Embedding readiness",
value: embeddingReady ? "ready" : "blocked",
},
{
id: "mount-phase",
label: "Mount phase",
value: mountPhase ?? "missing",
},
{
id: "render-row-count",
label: "Render row count",
value: String(renderRowCount),
},
{
id: "error",
label: "Error",
value: error ?? "none",
},
],
};
}
export function createIniPanelShellWorkflowOverviewEmbeddingDisplayViewModel(
report = createIniPanelShellWorkflowOverviewEmbeddingReport(),
) {
const blockingReasons = Array.isArray(report?.blockingReasons) ? report.blockingReasons : [];
const rows = Array.isArray(report?.rows)
? report.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
return {
phase: report?.phase === "ready" ? "ready" : "blocked",
title: "Workflow overview embedding",
statusText: report?.ready ? "Ready" : "Blocked",
detailText: blockingReasons.length === 0 ? "No blocking reasons" : blockingReasons.join(", "),
rows,
};
}
export function createIniPanelShellWorkflowOverviewEmbeddingRenderState(
displayViewModel = createIniPanelShellWorkflowOverviewEmbeddingDisplayViewModel(),
) {
const rows = Array.isArray(displayViewModel?.rows)
? displayViewModel.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const ready = displayViewModel?.phase === "ready" && displayViewModel?.statusText === "Ready";
const statusText = displayViewModel?.statusText ?? (ready ? "Ready" : "Blocked");
const detailText = displayViewModel?.detailText ?? "No blocking reasons";
return {
apiName: "ini-panel-shell-workflow-overview-embedding-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: displayViewModel?.title ?? "Workflow overview embedding",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-embedding",
},
};
}
export function createIniPanelShellWorkflowOverviewEmbeddingDomContract({
rowDatasetPrefix = "workflowOverviewEmbedding",
selectors = {},
} = {}) {
const mountSelector = selectors.mount ?? "[data-workflow-overview-embedding]";
const statusSelector = selectors.status ?? "[data-workflow-overview-embedding-status]";
const rowsSelector = selectors.rows ?? "[data-workflow-overview-embedding-rows]";
return {
apiName: "ini-panel-shell-workflow-overview-embedding-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: ["rendered", "statusLine", "rowCount", "rowIds", "dataset"],
};
}
export function createIniPanelShellWorkflowOverviewEmbeddingDomReadiness({
rowDatasetPrefix = "workflowOverviewEmbedding",
contract = createIniPanelShellWorkflowOverviewEmbeddingDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-embedding-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellWorkflowOverviewEmbeddingState(
renderState = createIniPanelShellWorkflowOverviewEmbeddingRenderState(),
{
rowDatasetPrefix = "workflowOverviewEmbedding",
contract = createIniPanelShellWorkflowOverviewEmbeddingDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewEmbeddingDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview embedding DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope ?? "workflow-overview-embedding";
statusNode.textContent = renderState?.statusLine ?? "Blocked: No workflow overview embedding render state";
rowsNode.replaceChildren();
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellWorkflowOverviewEmbeddingState({
renderState = createIniPanelShellWorkflowOverviewEmbeddingRenderState(),
rowDatasetPrefix = "workflowOverviewEmbedding",
contract = createIniPanelShellWorkflowOverviewEmbeddingDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewEmbeddingDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-embedding-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewEmbeddingState(renderState, {
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
return {
apiName: "ini-panel-shell-workflow-overview-embedding-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-embedding-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "workflow overview embedding DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function createIniPanelShellWorkflowOverviewEmbeddingMountDisplayViewModel(
mountResult = mountIniPanelShellWorkflowOverviewEmbeddingState(),
) {
const domMissing = Array.isArray(mountResult?.domReadiness?.missing)
? mountResult.domReadiness.missing
: [];
const renderResult = mountResult?.renderResult && typeof mountResult.renderResult === "object"
? mountResult.renderResult
: {};
const renderState = mountResult?.renderState && typeof mountResult.renderState === "object"
? mountResult.renderState
: {};
const error = mountResult?.error ?? null;
const ready = mountResult?.ready === true;
const problems = [
...(ready ? [] : [`mount:${mountResult?.phase ?? "blocked"}`]),
...domMissing.map((name) => `dom:${name}`),
...(error ? [`error:${error}`] : []),
];
return {
phase: ready ? "ready" : "blocked",
title: "Workflow overview embedding mount",
statusText: ready ? "Ready" : "Blocked",
detailText: problems.length === 0 ? "No blocking reasons" : problems.join(", "),
rows: [
{
id: "mount-ready",
label: "Mount readiness",
value: ready ? "ready" : "blocked",
},
{
id: "dom-readiness",
label: "DOM readiness",
value: mountResult?.domReadiness?.ready ? "ready" : "blocked",
},
{
id: "missing-dom",
label: "Missing DOM",
value: domMissing.length === 0 ? "none" : domMissing.join(", "),
},
{
id: "render-state",
label: "Render state",
value: renderState.statusLine ?? "missing",
},
{
id: "render-result",
label: "Render result",
value: renderResult.rendered ? "rendered" : "missing",
},
{
id: "render-row-count",
label: "Render row count",
value: Number.isFinite(renderResult.rowCount) ? String(renderResult.rowCount) : "0",
},
{
id: "error",
label: "Error",
value: error ?? "none",
},
],
};
}
export function createIniPanelShellWorkflowOverviewEmbeddingMountRenderState(
displayViewModel = createIniPanelShellWorkflowOverviewEmbeddingMountDisplayViewModel(),
) {
const rows = Array.isArray(displayViewModel?.rows)
? displayViewModel.rows.map(({ id, label, value }) => ({
id,
label,
value: value == null ? "" : String(value),
}))
: [];
const ready = displayViewModel?.phase === "ready" && displayViewModel?.statusText === "Ready";
const statusText = displayViewModel?.statusText ?? (ready ? "Ready" : "Blocked");
const detailText = displayViewModel?.detailText ?? "No blocking reasons";
return {
apiName: "ini-panel-shell-workflow-overview-embedding-mount-render-state",
renderStateVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
title: displayViewModel?.title ?? "Workflow overview embedding mount",
statusText,
detailText,
statusLine: `${statusText}: ${detailText}`,
rows,
dataset: {
handoffPhase: ready ? "ready" : "blocked",
handoffReady: ready ? "true" : "false",
handoffScope: "workflow-overview-embedding-mount",
},
};
}
export function createIniPanelShellWorkflowOverviewEmbeddingMountDomContract({
rowDatasetPrefix = "workflowOverviewEmbeddingMount",
selectors = {},
} = {}) {
const mountSelector = selectors.mount ?? "[data-workflow-overview-embedding-mount]";
const statusSelector = selectors.status ?? "[data-workflow-overview-embedding-mount-status]";
const rowsSelector = selectors.rows ?? "[data-workflow-overview-embedding-mount-rows]";
return {
apiName: "ini-panel-shell-workflow-overview-embedding-mount-dom-contract",
contractVersion: 1,
requiredNodeIds: ["mount", "status", "rows"],
selectors: {
mount: mountSelector,
status: statusSelector,
rows: rowsSelector,
},
mountDatasetKeys: ["handoffPhase", "handoffReady", "handoffScope"],
rowDatasetPrefix,
rowDatasetKeys: {
term: [`${rowDatasetPrefix}Row`, `${rowDatasetPrefix}Status`],
detail: [`${rowDatasetPrefix}Value`, `${rowDatasetPrefix}Status`],
},
renderResultFields: ["rendered", "statusLine", "rowCount", "rowIds", "dataset"],
};
}
export function createIniPanelShellWorkflowOverviewEmbeddingMountDomReadiness({
rowDatasetPrefix = "workflowOverviewEmbeddingMount",
contract = createIniPanelShellWorkflowOverviewEmbeddingMountDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const checks = {
document: Boolean(documentRef?.createElement),
mount: Boolean(mountNode),
status: Boolean(statusNode),
rows: Boolean(rowsNode),
rowDatasetPrefix: Boolean(contract.rowDatasetPrefix),
};
const missing = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([name]) => name);
const ready = missing.length === 0;
return {
apiName: "ini-panel-shell-workflow-overview-embedding-mount-dom-readiness",
readinessVersion: 1,
phase: ready ? "ready" : "blocked",
ready,
missing,
checks,
contract,
};
}
export function renderIniPanelShellWorkflowOverviewEmbeddingMountState(
renderState = createIniPanelShellWorkflowOverviewEmbeddingMountRenderState(),
{
rowDatasetPrefix = "workflowOverviewEmbeddingMount",
contract = createIniPanelShellWorkflowOverviewEmbeddingMountDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {},
) {
const readiness = createIniPanelShellWorkflowOverviewEmbeddingMountDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!readiness.ready) {
throw new Error(
`Workflow overview embedding mount DOM is not ready: ${readiness.missing.join(", ")}`,
);
}
mountNode.dataset.handoffPhase = renderState?.dataset?.handoffPhase ?? "blocked";
mountNode.dataset.handoffReady = renderState?.dataset?.handoffReady ?? "false";
mountNode.dataset.handoffScope = renderState?.dataset?.handoffScope ?? "workflow-overview-embedding-mount";
statusNode.textContent = renderState?.statusLine ?? "Blocked: No workflow overview embedding mount render state";
rowsNode.replaceChildren();
const rows = Array.isArray(renderState?.rows) ? renderState.rows : [];
const effectiveRowDatasetPrefix = contract.rowDatasetPrefix;
for (const row of rows) {
const term = documentRef.createElement("dt");
term.dataset[`${effectiveRowDatasetPrefix}Row`] = row.id;
term.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
term.textContent = row.label;
const detail = documentRef.createElement("dd");
detail.dataset[`${effectiveRowDatasetPrefix}Value`] = row.id;
detail.dataset[`${effectiveRowDatasetPrefix}Status`] = renderState?.ready ? "pass" : "blocked";
detail.textContent = row.value;
rowsNode.append(term, detail);
}
return {
rendered: true,
statusLine: statusNode.textContent,
rowCount: rows.length,
rowIds: rows.map(({ id }) => id),
dataset: {
handoffPhase: mountNode.dataset.handoffPhase,
handoffReady: mountNode.dataset.handoffReady,
handoffScope: mountNode.dataset.handoffScope,
},
};
}
export function mountIniPanelShellWorkflowOverviewEmbeddingMountState({
renderState = createIniPanelShellWorkflowOverviewEmbeddingMountRenderState(),
rowDatasetPrefix = "workflowOverviewEmbeddingMount",
contract = createIniPanelShellWorkflowOverviewEmbeddingMountDomContract({ rowDatasetPrefix }),
documentRef = globalThis.document,
mountNode = documentRef?.querySelector?.(contract.selectors.mount),
statusNode = documentRef?.querySelector?.(contract.selectors.status),
rowsNode = documentRef?.querySelector?.(contract.selectors.rows),
} = {}) {
const domReadiness = createIniPanelShellWorkflowOverviewEmbeddingMountDomReadiness({
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
if (!domReadiness.ready) {
return {
apiName: "ini-panel-shell-workflow-overview-embedding-mount-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${domReadiness.missing.join(", ")}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: null,
};
}
try {
const renderResult = renderIniPanelShellWorkflowOverviewEmbeddingMountState(renderState, {
contract,
documentRef,
mountNode,
statusNode,
rowsNode,
});
return {
apiName: "ini-panel-shell-workflow-overview-embedding-mount-dom-mount",
workflowVersion: 1,
phase: renderState?.phase === "ready" ? "ready" : "blocked",
ready: renderState?.ready === true,
statusLine: renderResult.statusLine,
contract,
domReadiness,
renderState,
renderResult,
error: null,
};
} catch (error) {
return {
apiName: "ini-panel-shell-workflow-overview-embedding-mount-dom-mount",
workflowVersion: 1,
phase: "blocked",
ready: false,
statusLine: `Blocked: ${error?.message ?? "workflow overview embedding mount DOM mount error"}`,
contract,
domReadiness,
renderState,
renderResult: null,
error: error?.message ?? String(error),
};
}
}
export function createIniPanelShellViewModel(entries = getVisibleIniPanelEntries()) {
const shellIntegrationManifest = createIniPanelShellIntegrationManifest(entries);
const shellIntegrationReadiness = createIniPanelShellIntegrationReadiness(shellIntegrationManifest);
const shellIntegrationWorkflowPlan = createIniPanelShellIntegrationWorkflowPlan({
manifest: shellIntegrationManifest,
readiness: shellIntegrationReadiness,
});
const shellSessionHandoffSummary = createIniPanelShellSessionHandoffSummary({
manifest: shellIntegrationManifest,
readiness: shellIntegrationReadiness,
workflowPlan: shellIntegrationWorkflowPlan,
});
const shellSessionHandoffCompatibilityReport = createIniPanelShellSessionHandoffCompatibilityReport(
shellSessionHandoffSummary,
);
const shellSessionHandoffDisplayViewModel = createIniPanelShellSessionHandoffDisplayViewModel(
shellSessionHandoffCompatibilityReport,
);
const shellSessionHandoffSnapshot = createIniPanelShellSessionHandoffSnapshot({
readiness: shellIntegrationReadiness,
summary: shellSessionHandoffSummary,
compatibilityReport: shellSessionHandoffCompatibilityReport,
displayViewModel: shellSessionHandoffDisplayViewModel,
});
const shellSessionHandoffRenderState = createIniPanelShellSessionHandoffRenderState(
shellSessionHandoffSnapshot,
);
const shellSessionHandoffActionPlan = createIniPanelShellSessionHandoffActionPlan({
snapshot: shellSessionHandoffSnapshot,
renderState: shellSessionHandoffRenderState,
});
const shellSessionHandoffChecklist = createIniPanelShellSessionHandoffChecklist({
actionPlan: shellSessionHandoffActionPlan,
renderState: shellSessionHandoffRenderState,
});
const shellSessionHandoffPackage = createIniPanelShellSessionHandoffPackage({
shellIntegrationManifest,
launchApiManifest: shellIntegrationManifest.launchApiManifest,
controlPageApiManifest: shellIntegrationManifest.controlPageApiManifest,
snapshot: shellSessionHandoffSnapshot,
renderState: shellSessionHandoffRenderState,
actionPlan: shellSessionHandoffActionPlan,
checklist: shellSessionHandoffChecklist,
});
const shellSessionHandoffPackageReport = createIniPanelShellSessionHandoffPackageReport(
shellSessionHandoffPackage,
);
const shellSessionHandoffPackageDisplayViewModel = createIniPanelShellSessionHandoffPackageDisplayViewModel(
shellSessionHandoffPackageReport,
);
const shellSessionHandoffPackageRenderState = createIniPanelShellSessionHandoffPackageRenderState(
shellSessionHandoffPackageDisplayViewModel,
);
const shellSessionHandoffPackageMountState = createIniPanelShellSessionHandoffPackageMountState({
handoffPackage: shellSessionHandoffPackage,
packageRenderState: shellSessionHandoffPackageRenderState,
});
const shellSessionHandoffPackageMountDisplayViewModel = createIniPanelShellSessionHandoffPackageMountDisplayViewModel(
shellSessionHandoffPackageMountState,
);
const shellSessionHandoffPackageMountRenderState = createIniPanelShellSessionHandoffPackageMountRenderState(
shellSessionHandoffPackageMountDisplayViewModel,
);
const shellSessionHandoffMountDomContract = createIniPanelShellSessionHandoffMountDomContract();
const shellSessionHandoffReadonlyStatusResult = readIniPanelShellSessionHandoffStatusFromControlPage({
handoffSummary: shellSessionHandoffSummary,
});
const baseShellSessionHandoffWorkflowSummary = createIniPanelShellSessionHandoffWorkflowSummary({
mountWorkflow: {
phase: shellSessionHandoffPackageMountRenderState.phase,
ready: shellSessionHandoffPackageMountRenderState.ready,
statusLine: shellSessionHandoffPackageMountRenderState.statusLine,
},
controlPageMountWorkflow: {
phase: shellSessionHandoffPackageMountState.phase,
ready: shellSessionHandoffPackageMountState.ready,
statusLine: shellSessionHandoffPackageMountState.statusLine,
},
readonlyStatusResult: shellSessionHandoffReadonlyStatusResult,
});
const shellSessionHandoffWorkflowDomContract = createIniPanelShellSessionHandoffWorkflowDomContract();
const shellWorkflowOverviewContract = createIniPanelShellWorkflowOverviewContract();
const shellSessionReadinessWorkflowReport = createIniPanelShellSessionReadinessWorkflowReport({
workflowSummary: baseShellSessionHandoffWorkflowSummary,
});
const shellPersistenceSummary = createMachineSessionPersistenceSummary();
const shellApiSurfaceInventory = createIniPanelShellApiSurfaceInventory({
launchApiManifest: shellIntegrationManifest.launchApiManifest,
controlPageApiManifest: shellIntegrationManifest.controlPageApiManifest,
workflowOverviewContract: shellWorkflowOverviewContract,
sessionReadinessWorkflowReport: shellSessionReadinessWorkflowReport,
persistenceSummary: shellPersistenceSummary,
});
const shellSessionHandoffWorkflowSummary = createIniPanelShellSessionHandoffWorkflowSummary({
mountWorkflow: baseShellSessionHandoffWorkflowSummary.mountWorkflow,
controlPageMountWorkflow: baseShellSessionHandoffWorkflowSummary.controlPageMountWorkflow,
readonlyStatusResult: shellSessionHandoffReadonlyStatusResult,
persistenceSummary: shellPersistenceSummary,
apiSurfaceInventory: shellApiSurfaceInventory,
});
const shellSessionHandoffWorkflowDisplayViewModel = createIniPanelShellSessionHandoffWorkflowDisplayViewModel(
shellSessionHandoffWorkflowSummary,
);
const shellSessionHandoffWorkflowRenderState = createIniPanelShellSessionHandoffWorkflowRenderState(
shellSessionHandoffWorkflowDisplayViewModel,
);
return {
pages: entries.map(({ id, href, title }) => ({
id,
href,
title,
})),
launcherLinks: createIniPanelLauncherLinkViewModel(entries),
shellIntegrationSchema: createIniPanelShellIntegrationSchema(),
shellIntegrationManifest,
shellIntegrationReadiness,
shellIntegrationWorkflowPlan,
shellSessionHandoffSummarySchema: createIniPanelShellSessionHandoffSummarySchema(),
shellSessionHandoffSummary,
shellSessionHandoffCompatibilityReport,
shellSessionHandoffDisplayViewModel,
shellSessionHandoffSnapshot,
shellSessionHandoffRenderState,
shellSessionHandoffActionPlan,
shellSessionHandoffChecklist,
shellSessionHandoffPackage,
shellSessionHandoffPackageSchema: createIniPanelShellSessionHandoffPackageSchema(),
shellSessionHandoffPackageReport,
shellSessionHandoffPackageDisplayViewModel,
shellSessionHandoffPackageRenderState,
shellSessionHandoffPackageMountState,
shellSessionHandoffPackageMountDisplayViewModel,
shellSessionHandoffPackageMountRenderState,
shellSessionHandoffMountDomContract,
shellSessionHandoffWorkflowSummary,
shellSessionReadinessWorkflowReport,
shellSessionHandoffWorkflowDisplayViewModel,
shellSessionHandoffWorkflowRenderState,
shellSessionHandoffWorkflowDomContract,
shellWorkflowOverviewContract,
shellPersistenceSummary,
shellApiSurfaceInventory,
launchApiSchema: createIniPanelLaunchApiSchema(),
launchApiManifest: createIniPanelLaunchApiManifest(entries),
isSupportedShellIntegrationManifest: isSupportedIniPanelShellIntegrationManifest,
createShellIntegrationReadiness: createIniPanelShellIntegrationReadiness,
createShellIntegrationWorkflowPlan: createIniPanelShellIntegrationWorkflowPlan,
isSupportedShellSessionHandoffSummary: isSupportedIniPanelShellSessionHandoffSummary,
createShellSessionHandoffSummarySchema: createIniPanelShellSessionHandoffSummarySchema,
createShellSessionHandoffSummary: createIniPanelShellSessionHandoffSummary,
createShellSessionHandoffCompatibilityReport: createIniPanelShellSessionHandoffCompatibilityReport,
createShellSessionHandoffDisplayViewModel: createIniPanelShellSessionHandoffDisplayViewModel,
createShellSessionHandoffSnapshot: createIniPanelShellSessionHandoffSnapshot,
createShellSessionHandoffRenderState: createIniPanelShellSessionHandoffRenderState,
createShellSessionHandoffActionPlan: createIniPanelShellSessionHandoffActionPlan,
createShellSessionHandoffChecklist: createIniPanelShellSessionHandoffChecklist,
createShellSessionHandoffPackage: createIniPanelShellSessionHandoffPackage,
createShellSessionHandoffPackageSchema: createIniPanelShellSessionHandoffPackageSchema,
createShellSessionHandoffPackageReport: createIniPanelShellSessionHandoffPackageReport,
createShellSessionHandoffPackageDisplayViewModel: createIniPanelShellSessionHandoffPackageDisplayViewModel,
createShellSessionHandoffPackageRenderState: createIniPanelShellSessionHandoffPackageRenderState,
createShellSessionHandoffPackageMountState: createIniPanelShellSessionHandoffPackageMountState,
createShellSessionHandoffPackageMountDisplayViewModel: createIniPanelShellSessionHandoffPackageMountDisplayViewModel,
createShellSessionHandoffPackageMountRenderState: createIniPanelShellSessionHandoffPackageMountRenderState,
createShellSessionHandoffMountDomContract: createIniPanelShellSessionHandoffMountDomContract,
createShellSessionHandoffMountDomReadiness: createIniPanelShellSessionHandoffMountDomReadiness,
renderShellSessionHandoffMountState: renderIniPanelShellSessionHandoffMountState,
mountShellSessionHandoff: mountIniPanelShellSessionHandoff,
mountShellSessionHandoffFromControlPage: mountIniPanelShellSessionHandoffFromControlPage,
readShellSessionHandoffStatusFromControlPage: readIniPanelShellSessionHandoffStatusFromControlPage,
createShellSessionHandoffWorkflowSummary: createIniPanelShellSessionHandoffWorkflowSummary,
createMachineSessionPersistenceSummary,
createShellSessionReadinessWorkflowReport: createIniPanelShellSessionReadinessWorkflowReport,
createShellApiSurfaceInventory: createIniPanelShellApiSurfaceInventory,
createShellSessionHandoffWorkflowDisplayViewModel: createIniPanelShellSessionHandoffWorkflowDisplayViewModel,
createShellSessionHandoffWorkflowRenderState: createIniPanelShellSessionHandoffWorkflowRenderState,
createShellSessionHandoffWorkflowDomContract: createIniPanelShellSessionHandoffWorkflowDomContract,
createShellSessionHandoffWorkflowDomReadiness: createIniPanelShellSessionHandoffWorkflowDomReadiness,
renderShellSessionHandoffWorkflowState: renderIniPanelShellSessionHandoffWorkflowState,
mountShellSessionHandoffWorkflow: mountIniPanelShellSessionHandoffWorkflow,
createWorkflowOverviewContract: createIniPanelShellWorkflowOverviewContract,
createWorkflowOverviewReadiness: createIniPanelShellWorkflowOverviewReadiness,
runWorkflowOverviewReleaseReadinessArtifactJsonWorkflow:
runIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflow,
createWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowSummaryViewModel,
createWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowActionPlan,
createWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowRenderState,
createWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomContract,
createWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowDomReadiness,
renderWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState:
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
mountWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState:
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactJsonWorkflowState,
createWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationSummaryViewModel,
createWorkflowOverviewReleaseReadinessArtifactValidationActionPlan:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlan,
createWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanRenderState,
createWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomContract,
createWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanDomReadiness,
renderWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState:
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
mountWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState:
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactValidationActionPlanState,
createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel,
createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowActionPlan,
createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowRenderState,
createWorkflowOverviewPromotionFamilyRowsRenderState:
createIniPanelShellWorkflowOverviewPromotionFamilyRowsRenderState,
createWorkflowOverviewPromotionFamilySourceFilterViewModel:
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterViewModel,
createWorkflowOverviewPromotionFamilySourceFilterDomContract:
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomContract,
createWorkflowOverviewPromotionFamilySourceFilterDomReadiness:
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterDomReadiness,
createWorkflowOverviewPromotionFamilySourceFilterSelectionActionPlan:
createIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionActionPlan,
handleWorkflowOverviewPromotionFamilySourceFilterSelectionChange:
handleIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionChange,
bindWorkflowOverviewPromotionFamilySourceFilterSelectionControls:
bindIniPanelShellWorkflowOverviewPromotionFamilySourceFilterSelectionControls,
renderWorkflowOverviewPromotionFamilySourceFilterState:
renderIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState,
mountWorkflowOverviewPromotionFamilySourceFilterState:
mountIniPanelShellWorkflowOverviewPromotionFamilySourceFilterState,
createWorkflowOverviewPromotionFamilyRowsDomContract:
createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomContract,
createWorkflowOverviewPromotionFamilyRowsDomReadiness:
createIniPanelShellWorkflowOverviewPromotionFamilyRowsDomReadiness,
renderWorkflowOverviewPromotionFamilyRowsState:
renderIniPanelShellWorkflowOverviewPromotionFamilyRowsState,
mountWorkflowOverviewPromotionFamilyRowsState:
mountIniPanelShellWorkflowOverviewPromotionFamilyRowsState,
createWorkflowOverviewPromotionCandidateDrilldownViewModel:
createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownViewModel,
createWorkflowOverviewPromotionCandidateDrilldownRenderState:
createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownRenderState,
createWorkflowOverviewPromotionCandidateDrilldownDomContract:
createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomContract,
createWorkflowOverviewPromotionCandidateDrilldownDomReadiness:
createIniPanelShellWorkflowOverviewPromotionCandidateDrilldownDomReadiness,
renderWorkflowOverviewPromotionCandidateDrilldownState:
renderIniPanelShellWorkflowOverviewPromotionCandidateDrilldownState,
mountWorkflowOverviewPromotionCandidateDrilldownState:
mountIniPanelShellWorkflowOverviewPromotionCandidateDrilldownState,
createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomContract,
createWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowDomReadiness,
renderWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState:
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
mountWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState:
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowState,
createWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryViewModel,
createWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlGateExecutionSummaryViewModel,
createWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryRenderState,
createWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomContract,
createWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness:
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryDomReadiness,
renderWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState:
renderIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
mountWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState:
mountIniPanelShellWorkflowOverviewReleaseReadinessArtifactGateExecutionSummaryState,
loadWorkflowOverviewReleaseReadinessArtifactUrl:
loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl,
mountWorkflowOverviewEmbedding: mountIniPanelShellWorkflowOverviewEmbedding,
createWorkflowOverviewEmbeddingReport: createIniPanelShellWorkflowOverviewEmbeddingReport,
createWorkflowOverviewEmbeddingDisplayViewModel: createIniPanelShellWorkflowOverviewEmbeddingDisplayViewModel,
createWorkflowOverviewEmbeddingRenderState: createIniPanelShellWorkflowOverviewEmbeddingRenderState,
createWorkflowOverviewEmbeddingDomContract: createIniPanelShellWorkflowOverviewEmbeddingDomContract,
createWorkflowOverviewEmbeddingDomReadiness: createIniPanelShellWorkflowOverviewEmbeddingDomReadiness,
renderWorkflowOverviewEmbeddingState: renderIniPanelShellWorkflowOverviewEmbeddingState,
mountWorkflowOverviewEmbeddingState: mountIniPanelShellWorkflowOverviewEmbeddingState,
createWorkflowOverviewEmbeddingMountDisplayViewModel:
createIniPanelShellWorkflowOverviewEmbeddingMountDisplayViewModel,
createWorkflowOverviewEmbeddingMountRenderState:
createIniPanelShellWorkflowOverviewEmbeddingMountRenderState,
createWorkflowOverviewEmbeddingMountDomContract:
createIniPanelShellWorkflowOverviewEmbeddingMountDomContract,
createWorkflowOverviewEmbeddingMountDomReadiness:
createIniPanelShellWorkflowOverviewEmbeddingMountDomReadiness,
renderWorkflowOverviewEmbeddingMountState:
renderIniPanelShellWorkflowOverviewEmbeddingMountState,
mountWorkflowOverviewEmbeddingMountState:
mountIniPanelShellWorkflowOverviewEmbeddingMountState,
isSupportedShellSessionHandoffPackage: isSupportedIniPanelShellSessionHandoffPackage,
controlPage: {
browserApiSchema: createControlPageBrowserApiSchema(),
browserApiManifest: createControlPageBrowserApiManifest(),
browserApiMethods: createControlPageBrowserApiMethods(),
contract: createIniPanelShellControlPageContract(),
createController: createMachineSessionControlPageController,
isSupportedBrowserApiManifest: isSupportedIniPanelControlPageApiManifest,
loadSessionState: loadMachineSessionForControlPageWorkflow,
readonlyStatusApiManifest: createMachineSessionReadonlyStatusApiManifest(),
readStatus: readMachineSessionReadonlyStatus,
refresh: refreshMachineSessionControlPage,
renderView: renderMachineSessionControlView,
},
};
}