160 lines
7.6 KiB
TypeScript
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));
|