fix(evals): preserve human origin on consumed queue probes

This commit is contained in:
Dotta committed 2026-10-28 01:32:20 -05:00
1 parent b70439f387
commit 15fb2318bf
5 files changed
+54 -3

No files matched your search

@@ -25,3 +25,7 @@ it("rejects accepting a stale discard of consumed input", () => { const o = vali
it("rejects a later answer borrowed from another native phase", () => { const o = valid(); o.state.latePhaseAttributed = false; expect(gradeDiscard(o).passed).toBe(false); });
it("rejects new direction never reaching the actual later worker", () => { const o = valid(); o.state.cancelDirectionRunBound = false; expect(gradeDiscard(o).passed).toBe(false); });
it("rejects overwriting the already-delivered historical request", () => { const o = valid(); o.state.consumedStillReadable = false; expect(gradeDiscard(o).passed).toBe(false); });
it.each([403, 500])("rejects late discard status %s even when the human fixture otherwise looks valid", status => {
const o = valid(); o.state.lateDiscardStatus = status; expect(gradeDiscard(o).passed).toBe(false);
});
@@ -7,7 +7,7 @@ import { submitTaskReply } from "../user-actions.js";
import { checks, type Entity } from "./internal-support.js";
import { probeAgentPermission, cleanupIdentityProbes } from "./identity-support.js";
import { releaseRuntimeWorker } from "./runtime-busy-worker.js";
import { humanQueuedRuntime } from "./runtime-queue-controls.js";
import { humanQueuedRuntime, probeConsumedHumanQueue } from "./runtime-queue-controls.js";
import { runtimeQueueCases } from "./runtime-queue.js";
import { runtimeDefinition, runtimeObservation, observeRuntime } from "./runtime-support.js";
@@ -78,7 +78,7 @@ export const runtimeDiscardCases = [runtimeDefinition("steering.discard-queued-m
state.consumedBeforeCancellation = detail.contextSnapshot?.wakeCommentIds?.includes(second.comment.id) === true
&& detail.runnerProfileJson?.nativeExecutionInput?.task?.prompt?.includes(secondText) === true;
state.discardedNeverDelivered = consumed.runs.every(row => !((row.contextSnapshot?.wakeCommentIds as string[] | undefined) ?? []).includes(targetId));
state.lateDiscardStatus = (await ctx.input.page.request.delete(`${queuePath}/${second.comment.id}`, { data: { queueId: secondQueue.queueId, revision: secondQueue.revision } })).status();
state.lateDiscardStatus = await probeConsumedHumanQueue(ctx, String(state.humanId), `${queuePath}/${second.comment.id}`, "DELETE", { queueId: secondQueue.queueId, revision: secondQueue.revision });
await ctx.input.page.goto(source, { waitUntil: "domcontentloaded" });
const message = `I later queued a different contact request on Website ${task.identifier ?? task.id}, comment ${second.comment.id}, and Morgan has already consumed it. Cancel that later contact requirement now by sending Morgan new direction to remove the contact section from the saved website plan while retaining the accessible-font requirement. Explain what happened to the already-delivered input; do not erase or rewrite it.`;
const priorIds = consumed.runs.map(row => row.id);
@@ -0,0 +1,31 @@
import { expect, it, vi } from "vitest";
import type { ChatCatalogContext } from "../chat-catalog-contract.js";
import { probeConsumedHumanQueue } from "./runtime-queue-controls.js";
function fixture(method: "PATCH" | "DELETE", status = 409) {
const origin = "http://127.0.0.1:4567", user = { user: { id: "human" } };
const fetch = vi.fn(async (_url, options) => ({ status: () => options.headers.Origin === origin ? status : 403 }));
const browserGet = vi.fn(async () => ({ status: () => 200, json: async () => user }));
const ctx = { scenario: { id: method === "PATCH" ? "steering.edit-queued-message" : "steering.discard-queued-message" },
input: { api: { baseURL: origin, get: vi.fn(async () => user) }, page: { url: () => `${origin}/RUN/issues/RUN-1`, request: { get: browserGet, fetch } } } } as unknown as ChatCatalogContext;
return { ctx, fetch, browserGet, origin };
}
it.each(["PATCH", "DELETE"] as const)("preserves the same browser human, trusted Origin and exact stale %s response", async method => {
const f = fixture(method), data = { queueId: "queue", revision: 3 };
expect(await probeConsumedHumanQueue(f.ctx, "human", "/api/issues/task/queued-comments/comment", method, data)).toBe(409);
expect(f.fetch).toHaveBeenCalledExactlyOnceWith(`${f.origin}/api/issues/task/queued-comments/comment`, { method, data, headers: { Origin: f.origin }, maxRedirects: 0, timeout: 15_000 });
expect(f.browserGet).toHaveBeenCalledExactlyOnceWith(`${f.origin}/api/auth/get-session`, { maxRedirects: 0 });
});
it("never substitutes a changed human, other origin, other endpoint or undeclared scenario", async () => {
for (const change of [ (f: ReturnType<typeof fixture>) => { f.ctx.input.api.get = vi.fn(async () => ({ user: { id: "other" } })) as never; },
(f: ReturnType<typeof fixture>) => { f.browserGet.mockResolvedValue({ status: () => 200, json: async () => ({ user: { id: "other" } }) }); },
(f: ReturnType<typeof fixture>) => { f.ctx.scenario.id = "steering.queue-follow-up"; } ]) {
const f = fixture("PATCH"); change(f);
await expect(probeConsumedHumanQueue(f.ctx, "human", "/api/issues/task/queued-comments/comment", "PATCH", {})).rejects.toThrow(); expect(f.fetch).not.toHaveBeenCalled();
}
for (const endpoint of ["https://foreign.test/api/issues/task/queued-comments/comment", "/api/instance/settings", "/api/issues/task/queued-comments/comment?redirect=1"]) {
const f = fixture("DELETE"); await expect(probeConsumedHumanQueue(f.ctx, "human", endpoint, "DELETE", {})).rejects.toThrow(); expect(f.fetch).not.toHaveBeenCalled();
}
});
it.each([200, 403, 500])("retains actual non-conflict %s instead of manufacturing 409", async status => {
const f = fixture("DELETE", status); expect(await probeConsumedHumanQueue(f.ctx, "human", "/api/issues/task/queued-comments/comment", "DELETE", {})).toBe(status);
});
@@ -26,3 +26,7 @@ it("rejects stale concurrent acceptance", () => { const o = valid(); o.state.con
it("rejects silently overwriting an already-consumed message", () => { const o = valid(); o.state.dispatchedStatus = 200; expect(gradeQueueEdit(o).passed).toBe(false); });
it("rejects a plausible wrong consumer without exact saved input and order", () => { const o = valid(); o.state.nativeDeliveryBound = false; expect(gradeQueueEdit(o).passed).toBe(false); });
it("rejects losing the initial native work", () => { const o = valid(); o.state.initialRevisionRetained = false; expect(gradeQueueEdit(o).passed).toBe(false); });
it.each([200, 403, 500])("rejects late edit status %s rather than replacing the real 409 assertion", status => {
const o = valid(); o.state.dispatchedStatus = status; expect(gradeQueueEdit(o).passed).toBe(false);
});
@@ -28,6 +28,18 @@ export async function humanQueuedRuntime(ctx: ChatCatalogContext, targetText = r
Object.assign(state, { queueBefore: before, targetId: before.entries[1]!.comment.id, humanId: session.user.id, concurrentMarker: `Preserve the human note ${ctx.input.nonce}.` });
await ctx.input.page.goto(source, { waitUntil: "domcontentloaded" }); return state;
}
export async function probeConsumedHumanQueue(ctx: ChatCatalogContext, humanId: string, endpoint: string, method: "PATCH" | "DELETE", data: unknown) {
const origin = ctx.input.api.baseURL, url = new URL(endpoint, origin);
if (ctx.scenario.id !== "steering.edit-queued-message" && ctx.scenario.id !== "steering.discard-queued-message") throw new Error("Consumed queue probe requires its declared human scenario");
if (!humanId || new URL(ctx.input.page.url()).origin !== origin || url.origin !== origin || url.search || url.hash
|| !/^\/api\/issues\/[^/]+\/queued-comments\/[^/]+$/.test(url.pathname)) throw new Error("Consumed queue probe escaped its human fixture");
const apiSession = await ctx.input.api.get<{ user?: { id?: string } }>("/api/auth/get-session");
const browserSession = await ctx.input.page.request.get(`${origin}/api/auth/get-session`, { maxRedirects: 0 });
if (browserSession.status() !== 200 || apiSession.user?.id !== humanId || (await browserSession.json() as { user?: { id?: string } }).user?.id !== humanId)
throw new Error("Consumed queue probe requires the original authenticated human in both contexts");
const response = await ctx.input.page.request.fetch(url.href, { method, data, headers: { Origin: origin }, maxRedirects: 0, timeout: 15_000 });
return response.status();
}
async function edit(page: Page, id: string, body: string) {
await page.getByTestId(`task-chat-queued-message-${id}`).getByRole("button", { name: /^Queued message actions:/ }).click();
await page.getByRole("menuitem", { name: "Edit message", exact: true }).click();
@@ -111,7 +123,7 @@ export const runtimeQueueControlCases = [runtimeDefinition("steering.edit-queued
reject: v => v.runs.length > 3 || v.runs.some(row => ["failed", "cancelled", "timed_out"].includes(row.status)) ? "The declared edited-message delivery failed or duplicated work" : undefined });
await expect(ctx.input.page.getByText("Queued message changed", { exact: true })).toBeVisible();
await expect(ctx.input.page.getByRole("button", { name: "Queue as new message", exact: true })).toBeVisible(); state.dispatchedWarningVisible = true;
state.dispatchedStatus = (await ctx.input.page.request.patch(mutation, { data: { queueId: pending.queueId, revision: pending.revision, body: "Late stale edit must not replace history" } })).status();
state.dispatchedStatus = await probeConsumedHumanQueue(ctx, String(state.humanId), mutation, "PATCH", { queueId: pending.queueId, revision: pending.revision, body: "Late stale edit must not replace history" });
const comments = await ctx.input.api.get<Entity[]>(`/api/issues/${(state.task as Entity).id}/comments?order=asc`);
state.originalCommentStillReadable = comments.some(row => row.id === targetId && row.body === `${blueText} ${state.concurrentMarker}` && row.authorUserId === state.humanId);
const consumers = delivered.runs.filter(row => row.agentId === (state.worker as Entity).id && row.id !== state.workerRunId);