Files
pikasTech-unidesk/scripts/microservice-health-output-contract-test.ts
T
2026-05-23 07:26:05 +00:00

160 lines
7.6 KiB
TypeScript

import { summarizeMicroserviceHealthResponse } from "./src/microservices";
import { summarizeRemoteMicroserviceResponse } from "./src/remote";
type JsonRecord = Record<string, unknown>;
function assertCondition(condition: unknown, message: string, detail: JsonRecord = {}): void {
if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
}
function asRecord(value: unknown): JsonRecord {
assertCondition(typeof value === "object" && value !== null && !Array.isArray(value), "expected JSON object", { value });
return value as JsonRecord;
}
function manyIds(prefix: string, count: number): string[] {
return Array.from({ length: count }, (_, index) => `${prefix}-${String(index + 1).padStart(3, "0")}`);
}
function longText(prefix: string, count: number): string {
return Array.from({ length: count }, (_, index) => `${prefix} diagnostic row ${index + 1} with queue detail and commander-noise payload`).join("\n");
}
function largeCodeQueueHealth(): JsonRecord {
return {
ok: true,
status: 200,
body: {
ok: true,
service: "code-queue",
instanceId: "D601-code-queue-scheduler",
role: "scheduler",
deploy: {
commit: "abcdef1234567890",
requestedCommit: "abcdef1234567890",
},
databaseReady: true,
schedulerEnabled: true,
queue: {
total: 640,
counts: {
running: 3,
judging: 2,
queued: 41,
retry_wait: 4,
succeeded: 560,
failed: 30,
},
queues: manyIds("queue", 90).map((id) => ({
id,
name: id,
total: 12,
counts: { queued: 5, succeeded: 7 },
diagnostics: longText(id, 18),
})),
queueCount: 90,
activeRunSlotCount: 5,
activeTaskIds: manyIds("active-task", 12),
activeTaskId: "active-task-001",
activeQueueIds: manyIds("active-queue", 12),
processingQueueIds: manyIds("processing-queue", 8),
processing: true,
orphanedActiveTaskCount: 0,
unreadTerminal: 7,
defaultQueueId: "default",
defaultModel: "gpt-5.5",
defaultReasoningEffort: "xhigh",
maxActiveQueues: 0,
schedulerHeartbeatStaleMs: 120000,
},
executionDiagnostics: {
state: "split-brain",
degraded: true,
splitBrain: true,
splitBrainLive: true,
effectiveLiveness: "live",
recommendedAction: "continue-supervision",
executionStateSource: "postgres-control-plane",
controlPlane: "D601-code-queue-scheduler",
databaseActiveTaskCount: 12,
schedulerActiveRunSlotCount: 5,
activeHeartbeatCount: 12,
activeHeartbeatTaskIds: manyIds("active-heartbeat", 12),
heartbeatFreshTaskIds: manyIds("fresh-heartbeat", 12),
heartbeatExpiredTaskIds: [],
heartbeatMissingTaskIds: [],
staleRecoveryCandidateTaskIds: [],
heartbeatRiskTaskIds: [],
traceGapTaskIds: manyIds("trace-gap", 15),
lastSchedulerHeartbeatAt: "2026-05-22T00:00:12.000Z",
lastObservedAgentEventAt: "2026-05-22T00:00:11.000Z",
lastPersistedTraceAt: "2026-05-22T00:00:10.000Z",
reasons: Array.from({ length: 12 }, (_, index) => longText(`reason-${index + 1}`, 8)),
},
modelProviderConfig: {
source: "fixture",
largeNoise: longText("model-provider", 200),
},
},
};
}
const fixture = largeCodeQueueHealth();
const compact = asRecord(summarizeMicroserviceHealthResponse(fixture, ["health", "code-queue"], "code-queue"));
const raw = summarizeMicroserviceHealthResponse(fixture, ["health", "code-queue", "--raw"], "code-queue");
const full = summarizeMicroserviceHealthResponse(fixture, ["health", "code-queue", "--full"], "code-queue");
const remoteCompact = asRecord(summarizeRemoteMicroserviceResponse("health", "code-queue", fixture, ["microservice", "health", "code-queue"]));
const remoteRaw = summarizeRemoteMicroserviceResponse("health", "code-queue", fixture, ["microservice", "health", "code-queue", "--raw"]);
const unhealthyWrapper = asRecord(summarizeMicroserviceHealthResponse({
ok: false,
status: 503,
body: {
ok: false,
status: "unhealthy",
serviceId: "code-queue",
reason: "health body ok=false",
upstream: {
status: 503,
contentType: "application/json",
body: fixture.body,
},
},
}, ["health", "code-queue"], "code-queue"));
const compactBody = JSON.stringify(compact);
const rawBody = JSON.stringify(fixture);
const queue = asRecord(compact.queue);
const heartbeat = asRecord(compact.heartbeat);
const liveness = asRecord(compact.liveness);
const outputPolicy = asRecord(compact.outputPolicy);
const unhealthyQueue = asRecord(unhealthyWrapper.queue);
const unhealthyLiveness = asRecord(unhealthyWrapper.liveness);
assertCondition(compactBody.length < rawBody.length * 0.25, "default code-queue health output should be materially compact", { compactChars: compactBody.length, rawChars: rawBody.length });
assertCondition(compactBody.length < 12000, "default code-queue health output should stay commander-safe", { compactChars: compactBody.length });
assertCondition(!("body" in compact), "compact health must not retain the raw body", compact);
assertCondition(!("queues" in queue), "compact queue summary must not include full queue dumps", queue);
assertCondition(compact.ok === true && compact.status === 200 && compact.serviceId === "code-queue", "compact health keeps ok/status/service identity", compact);
assertCondition(queue.runningCount === 5 && queue.queueCount === 90, "compact queue keeps running count and queue count", queue);
assertCondition(heartbeat.heartbeatFreshTaskCount === 12 && heartbeat.heartbeatRiskTaskCount === 0, "compact heartbeat keeps freshness and risk counts", heartbeat);
assertCondition(liveness.effectiveLiveness === "live" && liveness.splitBrainLive === true, "compact liveness keeps split-brain live interpretation", liveness);
assertCondition(String(liveness.interpretation).includes("continue supervision"), "compact liveness includes commander interpretation", liveness);
assertCondition(typeof outputPolicy.rawCommand === "string" && String(outputPolicy.rawCommand).includes("--raw"), "compact output exposes raw drill-down command", outputPolicy);
assertCondition(raw === fixture && full === fixture, "--raw/--full must preserve full health access", { rawSame: raw === fixture, fullSame: full === fixture });
assertCondition(!("body" in remoteCompact) && asRecord(remoteCompact.queue).runningCount === 5, "remote frontend health must reuse compact code-queue summary by default", remoteCompact);
assertCondition(remoteRaw === fixture, "remote frontend health --raw must preserve full diagnostics", { remoteRawSame: remoteRaw === fixture });
assertCondition(unhealthyWrapper.ok === false && unhealthyWrapper.reason === "health body ok=false", "unhealthy wrapper keeps probe failure", unhealthyWrapper);
assertCondition(unhealthyQueue.runningCount === 5 && unhealthyLiveness.effectiveLiveness === "live", "unhealthy wrapper still surfaces upstream queue liveness", { unhealthyQueue, unhealthyLiveness });
console.log(JSON.stringify({
ok: true,
checks: [
"default code-queue health output is compact and omits raw body/queue dumps",
"critical ok/status/service/running/heartbeat/liveness fields remain visible",
"unhealthy backend health wrapper still surfaces upstream code-queue liveness",
"remote frontend microservice health uses the same compact/raw policy",
"--raw and --full return the original health response for diagnostics",
],
compactChars: compactBody.length,
rawChars: rawBody.length,
}, null, 2));