fix: report current M4 M5 runtime blockers
This commit is contained in:
@@ -9,6 +9,12 @@ import {
|
||||
AGENT_SKILLS_SERVICE_ID,
|
||||
AGENT_WORKER_SERVICE_ID
|
||||
} from "../../internal/agent/index.mjs";
|
||||
import {
|
||||
RUNTIME_DURABLE_ADAPTER_MISSING,
|
||||
RUNTIME_DURABILITY_REQUIRED_EVIDENCE,
|
||||
RUNTIME_STORE_KIND_POSTGRES
|
||||
} from "../../internal/db/runtime-store.mjs";
|
||||
import { CLOUD_CORE_MIGRATION_ID } from "../../internal/db/schema.mjs";
|
||||
import { DEV_ENDPOINT, DEV_FRONTEND_ENDPOINT, ENVIRONMENT_DEV } from "../../internal/protocol/index.mjs";
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
@@ -20,6 +26,183 @@ export const d601K3sReadonlyCommand =
|
||||
export const workerServerDryRunCommand =
|
||||
"KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-dev create -f - --dry-run=server -o json";
|
||||
|
||||
export function isDbLiveReady(body) {
|
||||
const db = body?.db;
|
||||
return Boolean(db?.ready && db?.connected && db?.liveConnected !== false && db?.liveDbEvidence);
|
||||
}
|
||||
|
||||
export function isDbLiveBlocked(body) {
|
||||
const db = body?.db;
|
||||
if (!db || typeof db !== "object") {
|
||||
return false;
|
||||
}
|
||||
if (isDbLiveReady(body)) {
|
||||
return false;
|
||||
}
|
||||
return db.connected === false ||
|
||||
db.ready === false ||
|
||||
db.liveConnected === false ||
|
||||
db.liveDbEvidence === false ||
|
||||
["blocked", "degraded", "failed"].includes(db.status);
|
||||
}
|
||||
|
||||
export function summarizeDbBlocker(body) {
|
||||
const db = body?.db ?? {};
|
||||
const missing = Array.isArray(db.missingEnv) && db.missingEnv.length > 0
|
||||
? ` missing ${db.missingEnv.join(", ")}`
|
||||
: "";
|
||||
return `cloud-api /health/live reports DB ${db.status ?? "not ready"}; connected=${db.connected ?? "unknown"}; ready=${db.ready ?? "unknown"}; liveDbEvidence=${db.liveDbEvidence ?? "unknown"}.${missing}`;
|
||||
}
|
||||
|
||||
export function runtimeDurabilityFromHealth(body) {
|
||||
const runtime = body?.runtime ?? {};
|
||||
const durability = body?.readiness?.durability ?? {};
|
||||
const migration = runtime.migration ?? {};
|
||||
const migrationGate = runtime.gates?.migration ?? durability.gates?.migration ?? {};
|
||||
const blocker = runtime.blocker ??
|
||||
durability.blocker ??
|
||||
(Array.isArray(body?.blockerCodes)
|
||||
? body.blockerCodes.find((code) => String(code).startsWith("runtime_durable_adapter_"))
|
||||
: null) ??
|
||||
RUNTIME_DURABLE_ADAPTER_MISSING;
|
||||
const durableRequested = Boolean(
|
||||
runtime.durableRequested ||
|
||||
durability.durableRequested ||
|
||||
runtime.adapter === RUNTIME_STORE_KIND_POSTGRES ||
|
||||
durability.adapter === RUNTIME_STORE_KIND_POSTGRES
|
||||
);
|
||||
const ready = Boolean(
|
||||
runtime.durable === true &&
|
||||
runtime.ready === true &&
|
||||
runtime.liveRuntimeEvidence === true &&
|
||||
durability.ready !== false
|
||||
);
|
||||
|
||||
return {
|
||||
adapter: runtime.adapter ?? durability.adapter ?? "unknown",
|
||||
durable: Boolean(runtime.durable),
|
||||
durableRequested,
|
||||
ready,
|
||||
runtimeStatus: runtime.status ?? durability.runtimeStatus ?? "unknown",
|
||||
blocker,
|
||||
blockedLayer: runtime.durabilityContract?.blockedLayer ?? durability.blockedLayer ?? null,
|
||||
requiredEvidence: runtime.durabilityContract?.requiredEvidence ??
|
||||
durability.requiredEvidence ??
|
||||
RUNTIME_DURABILITY_REQUIRED_EVIDENCE,
|
||||
migration: {
|
||||
checked: migration.checked ?? migrationGate.checked ?? false,
|
||||
ready: migration.ready ?? migrationGate.ready ?? false,
|
||||
missing: migration.missing ?? (migration.ready === false ? true : null),
|
||||
requiredMigrationId: migration.requiredMigrationId ?? CLOUD_CORE_MIGRATION_ID,
|
||||
appliedMigrationId: migration.appliedMigrationId ?? null
|
||||
},
|
||||
queryAttempted: Boolean(runtime.connection?.queryAttempted ?? durability.queryAttempted),
|
||||
queryResult: runtime.connection?.queryResult ?? durability.queryResult ?? "unknown"
|
||||
};
|
||||
}
|
||||
|
||||
export function isRuntimeDurableAdapterBlocked(body) {
|
||||
const runtime = runtimeDurabilityFromHealth(body);
|
||||
if (!runtime.durableRequested) {
|
||||
return false;
|
||||
}
|
||||
return !runtime.ready ||
|
||||
["blocked", "degraded", "failed"].includes(runtime.runtimeStatus) ||
|
||||
String(runtime.blocker).startsWith("runtime_durable_adapter_");
|
||||
}
|
||||
|
||||
export function summarizeRuntimeDurableBlocker(body) {
|
||||
const runtime = runtimeDurabilityFromHealth(body);
|
||||
const migration = runtime.migration;
|
||||
return `cloud-api durable runtime adapter is blocked: ${runtime.blocker}; adapter=${runtime.adapter}; durable=${runtime.durable}; ready=${runtime.ready}; migration=${migration.requiredMigrationId} checked=${migration.checked} ready=${migration.ready} missing=${migration.missing ?? "unknown"}; queryResult=${runtime.queryResult}.`;
|
||||
}
|
||||
|
||||
export function publicDbLiveSummary(body) {
|
||||
const db = body?.db ?? null;
|
||||
if (!db || typeof db !== "object") {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
status: db.status ?? null,
|
||||
connected: db.connected ?? null,
|
||||
liveConnected: db.liveConnected ?? null,
|
||||
ready: db.ready ?? null,
|
||||
configReady: db.configReady ?? null,
|
||||
connectionChecked: db.connectionChecked ?? null,
|
||||
connectionAttempted: db.connectionAttempted ?? null,
|
||||
connectionResult: db.connectionResult ?? null,
|
||||
endpointSource: db.endpointSource ?? db.connection?.endpointSource ?? null,
|
||||
liveDbEvidence: db.liveDbEvidence ?? null,
|
||||
evidence: db.evidence ?? null
|
||||
};
|
||||
}
|
||||
|
||||
export function publicRuntimeDurabilitySummary(body) {
|
||||
if (!body?.runtime && !body?.readiness?.durability) {
|
||||
return null;
|
||||
}
|
||||
const runtime = runtimeDurabilityFromHealth(body);
|
||||
return {
|
||||
adapter: runtime.adapter,
|
||||
durable: runtime.durable,
|
||||
durableRequested: runtime.durableRequested,
|
||||
ready: runtime.ready,
|
||||
status: runtime.runtimeStatus,
|
||||
blocker: runtime.blocker,
|
||||
blockedLayer: runtime.blockedLayer,
|
||||
requiredEvidence: runtime.requiredEvidence,
|
||||
liveRuntimeEvidence: Boolean(runtime.ready),
|
||||
migration: runtime.migration,
|
||||
queryAttempted: runtime.queryAttempted,
|
||||
queryResult: runtime.queryResult
|
||||
};
|
||||
}
|
||||
|
||||
export function classifyCloudApiLiveReadiness(body) {
|
||||
if (isDbLiveBlocked(body)) {
|
||||
return {
|
||||
blocked: true,
|
||||
blockerType: "runtime_blocker",
|
||||
blockerScope: "db-live",
|
||||
sourceIssue: "pikasTech/HWLAB#49",
|
||||
blockedClassification: "DB live",
|
||||
blockerSummary: summarizeDbBlocker(body),
|
||||
summary: "Blocked at DB live readiness before scheduling a DEV agent task.",
|
||||
evidenceSuffix: "db-blocked",
|
||||
dbLiveReady: false,
|
||||
runtimeDurableReady: false
|
||||
};
|
||||
}
|
||||
|
||||
if (isRuntimeDurableAdapterBlocked(body)) {
|
||||
const runtime = runtimeDurabilityFromHealth(body);
|
||||
return {
|
||||
blocked: true,
|
||||
blockerType: "runtime_blocker",
|
||||
blockerScope: "runtime-durable-adapter",
|
||||
sourceIssue: "pikasTech/HWLAB#164",
|
||||
blockedClassification: runtime.blocker,
|
||||
blockerSummary: summarizeRuntimeDurableBlocker(body),
|
||||
summary: "Blocked at runtime durable adapter readiness before scheduling a DEV agent task.",
|
||||
evidenceSuffix: `runtime-durable-adapter-blocked:${runtime.blocker}`,
|
||||
dbLiveReady: isDbLiveReady(body),
|
||||
runtimeDurableReady: false
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
blocked: false,
|
||||
blockerType: null,
|
||||
blockerScope: null,
|
||||
blockedClassification: "none",
|
||||
blockerSummary: "",
|
||||
summary: "Live DEV preflight observed DB live and durable runtime adapter readiness.",
|
||||
evidenceSuffix: null,
|
||||
dbLiveReady: isDbLiveReady(body),
|
||||
runtimeDurableReady: true
|
||||
};
|
||||
}
|
||||
|
||||
export function requestJson(urlString, { method = "GET", headers = {}, body, timeoutMs = 5000 } = {}) {
|
||||
const url = new URL(urlString);
|
||||
const client = url.protocol === "https:" ? httpsRequest : httpRequest;
|
||||
@@ -348,12 +531,9 @@ export async function collectPublicEntrypoints() {
|
||||
serviceId: apiLive.body?.serviceId ?? null,
|
||||
environment: apiLive.body?.environment ?? null,
|
||||
status: apiLive.body?.status ?? null,
|
||||
db: apiLive.body?.db ? {
|
||||
status: apiLive.body.db.status ?? null,
|
||||
connected: apiLive.body.db.connected ?? null,
|
||||
ready: apiLive.body.db.ready ?? null,
|
||||
evidence: apiLive.body.db.evidence ?? null
|
||||
} : null,
|
||||
db: publicDbLiveSummary(apiLive.body),
|
||||
runtime: publicRuntimeDurabilitySummary(apiLive.body),
|
||||
blockerCodes: Array.isArray(apiLive.body?.blockerCodes) ? apiLive.body.blockerCodes : [],
|
||||
error: apiLive.error ?? null
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user