fix(evals): display existing campaign summary inline

This commit is contained in:
Dotta committed 2026-10-27 13:35:34 -05:00
1 parent b3c77ff304
commit 2f68f4ff3c
3 files changed
+29 -1

No files matched your search

+1
View File
@@ -175,6 +175,7 @@ export async function regenerateRunnerDashboard(input: {
entries,
campaign,
summaryAvailable: summary !== undefined,
summaryText: summary,
history,
});
const upgraded = {
@@ -22,11 +22,32 @@ it("regeneration derives link availability from the actual summary file without
await regenerateRunnerDashboard({ bundle: root, historyFile: null });
const html = await readFile(path.join(root, "index.html"), "utf8");
expect(html).toContain('href="summary.md"'); expect(html).toContain(before.source.workflowRunUrl);
expect(html).toContain('<summary>Campaign notes and coverage</summary>');
expect(html).toContain('Six incomplete or blocked journeys.');
const after = JSON.parse(await readFile(path.join(root, "normalized-results.json"), "utf8"));
expect(after.results).toEqual(before.results); expect(after.source).toEqual(before.source);
expect(after.selected).toBe(before.selected);
await rm(path.join(root, "summary.md"));
await regenerateRunnerDashboard({ bundle: root, historyFile: null });
expect(await readFile(path.join(root, "index.html"), "utf8")).not.toContain('href="summary.md"');
const withoutSummary = await readFile(path.join(root, "index.html"), "utf8");
expect(withoutSummary).not.toContain('href="summary.md"');
expect(withoutSummary).not.toContain('<summary>Campaign notes and coverage</summary>');
} finally { await rm(root, { recursive: true, force: true }); }
});
it("keeps coverage prose separate from measured counts and escapes untrusted summary markup", () => {
const summaryText = '# Current coverage\n0 passes, 1 failed initial, 243 unrun\n\n- tasks.create-backlog\n<script>alert(1)</script>\n[unsafe](javascript:alert(1))\n<img src=x onerror=alert(2)> & private-looking text';
const input = { title: "Campaign", generatedAt: "2026-10-27T00:00:00Z", expected: [], catalog: [], entries: [], campaign: campaign(), summaryText };
const output = renderRunnerE2EDashboard(input);
expect(output).toContain('0 passes, 1 failed initial, 243 unrun');
expect(output).toContain('tasks.create-backlog');
expect(output).toContain('&lt;script&gt;alert(1)&lt;/script&gt;');
expect(output).toContain('&lt;img src=x onerror=alert(2)&gt; &amp; private-looking text');
expect(output).not.toContain('<script>alert(1)</script>');
expect(output).not.toContain('<img src=x');
expect(output).not.toContain('href="javascript:');
expect(output).toContain('<strong>0/0</strong>');
expect(input.campaign.selected).toBe(0);
expect(renderRunnerE2EDashboard({ ...input, campaign: undefined })).not.toContain('<summary>Campaign notes and coverage</summary>');
expect(renderRunnerE2EDashboard({ ...input, summaryText: " " })).not.toContain('<summary>Campaign notes and coverage</summary>');
});
+6
View File
@@ -46,6 +46,8 @@ export interface RunnerDashboardInput {
campaign?: RunnerE2ECampaign;
/** The bundle contains its existing relative summary.md document. */
summaryAvailable?: boolean;
/** Existing public summary.md content, rendered only as escaped readable text. */
summaryText?: string;
history?: RunnerE2EHistoryIndex;
}
@@ -532,6 +534,9 @@ export function renderRunnerE2EDashboard(input: RunnerDashboardInput) {
h1 { max-width: 760px; margin: 0; font-size: clamp(32px, 4vw, 56px); font-weight: 650; line-height: 1.03; letter-spacing: -.04em; }
.lede { max-width: 720px; margin: 16px 0 0; color: var(--muted-foreground); font-size: 16px; }
.report-actions { display: flex; align-items: stretch; gap: 8px; }
.campaign-notes { margin: 0 0 24px; }
.campaign-notes > summary { cursor: pointer; font-weight: 600; }
.campaign-notes pre { white-space: pre-wrap; overflow-wrap: anywhere; font: inherit; line-height: 1.6; }
.summary { display: flex; border: 1px solid var(--border); border-radius: var(--radius); background: var(--card); }
.metric { min-width: 108px; padding: 13px 16px; border-right: 1px solid var(--border); }
.metric:last-child { border-right: 0; }
@@ -849,6 +854,7 @@ export function renderRunnerE2EDashboard(input: RunnerDashboardInput) {
<button class="gallery-launch" type="button" data-gallery-open ${screenshotCount === 0 ? "disabled" : ""}>${screenshotCount === 0 ? "Visual evidence · workflow artifact only" : `View gallery · ${screenshotCount}`}</button>
</div>
</header>
${input.campaign && input.summaryText?.trim() ? `<details class="campaign-notes" open><summary>Campaign notes and coverage</summary><pre>${html(input.summaryText)}</pre></details>` : ""}
${renderCampaignSuiteSummary(input.campaign?.suites ?? [], catalog, "", false)}
<details class="campaign-billing-details"><summary>Campaign usage and spend</summary>
<section class="billing-overview" aria-label="Campaign billing summary">