fix: add backend-core publish preflight

This commit is contained in:
Codex
2026-05-21 09:39:25 +00:00
parent 1a722412cd
commit 43ce0ee051
6 changed files with 449 additions and 63 deletions
+46 -2
View File
@@ -87,7 +87,7 @@ interface DispatchResult {
raw: unknown;
}
type PublishPreflightFailureClassification = "auth-missing" | "remote-proxy-missing" | "provider-unreachable" | "local-docker-required";
type PublishPreflightFailureClassification = "auth-missing" | "remote-proxy-missing" | "provider-unreachable" | "local-docker-required" | "registry-not-installed" | "registry-unhealthy" | "remote-command-timeout" | "ssh-helper-command-shape-incompatible";
type PublishPreflightControlChannel = "backend-core" | "database" | "provider" | "registry";
type PublishPreflightDetailedChannel = "backend-core-api" | "provider-dispatch" | "provider-host-ssh" | "database" | "artifact-registry";
@@ -120,6 +120,8 @@ interface PublishPreflight {
channels: PublishPreflightChannelProbe[];
registry: unknown;
controlPlane: Record<string, unknown>;
recommendedAction: string;
remoteCommandShape: string;
next: string[];
boundary: string;
}
@@ -435,10 +437,36 @@ function classifyPublishPreflightFailure(
if (kind !== "local-docker" && !responseOk(overview)) return "remote-proxy-missing";
if (!sshProbe.ok) return "provider-unreachable";
const registryRecord = asRecord(registry);
if (registryRecord?.ok === false) return "provider-unreachable";
if (registryRecord?.failureClassification === "local-docker-required") return "local-docker-required";
if (registryRecord?.failureClassification === "provider-ssh-command-missing") return "provider-unreachable";
if (registryRecord?.failureClassification === "ssh-helper-command-shape-incompatible") return "ssh-helper-command-shape-incompatible";
if (registryRecord?.failureClassification === "remote-command-timeout") return "remote-command-timeout";
if (registryRecord?.failureClassification === "registry-not-installed") return "registry-not-installed";
if (registryRecord?.failureClassification === "registry-unhealthy") return "registry-unhealthy";
if (registryRecord?.ok === false) return kind === "local-docker" ? "provider-unreachable" : "registry-unhealthy";
return null;
}
function recommendedPublishPreflightAction(
failureClassification: PublishPreflightFailureClassification | null,
registry: unknown,
missingControlChannels: PublishPreflightControlChannel[],
): string {
if (failureClassification === null && missingControlChannels.length === 0) return "none";
const registryRecommendedAction = asString(asRecord(registry)?.recommendedAction);
if (registryRecommendedAction.length > 0 && registryRecommendedAction !== "none") return registryRecommendedAction;
if (failureClassification === "local-docker-required") return "rerun this read-only preflight through --main-server-ip <host> or from a main-server CLI with backend-core available";
if (failureClassification === "auth-missing") return "restore frontend control-plane authentication before rerunning the dry-run preflight";
if (failureClassification === "remote-proxy-missing") return "restore frontend to backend-core proxy reachability before rerunning the dry-run preflight";
if (failureClassification === "provider-unreachable") return "restore D601 provider-gateway host.ssh reachability before rerunning the dry-run preflight";
if (failureClassification === "ssh-helper-command-shape-incompatible") return "upgrade or shorten the host.ssh readonly command shape before rerunning the dry-run preflight";
if (failureClassification === "remote-command-timeout") return "rerun artifact-registry health and inspect D601 host.ssh latency if the timeout repeats";
if (failureClassification === "registry-not-installed") return "install the D601 artifact registry through the controlled artifact-registry install path, then rerun health";
if (failureClassification === "registry-unhealthy") return "restore the D601 artifact registry service/container/API until artifact-registry health passes";
if (missingControlChannels.includes("registry")) return "restore or install the D601 artifact registry until artifact-registry health passes";
return `restore missing control channel(s): ${missingControlChannels.join(", ") || "unknown"}`;
}
function publishPreflightControlPlane(
transport: PublishPreflightTransport,
failureClassification: PublishPreflightFailureClassification | null,
@@ -462,6 +490,13 @@ function publishPreflightControlPlane(
};
}
function publishPreflightFailedScopes(preflight: PublishPreflight): string[] {
if (preflight.ok) return [];
const registryScopes = asRecord(preflight.registry)?.failedScopes;
if (Array.isArray(registryScopes)) return registryScopes.map(String);
return preflight.missingChannels;
}
function dispatchPreflightFailure(command: string, result: DispatchResult): DispatchResult {
return {
ok: false,
@@ -1430,6 +1465,7 @@ async function publishUserServicePreflight(
const missingControlChannels = controlChannels.filter((item) => !item.ok).map((item) => item.channel);
const ready = missingChannels.length === 0;
const failureClassification = ready ? null : classifyPublishPreflightFailure(transport, overview, sshProbe, registry);
const recommendedAction = recommendedPublishPreflightAction(failureClassification, registry, missingControlChannels);
return {
ok: ready,
runnerDisposition: ready ? "ready" : "infra-blocked",
@@ -1444,6 +1480,8 @@ async function publishUserServicePreflight(
channels,
registry,
controlPlane: publishPreflightControlPlane(transport, failureClassification),
recommendedAction,
remoteCommandShape: registryProbe.remoteCommandShape,
next: ready
? [
`bun scripts/cli.ts ci publish-user-service --service ${options.serviceId} --commit ${options.commit} --wait-ms 1200000`,
@@ -1634,6 +1672,9 @@ async function publishUserServiceArtifact(config: UniDeskConfig, options: CiPubl
controlChannels: preflight.controlChannels,
channels: preflight.channels,
failureClassification: preflight.failureClassification,
failedScopes: publishPreflightFailedScopes(preflight),
recommendedAction: preflight.recommendedAction,
remoteCommandShape: preflight.remoteCommandShape,
controlPlane: preflight.controlPlane,
registry: preflight.registry,
sourceHostPath: options.sourceHostPath,
@@ -1761,6 +1802,9 @@ export async function runCiPublishUserServiceDryRunPreflight(
controlChannels: preflight.controlChannels,
channels: preflight.channels,
failureClassification: preflight.failureClassification,
failedScopes: publishPreflightFailedScopes(preflight),
recommendedAction: preflight.recommendedAction,
remoteCommandShape: preflight.remoteCommandShape,
controlPlane: preflight.controlPlane,
registry: preflight.registry,
sourceHostPath: options.sourceHostPath,