fix: clarify code queue liveness snapshots
This commit is contained in:
@@ -241,6 +241,64 @@ function splitBrainLiveSupervisorFixtureResponse(path: string): JsonRecord {
|
||||
};
|
||||
}
|
||||
|
||||
function staleSnapshotSupervisorFixtureResponse(path: string): JsonRecord {
|
||||
if (path.includes("/summary")) return fixtureResponse(path);
|
||||
assertCondition(path.startsWith("/api/microservices/code-queue/proxy/api/tasks/overview"), "unexpected path", { path });
|
||||
const staleTaskIds = manyIds("stale-active", 7);
|
||||
const tasks = [
|
||||
...staleTaskIds.map((taskId, index) => task(
|
||||
taskId,
|
||||
"running",
|
||||
`2026-05-22T02:${String(50 - index).padStart(2, "0")}:00.000Z`,
|
||||
)),
|
||||
task("stale-snapshot-new-queued", "queued", "2026-05-22T02:55:00.000Z"),
|
||||
];
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
body: {
|
||||
ok: true,
|
||||
queue: {
|
||||
counts: { running: 7, queued: 1 },
|
||||
activeQueueIds: [],
|
||||
activeTaskIds: { items: [], count: 7, returned: 0, truncated: true },
|
||||
activeRunSlotCount: 0,
|
||||
databaseActiveTaskCount: 7,
|
||||
executionDiagnostics: {
|
||||
state: "stale-active",
|
||||
splitBrain: false,
|
||||
effectiveLiveness: "at-risk",
|
||||
recommendedAction: "investigate-heartbeat-risk",
|
||||
now: "2026-05-22T03:00:00.000Z",
|
||||
databaseActiveTaskCount: 7,
|
||||
databaseActiveTaskIds: staleTaskIds,
|
||||
schedulerActiveRunSlotCount: 0,
|
||||
schedulerActiveTaskIds: [],
|
||||
activeHeartbeatCount: 7,
|
||||
activeHeartbeatTaskIds: staleTaskIds,
|
||||
heartbeatFreshTaskIds: [],
|
||||
heartbeatExpiredTaskIds: staleTaskIds,
|
||||
heartbeatMissingTaskIds: [],
|
||||
staleRecoveryCandidateTaskIds: staleTaskIds,
|
||||
heartbeatRiskTaskIds: staleTaskIds,
|
||||
lastSchedulerHeartbeatAt: "2026-05-22T02:45:00.000Z",
|
||||
lastObservedAgentEventAt: "2026-05-22T02:44:30.000Z",
|
||||
reasons: ["owner heartbeat is expired and scheduler has no local active run for at least one database-active task"],
|
||||
},
|
||||
},
|
||||
pagination: {
|
||||
limit: 200,
|
||||
returned: 8,
|
||||
total: 8,
|
||||
hasMore: false,
|
||||
nextBeforeId: null,
|
||||
includeActive: true,
|
||||
},
|
||||
tasks,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function runCodeQueueSupervisorDisclosureContract(): JsonRecord {
|
||||
const supervisor = codexTasksQueryForTest(["--view", "supervisor", "--limit", "20"], fixtureResponse);
|
||||
const cappedLimit = codexTasksQueryForTest(["--view", "supervisor", "--limit", "260"], fixtureResponse);
|
||||
@@ -249,6 +307,7 @@ export function runCodeQueueSupervisorDisclosureContract(): JsonRecord {
|
||||
const runningFiltered = codexTasksQueryForTest(["--status", "running", "--limit", "40"], manyRunningFixtureResponse);
|
||||
const unreadFiltered = codexTasksQueryForTest(["--unread", "--limit", "20"], fixtureResponse);
|
||||
const splitBrainLive = codexTasksQueryForTest(["--view", "supervisor", "--limit", "20"], splitBrainLiveSupervisorFixtureResponse);
|
||||
const staleSnapshot = codexTasksQueryForTest(["--view", "supervisor", "--limit", "20"], staleSnapshotSupervisorFixtureResponse);
|
||||
|
||||
const supervisorBody = JSON.stringify(supervisor);
|
||||
const fullBody = JSON.stringify(full);
|
||||
@@ -283,6 +342,12 @@ export function runCodeQueueSupervisorDisclosureContract(): JsonRecord {
|
||||
const splitBrainLiveActivity = asRecord(splitBrainLiveView.activity);
|
||||
const splitBrainLiveConcurrency = asRecord(splitBrainLiveView.commanderConcurrency);
|
||||
const splitBrainLiveCounts = asRecord(splitBrainLiveView.counts);
|
||||
const staleSnapshotView = asRecord(asRecord(staleSnapshot).supervisor);
|
||||
const staleSnapshotActivity = asRecord(staleSnapshotView.activity);
|
||||
const staleSnapshotConcurrency = asRecord(staleSnapshotView.commanderConcurrency);
|
||||
const staleSnapshotDiagnostics = asRecord(staleSnapshotView.executionDiagnostics);
|
||||
const staleSnapshotRecovery = asRecord(staleSnapshotActivity.recovery);
|
||||
const staleSnapshotDiagnosticsRecovery = asRecord(staleSnapshotDiagnostics.recovery);
|
||||
const cappedFilters = asRecord(cappedSupervisorView.filters);
|
||||
const cappedSource = asRecord(cappedSupervisorView.source);
|
||||
const cappedLimitPolicy = asRecord(asRecord(cappedSupervisorView.disclosure).limitPolicy);
|
||||
@@ -359,6 +424,14 @@ export function runCodeQueueSupervisorDisclosureContract(): JsonRecord {
|
||||
assertCondition(String(splitBrainLiveConcurrency.decisionRule ?? "").includes("15 - activeRunnerCount"), "split-brain supervisor should give 15-concurrency arithmetic", splitBrainLiveConcurrency);
|
||||
assertCondition(String(splitBrainLiveActivity.activeQueueIdsNote ?? "").includes("zero local queue ids does not mean zero active runners"), "split-brain supervisor activity should explain activeQueueIds are local-only", splitBrainLiveActivity);
|
||||
assertCondition(String(splitBrainLiveActivity.interpretation ?? "").includes("continue supervision"), "split-brain supervisor activity should not imply scheduler stoppage", splitBrainLiveActivity);
|
||||
assertCondition(staleSnapshotActivity.heartbeatRiskTaskCount === 7 && staleSnapshotActivity.staleRecoveryCandidateTaskCount === 7, "stale supervisor snapshot should keep heartbeat-risk candidates visible", staleSnapshotActivity);
|
||||
assertCondition(staleSnapshotActivity.effectiveActiveTaskCount === 7 && staleSnapshotActivity.databaseRunningTaskCount === 7, "stale supervisor snapshot should preserve database-active running count", staleSnapshotActivity);
|
||||
assertCondition(staleSnapshotRecovery.disposition === "transient-needs-repoll" && staleSnapshotRecovery.hint === "re-poll supervisor before recovery", "stale supervisor snapshot should ask for re-poll before recovery", staleSnapshotRecovery);
|
||||
assertCondition(staleSnapshotRecovery.snapshotRole === "supervisor-poll" && staleSnapshotRecovery.boundedSnapshot === false, "supervisor recovery context should distinguish poll from submit confirmation", staleSnapshotRecovery);
|
||||
assertCondition(staleSnapshotRecovery.recoveryMutationAllowedByThisSnapshot === false, "single supervisor poll must not allow recovery mutation", staleSnapshotRecovery);
|
||||
assertCondition(staleSnapshotConcurrency.attentionRequired === true && staleSnapshotConcurrency.interventionRequired === false, "stale supervisor snapshot should require attention but not immediate high-risk intervention", staleSnapshotConcurrency);
|
||||
assertCondition(staleSnapshotDiagnostics.effectiveLiveness === "at-risk" && staleSnapshotDiagnostics.recommendedAction === "investigate-heartbeat-risk", "stale supervisor diagnostics should keep at-risk visibility", staleSnapshotDiagnostics);
|
||||
assertCondition(staleSnapshotDiagnosticsRecovery.hint === "re-poll supervisor before recovery", "stale supervisor diagnostics should carry the re-poll hint", staleSnapshotDiagnosticsRecovery);
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
@@ -376,6 +449,7 @@ export function runCodeQueueSupervisorDisclosureContract(): JsonRecord {
|
||||
"full view remains detailed",
|
||||
"split-brain live supervisor activity distinguishes scheduler-local, database, and heartbeat counts",
|
||||
"commander concurrency block names the active runner count and 15-concurrency rule",
|
||||
"stale-active supervisor snapshot remains visible but requires re-poll before recovery",
|
||||
],
|
||||
supervisorChars: supervisorBody.length,
|
||||
fullChars: fullBody.length,
|
||||
|
||||
Reference in New Issue
Block a user