diff --git a/CHANGELOG.d/2.7.0-name-first-cited-after-ask-answer.md b/CHANGELOG.d/2.7.0-name-first-cited-after-ask-answer.md new file mode 100644 index 00000000..93d454ce --- /dev/null +++ b/CHANGELOG.d/2.7.0-name-first-cited-after-ask-answer.md @@ -0,0 +1,5 @@ +# 2.7.0 Name the first cited source after the landed Ask answer + +Open Public post from the landed Demo Corp members and the first +cited source on the landed Ask answer is named. Home list opens do +not. diff --git a/CHANGELOG.md b/CHANGELOG.md index e4a3c9ab..29fdb26e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to this project are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.7.0] - 2026-08-17 + +### Added + +- Opening Public post from the landed Demo Corp members now names the + first cited source after the landed first Ask answer: Linked post, + then open that evidence. Home list opens do not add that copy. No + TEPP theta is invented. No cutoff body is invented (ADR 0016). + ## [2.6.0] - 2026-08-17 ### Added diff --git a/frontend/package.json b/frontend/package.json index 1ddeeb39..0f6b4069 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "2.6.0", + "version": "2.7.0", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 53a8fab1..dca4697e 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -1491,6 +1491,7 @@ describe("App, authenticated", () => { expect(screen.queryByRole("status", { name: "Related next action" })).not.toBeInTheDocument(); expect(screen.queryByRole("status", { name: "Ask next action" })).not.toBeInTheDocument(); expect(screen.queryByRole("status", { name: "Ask seed next action" })).not.toBeInTheDocument(); + expect(screen.queryByRole("status", { name: "Ask citation next action" })).not.toBeInTheDocument(); expect(screen.queryByText("Related to Ada West")).not.toBeInTheDocument(); expect(screen.queryByText("Related to Priya Nair")).not.toBeInTheDocument(); const popup = document.querySelector(".popup-panel"); @@ -2425,6 +2426,19 @@ describe("App, authenticated", () => { expect( within(popup as HTMLElement).getAllByText("The seeded follow-up after the site visit."), ).toHaveLength(1); + const citedNext = await screen.findByRole("status", { name: "Ask citation next action" }); + expect(citedNext).toHaveTextContent( + "Linked post is the first cited source. Open that evidence next.", + ); + expect( + firstAskAnswer.compareDocumentPosition(citedNext) & Node.DOCUMENT_POSITION_FOLLOWING, + ).not.toBe(0); + expect(citedNext.compareDocumentPosition(askInput) & Node.DOCUMENT_POSITION_FOLLOWING).not.toBe( + 0, + ); + expect( + within(popup as HTMLElement).getByRole("button", { name: "Open evidence: Linked post" }), + ).toHaveAttribute("aria-current", "true"); await waitFor(() => expect(document.getElementById("post-ask")).toHaveFocus()); } finally { HTMLElement.prototype.scrollIntoView = originalScrollIntoView; @@ -2723,6 +2737,9 @@ describe("App, authenticated", () => { expect(firstAskAnswer.compareDocumentPosition(affiliate) & Node.DOCUMENT_POSITION_FOLLOWING).not.toBe( 0, ); + expect(await screen.findByRole("status", { name: "Ask citation next action" })).toHaveTextContent( + "Linked post is the first cited source. Open that evidence next.", + ); await waitFor(() => expect(document.getElementById("post-ask")).toHaveFocus()); }); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 4c53b73a..f8aa35db 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -133,10 +133,12 @@ function ChatCitations({ citedPosts, citedPostIds, onOpenEvidence, + currentPostId, }: { citedPosts?: { post_id: string; post_title: string }[]; citedPostIds: string[]; onOpenEvidence: (postId: string) => void; + currentPostId?: string; }) { if ((citedPosts?.length ?? citedPostIds.length) === 0) return null; const chips = @@ -150,6 +152,7 @@ function ChatCitations({ postId={cited.post_id} postTitle={cited.post_title} onOpenEvidence={onOpenEvidence} + current={cited.post_id === currentPostId} /> ))} @@ -209,6 +212,10 @@ function ChatPanel({ } } + const firstCitedTitle = + exchanges[0]?.cited_posts?.[0]?.post_title ?? + (exchanges[0]?.cited_post_ids[0] ? exchanges[0].cited_post_ids[0].slice(0, 8) : null); + return (

@@ -227,9 +234,17 @@ function ChatPanel({ citedPosts={exchanges[0].cited_posts} citedPostIds={exchanges[0].cited_post_ids} onOpenEvidence={setEvidencePostId} + currentPostId={ + exchanges[0].cited_posts?.[0]?.post_id ?? exchanges[0].cited_post_ids[0] + } /> ) : null} + {nameFirstAsk && firstCitedTitle ? ( +

+ {firstCitedNextAction(firstCitedTitle)} +

+ ) : null} {!seededOnly && (
void; + current?: boolean; }; /** @@ -13,12 +14,14 @@ export function CitationChip({ postId, postTitle, onOpenEvidence, + current, }: CitationChipProps) { return (