import { describe, expect, it } from "vitest"; import { renderCaseOutcome } from "./case-outcome.js"; import { renderRunnerE2EDashboard } from "./dashboard.js"; import { firstTaskTranscript, firstTaskUserRequest, renderFirstTaskTranscript, } from "./first-task-transcript.js"; import type { FirstTaskEvidence, FirstTaskCheckpoint, } from "./first-task-scoring.js"; import type { RunnerE2EResult } from "./types.js"; function recording(): FirstTaskEvidence { const opening: FirstTaskCheckpoint = { id: "opening", phase: "opening", at: "2026-09-15T00:00:00Z", issueId: "task", tasks: [], agents: [{ id: "agent", name: "Alex" }], runs: [], documents: [], comments: [{ id: "greeting", authorAgentId: "agent", body: "Welcome" }], interactions: [ { id: "question", kind: "ask_user_questions", status: "pending", payload: { questions: [ { id: "q", prompt: "What would help?", options: [{ id: "plan", label: "Make a plan" }], }, ], }, }, ], }; const response = structuredClone(opening); Object.assign(response, { id: "response", phase: "response", at: "2026-09-15T00:01:00Z", }); Object.assign(response.interactions[0], { status: "answered", resolvedAt: "2026-09-15T00:00:20Z", result: { answers: [ { questionId: "q", optionIds: ["plan"], otherText: "Use our garden club facts", }, ], }, }); response.comments.push({ id: "reply", authorAgentId: "agent", body: "Shall I proceed? ", createdAt: "2026-09-15T00:00:50Z", }); response.documents.push({ id: "doc", key: "plan", title: "Proposal", body: "Original scope", latestRevisionId: "v1", latestRevisionNumber: 1, }); const finished = structuredClone(response); Object.assign(finished, { id: "finished", phase: "finished", at: "2026-09-15T00:02:00Z", }); Object.assign(finished.documents[0], { body: "Revised scope", latestRevisionId: "v2", latestRevisionNumber: 2, }); return { caseId: "clear-task-first-response", nonce: "test", onboardingIssueId: "task", agentId: "agent", initialTaskIds: ["task"], instructions: [], configuredModel: null, observedModels: [], checkpoints: [opening, response, finished], checks: [ { id: "no-premature-work", passed: true, detail: "No work before approval", evidence: ["response"], }, ], }; } function result(): RunnerE2EResult { return { schema: "paperclip.runner-e2e.result/v2", suiteId: "first-task", executionId: "first-task.legacy-codex.local.clear-task-first-response", attempt: 1, status: "failed", profileId: "legacy-codex", environmentId: "local", caseId: "clear-task-first-response", provider: "openai", model: "unknown", runtimeMode: "legacy", startedAt: "2026-09-15T00:00:00Z", finishedAt: "2026-09-15T00:02:00Z", durationMs: 120000, runIds: [], cleanup: "passed", firstTask: recording(), failureClass: "secret_leak", error: "Credential detected in persisted Paperclip home: sessions/example.json", }; } describe("first-task conversation report", () => { it("grounds requirements in submitted user comments and resolved form answers", () => { const e = recording(); for (const checkpoint of e.checkpoints) { for (const row of [...checkpoint.comments, ...checkpoint.interactions]) row.issueId = "task"; Object.assign(checkpoint.interactions[0], { resolvedByUserId: "board" }); } e.checkpoints.at(-1)!.comments.push({ id: "user-scope", issueId: "task", authorUserId: "board", body: "Invite beginners explicitly." }); const request = firstTaskUserRequest(e); expect(request).toContain("[comment:task:user-scope] Invite beginners explicitly."); expect(request).toContain("[answer:question] Make a plan\nUse our garden club facts"); expect(request.match(/Use our garden club facts/g)).toHaveLength(1); expect(request).not.toMatch(/Shall I proceed|Welcome|GARDENtest|two-sentence/); }); it("does not infer requirements from scenario defaults, agent answers, or unrelated tasks", () => { const e = recording(); for (const checkpoint of e.checkpoints) { for (const row of checkpoint.interactions) Object.assign(row, { issueId: "task", resolvedByAgentId: "agent" }); checkpoint.comments.push({ id: "foreign", issueId: "other-task", authorUserId: "board", body: "Foreign requirement" }); } expect(() => firstTaskUserRequest(e)).toThrow("Missing recorded user request"); }); it("deduplicates observations, keeps first-observed time, and includes answers and each document revision", () => { const entries = firstTaskTranscript(recording()); expect(entries.filter((e) => e.kind === "comment")).toHaveLength(2); expect(entries.filter((e) => e.kind === "interaction")).toHaveLength(1); expect(entries.filter((e) => e.kind === "answer")).toHaveLength(1); expect( entries.filter((e) => e.kind === "document").map((e) => e.row.body), ).toEqual(["Original scope", "Revised scope"]); expect(entries.find((e) => e.row.id === "greeting")?.at).toBe( "2026-09-15T00:00:00Z", ); expect(entries.find((e) => e.kind === "interaction")?.row.status).toBe( "answered", ); expect(entries.findIndex((e) => e.kind === "answer")).toBeLessThan( entries.findIndex((e) => e.row.id === "reply"), ); }); it("renders full text, option labels, source references, and escaped untrusted chat", () => { const e = recording(); const longText = "Full retained body ".repeat(1000); e.checkpoints.at(-1)!.comments.push({ id: "long", body: longText }); const rendered = renderFirstTaskTranscript(e, (id) => `#${id}`); expect(rendered).toContain(longText); expect(rendered).toContain("Agent · Alex"); expect(rendered).toContain("transcript-comment transcript-agent"); expect(rendered).toContain("transcript-comment transcript-human"); expect(rendered).toContain("transcript-answer transcript-human"); expect(rendered).toContain("transcript-interaction transcript-card"); expect(rendered).toContain("User card response"); expect(rendered).toContain("Make a plan\nUse our garden club facts"); expect(rendered).toContain('href="#finished"'); expect(rendered).toContain("<script>unsafe()</script>"); expect(rendered).not.toContain("