207 lines
11 KiB
TypeScript
207 lines
11 KiB
TypeScript
import { codexTasksQueryForTest } from "./src/code-queue";
|
|
|
|
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 asArray(value: unknown): unknown[] {
|
|
assertCondition(Array.isArray(value), "expected JSON array", { value });
|
|
return value as unknown[];
|
|
}
|
|
|
|
function longText(marker: string, repeat: number): string {
|
|
return Array.from({ length: repeat }, (_, index) => `${marker}-${index} #132 Gate report diagnostic review evidence direct workbench fix`).join("\n");
|
|
}
|
|
|
|
function manyIds(prefix: string, count: number): string[] {
|
|
return Array.from({ length: count }, (_, index) => `${prefix}-${String(index + 1).padStart(3, "0")}`);
|
|
}
|
|
|
|
function task(id: string, status: string, updatedAt: string, readAt: string | null = null): JsonRecord {
|
|
return {
|
|
id,
|
|
queueId: "default",
|
|
status,
|
|
currentAttempt: status === "running" ? 2 : 1,
|
|
updatedAt,
|
|
finishedAt: status === "succeeded" ? updatedAt : null,
|
|
readAt,
|
|
prompt: longText(`prompt-${id}`, 90),
|
|
basePrompt: longText(`base-${id}`, 70),
|
|
displayPrompt: longText(`display-${id}`, 80),
|
|
lastAssistantMessage: {
|
|
at: updatedAt,
|
|
seq: 99,
|
|
source: "assistant",
|
|
text: longText(`assistant-${id}`, 120),
|
|
},
|
|
};
|
|
}
|
|
|
|
function fixtureResponse(path: string): JsonRecord {
|
|
if (path.includes("/summary")) {
|
|
const taskId = decodeURIComponent(path.split("/api/tasks/")[1]?.split("/")[0] ?? "unknown");
|
|
return {
|
|
ok: true,
|
|
status: 200,
|
|
body: {
|
|
ok: true,
|
|
summary: {
|
|
id: taskId,
|
|
queueId: "default",
|
|
status: taskId.includes("running") ? "running" : "succeeded",
|
|
currentAttempt: 1,
|
|
maxAttempts: 99,
|
|
prompt: longText(`summary-prompt-${taskId}`, 100),
|
|
basePrompt: longText(`summary-base-${taskId}`, 80),
|
|
lastAssistantMessage: {
|
|
at: "2026-05-22T00:00:00.000Z",
|
|
seq: 120,
|
|
source: "assistant",
|
|
text: longText(`summary-assistant-${taskId}`, 130),
|
|
},
|
|
commands: {
|
|
show: `bun scripts/cli.ts codex task ${taskId}`,
|
|
trace: `bun scripts/cli.ts codex task ${taskId} --trace --tail --limit 80`,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
assertCondition(path.startsWith("/api/microservices/code-queue/proxy/api/tasks/overview"), "unexpected path", { path });
|
|
return {
|
|
ok: true,
|
|
status: 200,
|
|
body: {
|
|
ok: true,
|
|
queue: {
|
|
executionDiagnostics: {
|
|
state: "split-brain",
|
|
splitBrain: true,
|
|
effectiveLiveness: "live",
|
|
splitBrainLive: true,
|
|
recommendedAction: "continue-supervision",
|
|
livenessSummary: longText("split-brain-live-summary", 45),
|
|
databaseActiveTaskCount: 80,
|
|
databaseActiveTaskIds: manyIds("db-active", 80),
|
|
schedulerActiveRunSlotCount: 30,
|
|
schedulerActiveTaskIds: manyIds("scheduler-active", 30),
|
|
activeHeartbeatCount: 80,
|
|
activeHeartbeatTaskIds: manyIds("active-heartbeat", 80),
|
|
heartbeatFreshTaskIds: manyIds("fresh-heartbeat", 80),
|
|
heartbeatExpiredTaskIds: [],
|
|
heartbeatMissingTaskIds: [],
|
|
staleRecoveryCandidateTaskIds: [],
|
|
heartbeatRiskTaskIds: [],
|
|
traceGapTaskIds: manyIds("trace-gap", 60),
|
|
traceGapNotStaleTaskIds: manyIds("trace-gap-fresh", 40),
|
|
reasons: Array.from({ length: 24 }, (_, index) => longText(`diagnostic-reason-${index + 1}`, 10)),
|
|
oaPublisher: {
|
|
pendingTaskIds: manyIds("oa-pending", 80),
|
|
lastError: longText("oa-publisher-error", 60),
|
|
},
|
|
},
|
|
},
|
|
pagination: {
|
|
limit: 200,
|
|
returned: 15,
|
|
total: 15,
|
|
hasMore: false,
|
|
nextBeforeId: null,
|
|
includeActive: true,
|
|
},
|
|
tasks: [
|
|
task("task-running", "running", "2026-05-22T00:09:00.000Z"),
|
|
task("task-succeeded-1", "succeeded", "2026-05-22T00:08:00.000Z"),
|
|
task("task-succeeded-2", "succeeded", "2026-05-22T00:07:00.000Z"),
|
|
task("task-succeeded-3", "succeeded", "2026-05-22T00:06:00.000Z"),
|
|
task("task-succeeded-4", "succeeded", "2026-05-22T00:05:00.000Z"),
|
|
task("task-succeeded-5", "succeeded", "2026-05-22T00:04:00.000Z"),
|
|
task("task-succeeded-6", "succeeded", "2026-05-22T00:03:00.000Z"),
|
|
task("task-succeeded-7", "succeeded", "2026-05-22T00:02:00.000Z"),
|
|
task("task-read-1", "succeeded", "2026-05-22T00:01:50.000Z", "2026-05-22T00:01:55.000Z"),
|
|
task("task-read-2", "succeeded", "2026-05-22T00:01:40.000Z", "2026-05-22T00:01:45.000Z"),
|
|
task("task-read-3", "succeeded", "2026-05-22T00:01:30.000Z", "2026-05-22T00:01:35.000Z"),
|
|
task("task-read-4", "succeeded", "2026-05-22T00:01:20.000Z", "2026-05-22T00:01:25.000Z"),
|
|
task("task-read-5", "succeeded", "2026-05-22T00:01:10.000Z", "2026-05-22T00:01:15.000Z"),
|
|
task("task-read-6", "succeeded", "2026-05-22T00:01:05.000Z", "2026-05-22T00:01:09.000Z"),
|
|
task("task-queued", "queued", "2026-05-22T00:01:00.000Z"),
|
|
],
|
|
},
|
|
};
|
|
}
|
|
|
|
export function runCodeQueueSupervisorDisclosureContract(): JsonRecord {
|
|
const supervisor = codexTasksQueryForTest(["--view", "supervisor", "--limit", "20"], fixtureResponse);
|
|
const full = codexTasksQueryForTest(["--view", "full", "--limit", "20"], fixtureResponse);
|
|
|
|
const supervisorBody = JSON.stringify(supervisor);
|
|
const fullBody = JSON.stringify(full);
|
|
const supervisorData = asRecord(supervisor);
|
|
const supervisorView = asRecord(supervisorData.supervisor);
|
|
const disclosure = asRecord(supervisorView.disclosure);
|
|
const runningItem = asRecord(asArray(asRecord(supervisorView.running).items)[0]);
|
|
const recentCompleted = asRecord(supervisorView.recentCompleted);
|
|
const recentItems = asArray(recentCompleted.items);
|
|
const prompt = asRecord(runningItem.prompt);
|
|
const lastMessage = asRecord(runningItem.lastMessage);
|
|
const commands = asRecord(runningItem.commands);
|
|
const fullItem = asRecord(asArray(asRecord(asRecord(full).tasks).items)[0]);
|
|
const completedUnread = asRecord(supervisorView.completedUnread);
|
|
const fullTasks = asRecord(asRecord(full).tasks);
|
|
const diagnostics = asRecord(supervisorView.executionDiagnostics);
|
|
const liveness = asRecord(diagnostics.liveness);
|
|
const listBudget = asRecord(diagnostics.listBudget);
|
|
const omittedCounts = asRecord(listBudget.omittedCounts);
|
|
|
|
assertCondition(supervisorBody.length < fullBody.length * 0.55, "supervisor output should be materially smaller than full output", { supervisorChars: supervisorBody.length, fullChars: fullBody.length });
|
|
assertCondition(supervisorBody.length < 70_000, "supervisor output should remain bounded even with large diagnostics", { supervisorChars: supervisorBody.length });
|
|
assertCondition(recentItems.length === 5, "recentCompleted should be capped below --limit by default", { returned: recentItems.length });
|
|
assertCondition(asArray(completedUnread.items).length === 7, "completedUnread should keep unread terminal tasks separate from recentCompleted", completedUnread);
|
|
assertCondition(recentItems.every((item) => asRecord(item).unreadTerminal === false), "recentCompleted should not duplicate unread terminal tasks", { recentItems });
|
|
assertCondition(asArray(diagnostics.databaseActiveTaskIds).length === 12, "diagnostic task id lists should be capped", diagnostics);
|
|
assertCondition(omittedCounts.databaseActiveTaskIds === 68, "diagnostic omitted counts should preserve full visibility metadata", omittedCounts);
|
|
assertCondition(liveness.effectiveLiveness === "live", "supervisor liveness summary should keep split-brain live explicit", liveness);
|
|
assertCondition(liveness.recommendedAction === "continue-supervision", "supervisor liveness summary should recommend continued supervision", liveness);
|
|
assertCondition(liveness.splitBrainLive === true, "supervisor liveness summary should mark splitBrainLive", liveness);
|
|
assertCondition(liveness.activeHeartbeatCount === 80, "supervisor liveness summary should foreground active heartbeat count", liveness);
|
|
assertCondition(asArray(liveness.heartbeatFreshTaskIds).length === 12, "supervisor liveness summary should keep heartbeatFreshTaskIds bounded", liveness);
|
|
assertCondition(String(liveness.interpretation ?? "").includes("continue supervision"), "supervisor liveness interpretation should not imply scheduler stoppage", liveness);
|
|
assertCondition(asArray(diagnostics.reasons).length === 6, "diagnostic reasons should be capped", diagnostics);
|
|
assertCondition(diagnostics.livenessSummaryTruncated === true, "long diagnostic liveness summary should be previewed", diagnostics);
|
|
assertCondition(listBudget.truncated === true && typeof listBudget.rawCommand === "string", "diagnostic list budget should disclose raw command", listBudget);
|
|
assertCondition(asArray(runningItem.issueRefs).includes("#132"), "supervisor row should expose issue refs for triage", runningItem);
|
|
assertCondition(Number(prompt.chars) > String(prompt.text ?? "").length && prompt.truncated === true, "supervisor prompt must be a short preview with original char count", prompt);
|
|
assertCondition(Number(lastMessage.chars) > String(lastMessage.text ?? "").length && lastMessage.truncated === true, "supervisor body must be a short preview with original char count", lastMessage);
|
|
assertCondition(commands.show !== undefined && commands.trace !== undefined && commands.output !== undefined && commands.full !== undefined, "supervisor row must keep progressive drill-down commands", commands);
|
|
assertCondition(runningItem.promptPreview === undefined && runningItem.lastAssistantMessage === undefined, "supervisor rows must not expose legacy long list fields", runningItem);
|
|
assertCondition(asRecord(fullItem.promptPreview).chars !== undefined && fullItem.lastAssistantMessage !== undefined, "full view must retain detailed task row fields", fullItem);
|
|
assertCondition(fullTasks.returned === 15, "full view must not inherit supervisor recentCompleted cap", fullTasks);
|
|
assertCondition(asRecord(disclosure.outputBudget).recentCompletedReturnedLimit === 5, "supervisor must expose output budget metadata", disclosure);
|
|
|
|
return {
|
|
ok: true,
|
|
checks: [
|
|
"supervisor output materially smaller than full",
|
|
"recentCompleted capped",
|
|
"split-brain diagnostics capped",
|
|
"prompt/body previews bounded",
|
|
"drill-down commands preserved",
|
|
"full view remains detailed",
|
|
],
|
|
supervisorChars: supervisorBody.length,
|
|
fullChars: fullBody.length,
|
|
};
|
|
}
|
|
|
|
if (import.meta.main) {
|
|
process.stdout.write(`${JSON.stringify(runCodeQueueSupervisorDisclosureContract(), null, 2)}\n`);
|
|
}
|