diff --git a/tests/runner-e2e/chat-catalog-domains/integrator-status-cards.test.ts b/tests/runner-e2e/chat-catalog-domains/integrator-status-cards.test.ts index 9d5060bf8cc..e62cf789da8 100644 --- a/tests/runner-e2e/chat-catalog-domains/integrator-status-cards.test.ts +++ b/tests/runner-e2e/chat-catalog-domains/integrator-status-cards.test.ts @@ -114,3 +114,32 @@ it("a paraphrase cannot replace required saved-card link or source-access eviden expect(gradeIntegratorCards(o).passed).toBe(true); expect(gradeIntegratorCards({ ...o, links: ["/ACORN/issues/source"] }).passed).toBe(false); }); + +import type { StatusCard } from "../../../packages/shared/src/validators/status-card.js"; +import { updateIssueSchema } from "../../../packages/shared/src/validators/issue.js"; +import { selectedStatusCardReference, refreshedBlockerTaskInput } from "./integrator-status-cards.js"; +it("delivers only actual selected card and saved generation/source context, not live answers or actions", () => { + const o = valid("status-cards.explain-card"); + const card = { ...o.cards[0]!, fingerprint: { source: { title: "Payment approval blocks launch", status: "blocked" } } } as unknown as StatusCard; + const context = selectedStatusCardReference(card, [{ id: "source", identifier: "ACN-1", title: "private-current-title", status: "done" }, { id: "unrelated", title: "unrelated-private-detail" }], "ACN"); + expect(context).toContain("[Launch blockers](/ACN/status/card)"); expect(context).toContain(card.summaryBody!); expect(context).toContain(card.lastGeneratedAt!); + expect(context).toContain("Payment approval blocks launch"); expect(context).toContain("/ACN/issues/ACN-1"); + expect(context).not.toMatch(/private-current-title|unrelated-private-detail|must|expected|archive|restore|DELETE|PATCH|\/api\//i); + expect(() => selectedStatusCardReference(card, [], undefined)).toThrow("actual company issue prefix"); + const other = selectedStatusCardReference({ ...card, id: "other-card", title: "Research" }, [], "ACN"); + expect(other).not.toContain("/ACN/status/card)"); expect(other).toContain("/ACN/status/other-card"); +}); +it("makes the genuine new blocker visible in the public task title used by bounded generation input", () => { + const update = updateIssueSchema.parse(refreshedBlockerTaskInput()); + expect(update.title).toMatch(/mobile Safari.*checkout regression/i); expect(update.description).toContain("Payment approval has been received"); + expect(update).not.toHaveProperty("status"); // No task/card/native status fabricated. + expect(JSON.stringify(update)).not.toMatch(/summari[sz]e|write|return|tool|generationIssueId|model/i); +}); +it("declares factual human attachments only for the two actual missing selected referents", () => { + for (const id of ["status-cards.explain-card", "status-cards.archive-card"]) { + const definition = integratorStatusCardsCases.find(row => row.scenarioId === id)!; + expect(definition.authentication).toBe("human-session"); expect(definition.queryAttachments).toEqual([{ stateKey: "factualContextAttachment", filename: "selected-status-card.md" }]); + } + // The refresh query already names Launch and the retained run selected it correctly. + expect(integratorStatusCardsCases.find(row => row.scenarioId === "status-cards.refresh-card")!.queryAttachments).toBeUndefined(); +}); diff --git a/tests/runner-e2e/chat-catalog-domains/integrator-status-cards.ts b/tests/runner-e2e/chat-catalog-domains/integrator-status-cards.ts index 6b94a164364..c7c3c781551 100644 --- a/tests/runner-e2e/chat-catalog-domains/integrator-status-cards.ts +++ b/tests/runner-e2e/chat-catalog-domains/integrator-status-cards.ts @@ -1,3 +1,4 @@ +import { uploadFactualQueryAttachment, factualContextQueryAttachment } from "../chat-query-attachments.js"; import type { StatusCard, StatusCardUpdate, StatusCardSummaryRevision } from "../../../packages/shared/src/validators/status-card.js"; import type { ChatCatalogCase, ChatCatalogContext } from "../chat-catalog-contract.js"; import { pollUntil } from "../api.js"; @@ -125,6 +126,20 @@ async function seedCard(ctx: ChatCatalogContext, authorId: string, summarizerId: reject: card => card.state === "error" ? "Prerequisite card generation failed; no synthetic summary substituted" : undefined }); } finally { await ctx.input.api.delete(`/api/agents/${authorId}/keys/${key.id}`, { allowNotFound: true }); } } +/** Human-visible selected resource data, copied from actual saved public rows. + * Live task state is deliberately left for the responding agent to inspect. */ +export function selectedStatusCardReference(card: StatusCard, sources: Entity[], issuePrefix: string | null | undefined) { + if (!issuePrefix) throw new Error("Selected status card context requires the actual company issue prefix"); + const sourceReferences = sources.filter(source => !!card.fingerprint?.[source.id]).map(source => ({ id: source.id, identifier: source.identifier, + title: card.fingerprint?.[source.id]?.title, href: `/${issuePrefix}/issues/${source.identifier ?? source.id}` })); + return `# Selected status card\n\n[${card.title ?? "Status card"}](/${issuePrefix}/status/${card.id})\n\n` + JSON.stringify({ + cardId: card.id, title: card.title, authorAgentId: card.createdByAgentId, summarizerAgentId: card.agentId, + lastGeneratedAt: card.lastGeneratedAt, summaryBody: card.summaryBody, sourceReferences, + }, null, 2); +} +export function refreshedBlockerTaskInput() { + return { title: "Mobile Safari checkout regression blocks launch", description: "Payment approval has been received. The remaining blocker is the mobile Safari checkout regression." }; +} const experiments = new WeakMap(); function define(id: string, seed: "none" | "ceo" | "morgan", extra: Partial = {}): ChatCatalogCase { return integratorDefinition("status-cards", id, async ctx => { @@ -149,18 +164,20 @@ function define(id: string, seed: "none" | "ceo" | "morgan", extra: Partial(`/api/issues/${t.id}`, id === "status-cards.explain-card" ? { status: "done", description: "The payment approval has been received; this blocker is resolved." } - : { description: "Payment approval has been received. The remaining blocker is the mobile Safari checkout regression." }); + : refreshedBlockerTaskInput()); } - return { project: p, sourceTasks, worker, card, otherCard, originalUpdates: await ctx.input.api.get(`/api/status-cards/${card.id}/updates`), originalSummaries: await ctx.input.api.get(`/api/status-cards/${card.id}/summary-revisions`) }; + const factualContextAttachment = ["status-cards.explain-card", "status-cards.archive-card"].includes(id) + ? await uploadFactualQueryAttachment(ctx, { filename: "selected-status-card.md", body: selectedStatusCardReference(card, sourceTasks, ctx.input.fixtures.company.issuePrefix) }) : undefined; + return { project: p, sourceTasks, worker, card, otherCard, factualContextAttachment, originalUpdates: await ctx.input.api.get(`/api/status-cards/${card.id}/updates`), originalSummaries: await ctx.input.api.get(`/api/status-cards/${card.id}/summary-revisions`) }; } catch (error) { await ctx.input.api.patch("/api/instance/settings/experimental", { enableStatusCards: previous.enableStatusCards }); experiments.delete(ctx); throw error; } }, observeCards, gradeIntegratorCards, verifyCard, { expectedRunCount: 2, attemptTimeoutMs: 540_000, ...extra, async cleanup(ctx) { await cleanupIdentityProbes(ctx); const previous = experiments.get(ctx); if (previous !== undefined) { await ctx.input.api.patch("/api/instance/settings/experimental", { enableStatusCards: previous }); experiments.delete(ctx); } } }); } export const integratorStatusCardsCases: readonly ChatCatalogCase[] = [ define("status-cards.create-card", "none"), - define("status-cards.archive-card", "ceo", { expectedRunCount: 3, attemptTimeoutMs: 720_000 }), + define("status-cards.archive-card", "ceo", { authentication: "human-session", queryAttachments: factualContextQueryAttachment("selected-status-card.md"), expectedRunCount: 3, attemptTimeoutMs: 720_000 }), define("status-cards.other-authors-card", "morgan"), - define("status-cards.explain-card", "ceo", { expectedRunCount: 3, expectedHumanMessageCount: 2, attemptTimeoutMs: 720_000, + define("status-cards.explain-card", "ceo", { authentication: "human-session", queryAttachments: factualContextQueryAttachment("selected-status-card.md"), expectedRunCount: 3, expectedHumanMessageCount: 2, attemptTimeoutMs: 720_000, sourceFiles: ["chat-catalog-domains/integrator-status-cards.ts", "chat-catalog-domains/identity-support.ts", "chat-catalog-domains/internal-definition.ts", "chat-catalog-domains/internal-support.ts", "chat-catalog-domains/integrator-support.ts", "chat-scenarios/status-cards.yaml"], async act(ctx, state) { const first = await pollUntil({ label: "accessible source explanation before actual access change", deadlineAt: Date.now() + 180_000, intervalMs: 1000, diff --git a/tests/runner-e2e/chat-query-attachments.test.ts b/tests/runner-e2e/chat-query-attachments.test.ts index 8cebeb5e888..241844dbf19 100644 --- a/tests/runner-e2e/chat-query-attachments.test.ts +++ b/tests/runner-e2e/chat-query-attachments.test.ts @@ -44,6 +44,7 @@ it("independently resolves declared receipt IDs and rejects undeclared, duplicat }); it.each([ + ["status-cards.explain-card", "selected-status-card.md"], ["status-cards.archive-card", "selected-status-card.md"], ["routines.webhook-trigger", "selected-routine.md"], ["developer-labs.gated-lab", "historical-lab-link.md"], ["documents-artifacts.resolve-feedback", "selected-source.md"], ["documents-artifacts.restore-document", "selected-source.md"], diff --git a/tests/runner-e2e/chat-query-attachments.ts b/tests/runner-e2e/chat-query-attachments.ts index 0c283f25580..ae2f704ccd5 100644 --- a/tests/runner-e2e/chat-query-attachments.ts +++ b/tests/runner-e2e/chat-query-attachments.ts @@ -21,6 +21,7 @@ const factualFiles: Readonly> = { "skills.author-skill": "skill-context.md", "skills.studio-test": "skill-context.md", "skills.review-update": "skill-context.md", "skills.find-and-install": "skill-context.md", "skills.fork-read-only": "skill-context.md", "connection-setup.secure-api-key": "provider-account.md", + "status-cards.explain-card": "selected-status-card.md", "status-cards.archive-card": "selected-status-card.md", "routines.webhook-trigger": "selected-routine.md", "cases.create-case": "customer-bug-brief.md", "app-permissions.ask-before-action": "launch-update.md", };