From fcc2e5e735a39e6d0551cf54e12fe714eb11bbef Mon Sep 17 00:00:00 2001 From: Dotta Date: Wed, 7 Oct 2026 12:13:26 -0500 Subject: [PATCH] Synchronize Pi task creation evidence mocks Keep native evidence and remote memory tests bound to the browser-created issue ID, company, and assignee. Include the scoped creation check in strict evidence expectations. Co-Authored-By: Paperclip --- tests/runner-e2e/pi-native-evidence.test.ts | 15 ++++++++++----- tests/runner-e2e/pi-native-remote-flow.test.ts | 6 ++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/runner-e2e/pi-native-evidence.test.ts b/tests/runner-e2e/pi-native-evidence.test.ts index 6f165b84c9..836763e132 100644 --- a/tests/runner-e2e/pi-native-evidence.test.ts +++ b/tests/runner-e2e/pi-native-evidence.test.ts @@ -10,7 +10,12 @@ import { sanitizeJson } from "./redaction.js"; // Drive the actual flow and packager without a browser, provider, or server. // Only the external browser/API boundaries are scripted. -vi.mock("./user-actions.js", () => ({ createTaskThroughUi: vi.fn() })); +vi.mock("./user-actions.js", () => ({ + createTaskThroughUi: vi.fn(async (input: { requireExplicitTitle?: boolean }) => { + expect(input.requireExplicitTitle).toBe(true); + return { submittedAtMs: Date.now(), issueId: "issue-fixture" }; + }), +})); vi.mock("@playwright/test", () => ({ expect: (actual: unknown, message?: string) => ({ toBe: (expected: unknown) => expect(actual, message).toBe(expected), @@ -28,7 +33,7 @@ async function fixture(options: { failComments?: boolean; remote?: boolean; inco const workspacePath = join(root, "workspace"); const snapshots = join(privateDir, "snapshots"); for (const directory of [workspacePath, snapshots, join(privateDir, "html-report"), join(privateDir, "blob-report")]) await mkdir(directory, { recursive: true }); const execution = { id: "pi-native.runner-acpx-pi.local.native-questions", environment: { id: options.remote ? "daytona" : "local" }, profile: { qualificationCandidate: "pi" }, task: piNativeTasks.find(row => row.id === "native-questions")! } as FlowInput["execution"]; - const issue = { id: "issue-fixture", identifier: "PI-1", title: execution.task.buildTitle("fixture"), status: "done" }; + const issue = { id: "issue-fixture", identifier: "PI-1", title: "Provider-generated task name", companyId: "company-fixture", assigneeAgentId: "agent-fixture", status: "done" }; const run = { id: "run-fixture", status: "succeeded", runtimeMode: "native", createdAt: "2026-09-29T00:00:00Z" }; const headers = ["Pi native color", "Pi native confirmation", "Pi native name", "Pi native draft"]; let answered = 0; const typed: string[] = []; let answerProof = ""; let remoteFinished = false; const cleanupAssertions: Array<() => Promise> = []; @@ -88,7 +93,7 @@ async function fixture(options: { failComments?: boolean; remote?: boolean; inco }; const input = { page: page as unknown as FlowInput["page"], api: api as unknown as FlowInput["api"], - fixtures: { company: { id: "company-fixture", issuePrefix: "PI" }, agent: { name: "Pi fixture" }, environment: { id: "environment-fixture" } } as FlowInput["fixtures"], + fixtures: { company: { id: "company-fixture", issuePrefix: "PI" }, agent: { id: "agent-fixture", name: "Pi fixture" }, environment: { id: "environment-fixture" } } as FlowInput["fixtures"], execution, nonce: "fixture", workspacePath, deadlineAt: Date.now() + 5000, restart: async () => { throw new Error("Unexpected restart"); }, observe: () => {}, capture, evidence, ...(options.remote ? { registerCleanupAssertion: (fn: () => Promise) => cleanupAssertions.push(fn), remoteBootstrap: { @@ -108,7 +113,7 @@ describe("Pi native terminal evidence", () => { it("packages the actual successful native-question flow with durable API state and every event page", async () => { const f = await fixture(); const result = await runPiNativeFlow(f.input); - expect(result.checks).toHaveLength(15); + expect(result.checks).toHaveLength(16); expect(result.checks.every(check => check.passed)).toBe(true); const packaged = await packageEvidence({ privateDir: f.privateDir, uploadDir: f.uploadDir, secrets: [f.secret], expectPassScreenshot: true }); expect(packaged.missing).toEqual([]); expect(packaged.leaks).toEqual([]); @@ -134,7 +139,7 @@ describe("Pi native terminal evidence", () => { const f = await fixture({ failComments: true }); await expect(runPiNativeFlow(f.input)).rejects.toThrow("fixture comments unavailable"); const checks = JSON.parse(await readFile(join(f.snapshots, "pi-native-checks.json"), "utf8")); - expect(checks.checks).toHaveLength(15); + expect(checks.checks).toHaveLength(16); expect(checks.checks.every((check: { passed: boolean }) => check.passed)).toBe(true); expect(f.capture.mock.calls.some(([id]) => id === "final-state")).toBe(false); const packaged = await packageEvidence({ privateDir: f.privateDir, uploadDir: f.uploadDir, secrets: [f.secret], expectPassScreenshot: true }); diff --git a/tests/runner-e2e/pi-native-remote-flow.test.ts b/tests/runner-e2e/pi-native-remote-flow.test.ts index 3a434e3cc1..d14ed9d1cd 100644 --- a/tests/runner-e2e/pi-native-remote-flow.test.ts +++ b/tests/runner-e2e/pi-native-remote-flow.test.ts @@ -6,7 +6,7 @@ import { expect, it, vi } from "vitest"; import { piNativeTasks, PI_NATIVE_MEMORY_PARENT_SEED_PATH, PI_NATIVE_MEMORY_PARENT_SEED_CONTENT } from "./pi-native-cases.js"; import { runPiNativeFlow } from "./pi-native-flow.js"; import * as remoteFixtures from "./remote-native-fixtures.js"; -const browser = vi.hoisted(() => ({ create: (_value: any) => {} })); +const browser = vi.hoisted(() => ({ create: (_value: any) => ({ submittedAtMs: Date.now(), issueId: "issue-fixture" }) })); vi.mock("./user-actions.js", () => ({ createTaskThroughUi: async (value: unknown) => browser.create(value) })); vi.mock("@playwright/test", () => ({ expect: (value: unknown, message?: string) => ({ toBe: (expected: unknown) => expect(value, message).toBe(expected), toBeVisible: async () => {} }) })); @@ -26,8 +26,10 @@ it.each([ ? { complete: false, incompleteReasons: ["unwatched_directory"] } as any : originalDiagnostic(error)); browser.create = value => { expect(parentSeeded).toBe(true); + expect(value.requireExplicitTitle).toBe(true); expect(value.prompt).toMatch(/^Read only bootstrap-/); expect(value.prompt).not.toContain("forbidden"); - const n = issues.length + 1; issues.push({ id: `issue-${n}`, title: value.title, status: "in_progress" }); runs.push({ id: `run-${n}`, status: "running", runtimeMode: "native", createdAt: `2026-09-29T00:00:0${n}Z` }); + const n = issues.length + 1; issues.push({ id: `issue-${n}`, title: "Provider-generated task name", companyId: "company", assigneeAgentId: "agent", status: "in_progress" }); runs.push({ id: `run-${n}`, status: "running", runtimeMode: "native", createdAt: `2026-09-29T00:00:0${n}Z` }); + return { submittedAtMs: Date.now(), issueId: `issue-${n}` }; }; const api = { request: { put: async (path: string, input: any) => { expect(path).toBe("/api/agents/agent/instructions-bundle/file");