mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-10 12:37:55 +01:00
test(evals): preserve announcement original response clock
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
c6cc59282a
commit
34d748d06f
4 files changed
+60
-3
No files matched your search
@@ -40,6 +40,7 @@ const originalClockExecutionIds = new Set([
|
||||
"chat-features.runner-opencode.local.navigation-preferences.quick-search",
|
||||
"chat-features.runner-opencode.local.navigation-preferences.edit-profile",
|
||||
"chat-features.runner-opencode.local.navigation-preferences.broken-link",
|
||||
"chat-features.runner-opencode.local.navigation-preferences.dismiss-announcement",
|
||||
"chat-features.runner-opencode.local.projects.share-project",
|
||||
"chat-features.runner-opencode.local.access.cli-authorization",
|
||||
"chat-features.runner-opencode.local.access.other-company",
|
||||
|
||||
@@ -3587,7 +3587,7 @@
|
||||
"../../ui/src/pages/Projects.tsx",
|
||||
"../../ui/src/components/AnnouncementWell.tsx"
|
||||
],
|
||||
"oracleVersion": "paperclip.chat-catalog.announcement-dismissal.v2",
|
||||
"oracleVersion": "paperclip.chat-catalog.announcement-dismissal.v3",
|
||||
"expectedRunCount": 1,
|
||||
"turnTimeoutMs": 120000,
|
||||
"attemptTimeoutMs": 300000,
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { afterEach, expect, it, vi } from "vitest";
|
||||
import type { ChatCatalogContext } from "../chat-catalog-contract.js";
|
||||
import { navigationBoundaryIdentityCases } from "./identity-navigation-boundaries.js";
|
||||
|
||||
const definition = navigationBoundaryIdentityCases.find(row => row.scenarioId === "navigation-preferences.dismiss-announcement")!;
|
||||
const boundary = new Error("First actual publication read; no human action performed");
|
||||
function fixture(replyAt = 151_600, deadline: number | undefined = 300_000) {
|
||||
const read = vi.fn().mockRejectedValue(boundary);
|
||||
const ctx = { observationDeadlineAt: deadline,
|
||||
input: { execution: { id: "chat-features.runner-opencode.local.navigation-preferences.dismiss-announcement" },
|
||||
page: { url: () => "http://fixture.invalid/ACO/chats/ceo" }, api: { get: read } },
|
||||
refreshIssue: async () => {},
|
||||
issue: () => ({ conversationState: Date.now() >= replyAt ? "waiting" : "active" }),
|
||||
allRuns: async () => [{ id: "native", status: Date.now() >= replyAt ? "succeeded" : "running" }],
|
||||
} as unknown as ChatCatalogContext;
|
||||
return { ctx, read };
|
||||
}
|
||||
afterEach(() => vi.useRealTimers());
|
||||
it("actual announcement act admits the native reply after151.6s within its original clock before human dismissal", async () => {
|
||||
vi.useFakeTimers(); vi.setSystemTime(0);
|
||||
const { ctx, read } = fixture();
|
||||
const pending = definition.act!(ctx, { publication: { id: "publication" } }).catch(error => error);
|
||||
await vi.advanceTimersByTimeAsync(151_000); expect(read).not.toHaveBeenCalled();
|
||||
await vi.advanceTimersByTimeAsync(1000); expect(await pending).toBe(boundary);
|
||||
expect(read).toHaveBeenCalledExactlyOnceWith("/api/announcements/current");
|
||||
expect(definition.attemptTimeoutMs).toBe(300_000);
|
||||
});
|
||||
it("consumes elapsed setup instead of granting a fresh wait budget", async () => {
|
||||
vi.useFakeTimers(); vi.setSystemTime(200_000);
|
||||
const { ctx, read } = fixture(280_000, 270_000);
|
||||
const pending = definition.act!(ctx, {}).catch(error => error);
|
||||
await vi.advanceTimersByTimeAsync(70_500);
|
||||
expect(String(await pending)).toContain("Timed out waiting for initial identity response");
|
||||
expect(read).not.toHaveBeenCalled();
|
||||
});
|
||||
it.each(["failed", "cancelled", "timed_out"])("does not turn a %s native run into a human dismissal", async status => {
|
||||
vi.useFakeTimers(); vi.setSystemTime(0);
|
||||
const { ctx, read } = fixture(); ctx.allRuns = async () => [{ status }] as never;
|
||||
await expect(definition.act!(ctx, {})).rejects.toThrow("Initial response failed");
|
||||
expect(read).not.toHaveBeenCalled();
|
||||
});
|
||||
it.each([undefined, NaN, Infinity, 200_000, 199_999])("rejects missing or exhausted original deadline %s before observing", async deadline => {
|
||||
vi.useFakeTimers(); vi.setSystemTime(200_000);
|
||||
const { ctx, read } = fixture(0); ctx.observationDeadlineAt = deadline;
|
||||
await expect(definition.act!(ctx, {})).rejects.toThrow("Original native observation budget exhausted or missing");
|
||||
expect(read).not.toHaveBeenCalled();
|
||||
});
|
||||
it("rejects a successful observation that completes after the original deadline", async () => {
|
||||
vi.useFakeTimers(); vi.setSystemTime(269_000);
|
||||
const { ctx, read } = fixture(0, 270_000);
|
||||
ctx.refreshIssue = async () => { vi.setSystemTime(270_001); };
|
||||
const pending = definition.act!(ctx, {}).catch(error => error);
|
||||
await vi.advanceTimersByTimeAsync(1500);
|
||||
expect(String(await pending)).toContain("Timed out waiting for initial identity response");
|
||||
expect(read).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -122,9 +122,9 @@ export const navigationBoundaryIdentityCases: readonly ChatCatalogCase[] = [
|
||||
observerBeforePublicationId: observerPublication?.id, invalidAuditCompanyStatus };
|
||||
} catch (error) { try { await observer.dispose(); } finally { observers.delete(ctx); const id = otherCompanies.get(ctx); if (id) await ctx.input.api.delete(`/api/companies/${id}`, { allowNotFound: true }); otherCompanies.delete(ctx); } throw error; }
|
||||
}, gradeNavigationBoundary, {
|
||||
sourceFiles: [...sources, "chat-announcement-fixture.ts", "harness-env.ts", "../../packages/shared/src/announcements.ts", "../../server/src/services/announcement-feed.ts", "../../server/src/routes/announcements.ts", "../../ui/src/pages/Projects.tsx", "../../ui/src/components/AnnouncementWell.tsx"], authentication: "human-session", oracleVersion: "paperclip.chat-catalog.announcement-dismissal.v2",
|
||||
sourceFiles: [...sources, "chat-announcement-fixture.ts", "harness-env.ts", "../../packages/shared/src/announcements.ts", "../../server/src/services/announcement-feed.ts", "../../server/src/routes/announcements.ts", "../../ui/src/pages/Projects.tsx", "../../ui/src/components/AnnouncementWell.tsx"], authentication: "human-session", oracleVersion: "paperclip.chat-catalog.announcement-dismissal.v3",
|
||||
async act(ctx, state) {
|
||||
await waitForReply(ctx); const publication = state.publication as Publication; const source = ctx.input.page.url();
|
||||
await waitForReply(ctx, chatCatalogOriginalPhaseDeadline(ctx)); const publication = state.publication as Publication; const source = ctx.input.page.url();
|
||||
state.beforeHumanPublicationId = (await ctx.input.api.get<Publication | null>("/api/announcements/current"))?.id;
|
||||
state.agentDismissStatus = await probeAgentPermission(ctx, `/api/announcements/${encodeURIComponent(publication.id)}/dismiss`, "POST", { companyId: ctx.input.fixtures.company.id });
|
||||
const response = ctx.input.page.waitForResponse(row => row.request().method() === "POST" && new URL(row.url()).pathname === `/api/announcements/${publication.id}/dismiss`);
|
||||
|
||||
Reference in new issue
Block a user