Fix silent context-engine maintenance task delivery status (#102147)

* Fix silent context maintenance task delivery status

* refactor(context-engine): document maintenance delivery invariant

* fix(context-engine): preserve visible maintenance flows

* style(context-engine): format maintenance test import

* test(context-engine): use direct maintenance task lookup

---------

Co-authored-by: Sascha Kuhlmann <coolmanns@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
Sascha Kuhlmann 2026-07-09 09:33:05 -05:00 committed by GitHub
parent 3ebcfb8ee3
commit 13821c9d34
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 50 additions and 46 deletions

View file

@ -9,7 +9,7 @@ import {
} from "../../process/command-queue.js";
import * as commandQueueModule from "../../process/command-queue.js";
import { createQueuedTaskRun as createQueuedTaskRunOrNull } from "../../tasks/task-executor.js";
import { resetTaskFlowRegistryForTests } from "../../tasks/task-flow-registry.js";
import { getTaskFlowById, resetTaskFlowRegistryForTests } from "../../tasks/task-flow-registry.js";
import {
getTaskById,
listTasksForOwnerKey,
@ -654,7 +654,7 @@ describe("runContextEngineMaintenance", () => {
requesterSessionKey: sessionKey,
taskKind: TURN_MAINTENANCE_TASK_KIND,
notifyPolicy: "silent",
deliveryStatus: "pending",
deliveryStatus: "not_applicable",
});
if (!releaseForeground) {
@ -1494,6 +1494,21 @@ describe("runContextEngineMaintenance", () => {
await waitForAssertion(() => expect(maintain).toHaveBeenCalledTimes(1));
expect(sendMessageMock).not.toHaveBeenCalled();
expect(peekSystemEvents(sessionKey)).toStrictEqual([]);
const tasks = listTasksForOwnerKey(sessionKey).filter(
(task) => task.taskKind === TURN_MAINTENANCE_TASK_KIND,
);
expect(tasks).toHaveLength(1);
await waitForAssertion(() =>
expect(getTaskById(tasks[0].taskId)?.status).toBe("succeeded"),
);
const task = requireRecord(getTaskById(tasks[0].taskId), "maintenance task");
expectRecordFields(task, {
status: "succeeded",
notifyPolicy: "silent",
deliveryStatus: "not_applicable",
});
expect(task.parentFlowId).toBeUndefined();
} finally {
vi.useRealTimers();
}
@ -1552,6 +1567,14 @@ describe("runContextEngineMaintenance", () => {
"Background task update: Context engine turn maintenance.",
),
);
const task = listTasksForOwnerKey(sessionKey).find(
(candidate) => candidate.taskKind === TURN_MAINTENANCE_TASK_KIND,
);
const parentFlowId = task?.parentFlowId;
if (!parentFlowId) {
throw new Error("Expected visible maintenance to have a task flow");
}
expect(getTaskFlowById(parentFlowId)?.status).toBe("running");
if (!releaseMaintenance) {
throw new Error("Expected maintenance release callback to be initialized");
@ -1563,6 +1586,7 @@ describe("runContextEngineMaintenance", () => {
"Background task done: Context engine turn maintenance",
),
);
expect(getTaskFlowById(parentFlowId)?.status).toBe("succeeded");
} finally {
vi.useRealTimers();
}
@ -1609,6 +1633,14 @@ describe("runContextEngineMaintenance", () => {
"Background task failed: Context engine turn maintenance",
),
);
const task = listTasksForOwnerKey(sessionKey).find(
(candidate) => candidate.taskKind === TURN_MAINTENANCE_TASK_KIND,
);
const parentFlowId = task?.parentFlowId;
if (!parentFlowId) {
throw new Error("Expected failed maintenance to have a task flow");
}
expect(getTaskFlowById(parentFlowId)?.status).toBe("failed");
} finally {
vi.useRealTimers();
}

View file

@ -22,7 +22,6 @@ import {
createQueuedTaskRun,
failTaskRunByRunId,
recordTaskRunProgressByRunId,
setDetachedTaskDeliveryStatusByRunId,
startTaskRunByRunId,
} from "../../tasks/detached-task-runtime.js";
import {
@ -231,11 +230,15 @@ function markDeferredTurnMaintenanceTaskScheduleFailure(params: {
});
}
function buildTurnMaintenanceTaskDescriptor(params: { sessionKey: string }) {
const runId = `turn-maint:${params.sessionKey}:${Date.now().toString(36)}:${randomUUID().slice(
0,
8,
)}`;
function buildTurnMaintenanceTaskDescriptor(params: {
sessionKey: string;
runId?: string;
notifyPolicy?: "silent" | "done_only" | "state_changes";
deliveryStatus?: "not_applicable" | "pending";
}) {
const runId =
params.runId ??
`turn-maint:${params.sessionKey}:${Date.now().toString(36)}:${randomUUID().slice(0, 8)}`;
return createQueuedTaskRun({
runtime: "acp",
taskKind: TURN_MAINTENANCE_TASK_KIND,
@ -246,8 +249,10 @@ function buildTurnMaintenanceTaskDescriptor(params: { sessionKey: string }) {
runId,
label: TURN_MAINTENANCE_TASK_LABEL,
task: TURN_MAINTENANCE_TASK_TASK,
notifyPolicy: "silent",
deliveryStatus: "pending",
notifyPolicy: params.notifyPolicy ?? "silent",
// Fast maintenance stays silent and must not create a one-task flow.
// Long-running and failed workers promote it to pending before notifying.
deliveryStatus: params.deliveryStatus ?? "not_applicable",
preferMetadata: true,
});
}
@ -257,45 +262,12 @@ function promoteTurnMaintenanceTaskVisibility(params: {
runId: string;
notifyPolicy: "done_only" | "state_changes";
}) {
const task = findTaskByRunIdForOwner({
runId: params.runId,
callerOwnerKey: params.sessionKey,
});
if (!task) {
return createQueuedTaskRun({
runtime: "acp",
taskKind: TURN_MAINTENANCE_TASK_KIND,
sourceId: TURN_MAINTENANCE_TASK_KIND,
requesterSessionKey: params.sessionKey,
ownerKey: params.sessionKey,
scopeKind: "session",
runId: params.runId,
label: TURN_MAINTENANCE_TASK_LABEL,
task: TURN_MAINTENANCE_TASK_TASK,
notifyPolicy: params.notifyPolicy,
deliveryStatus: "pending",
preferMetadata: true,
});
}
setDetachedTaskDeliveryStatusByRunId({
runId: params.runId,
runtime: "acp",
return buildTurnMaintenanceTaskDescriptor({
sessionKey: params.sessionKey,
runId: params.runId,
notifyPolicy: params.notifyPolicy,
deliveryStatus: "pending",
});
if (task.notifyPolicy !== params.notifyPolicy) {
updateTaskNotifyPolicyForOwner({
taskId: task.taskId,
callerOwnerKey: params.sessionKey,
notifyPolicy: params.notifyPolicy,
});
}
return (
findTaskByRunIdForOwner({
runId: params.runId,
callerOwnerKey: params.sessionKey,
}) ?? task
);
}
/**