diff --git a/CHANGELOG.d/2.10.0-land-evidence-event-lineage.md b/CHANGELOG.d/2.10.0-land-evidence-event-lineage.md
new file mode 100644
index 00000000..a5a0f0fb
--- /dev/null
+++ b/CHANGELOG.d/2.10.0-land-evidence-event-lineage.md
@@ -0,0 +1,6 @@
+# 2.10.0 Land Event Lineage under the named evidence next action
+
+Open Public post from the landed Demo Corp members and Event Lineage
+for Linked post sits under the evidence next action, ahead of the
+input. Home list opens still keep a single Event Lineage on the
+opened post.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b6cc075d..2ada0f44 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,16 @@ 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.10.0] - 2026-08-17
+
+### Added
+
+- Opening Public post from the landed Demo Corp members now puts Event
+ Lineage for the cited Linked post immediately under the named
+ evidence next action, ahead of the chat input. Home list opens do
+ not add that section. No TEPP theta is invented. No cutoff body is
+ invented (ADR 0016).
+
## [2.9.0] - 2026-08-17
### Added
diff --git a/CLAUDE.md b/CLAUDE.md
index 1bcf5076..067c4e93 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -67,6 +67,8 @@ popup lands Ask about this lineage. After landed chat, the popup names
the first Ask. After that next action, the popup lands the first Ask
answer. After landed first Ask answer, the popup names the first
cited source. After that next action, the popup lands the first cited
-evidence. Changing the week first still
+evidence. After landed cited evidence, the popup names Event Lineage
+on that post. After that next action, the popup lands Event Lineage
+on the cited post. Changing the week first still
focuses the report period field. Mean θ stays on the period-report
panel.
diff --git a/frontend/package.json b/frontend/package.json
index c15e3db5..58489b34 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
- "version": "2.9.0",
+ "version": "2.10.0",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx
index ca589cdf..58c91087 100644
--- a/frontend/src/App.test.tsx
+++ b/frontend/src/App.test.tsx
@@ -1348,6 +1348,15 @@ describe("App, authenticated", () => {
}),
);
}
+ if (url.endsWith("/api/posts/post-2/lineage")) {
+ return Promise.resolve(
+ jsonResponse({
+ post_id: "post-2",
+ direct: [{ post_id: "post-1", post_title: "Public post" }],
+ indirect: [],
+ }),
+ );
+ }
if (url.endsWith("/api/posts/post-1/chat") && method === "GET") {
return Promise.resolve(
jsonResponse({
@@ -1506,6 +1515,7 @@ describe("App, authenticated", () => {
expect(screen.queryByRole("status", { name: "Ask citation next action" })).not.toBeInTheDocument();
expect(screen.queryByRole("status", { name: "Evidence next action" })).not.toBeInTheDocument();
expect(screen.queryByRole("complementary", { name: "Evidence" })).not.toBeInTheDocument();
+ expect(screen.queryByText("직접")).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");
@@ -2489,6 +2499,22 @@ describe("App, authenticated", () => {
expect(evidenceNext.compareDocumentPosition(askInput) & Node.DOCUMENT_POSITION_FOLLOWING).not.toBe(
0,
);
+ const lineageHeadings = within(popup as HTMLElement).getAllByRole("heading", {
+ name: "Event Lineage",
+ });
+ expect(lineageHeadings).toHaveLength(2);
+ const landedLineage = lineageHeadings[1];
+ expect(
+ evidenceNext.compareDocumentPosition(landedLineage) & Node.DOCUMENT_POSITION_FOLLOWING,
+ ).not.toBe(0);
+ expect(
+ landedLineage.compareDocumentPosition(askInput) & Node.DOCUMENT_POSITION_FOLLOWING,
+ ).not.toBe(0);
+ expect(landedLineage.compareDocumentPosition(affiliate) & Node.DOCUMENT_POSITION_FOLLOWING).not.toBe(
+ 0,
+ );
+ expect(await within(popup as HTMLElement).findByText("직접")).toBeInTheDocument();
+ expect(screen.getByText("직접").closest("li")).toHaveTextContent("Public post");
await waitFor(() => expect(document.getElementById("post-ask")).toHaveFocus());
} finally {
HTMLElement.prototype.scrollIntoView = originalScrollIntoView;
@@ -2670,7 +2696,10 @@ describe("App, authenticated", () => {
fetchMock.releaseMe();
expect(
await screen.findByRole("button", { name: "Request a lineage reconstruction" }),
- ).toBeEnabled();
+ ).toBeInTheDocument();
+ await waitFor(() =>
+ expect(screen.getByRole("button", { name: "Request a lineage reconstruction" })).toBeEnabled(),
+ );
expect(
await screen.findByRole("combobox", { name: "Corporate entity to reconstruct" }),
).toBeInTheDocument();
@@ -2864,6 +2893,17 @@ describe("App, authenticated", () => {
expect(await screen.findByRole("status", { name: "Evidence next action" })).toHaveTextContent(
"Linked post evidence is current. Read Event Lineage on that post next.",
);
+ const lineageHeadings = within(popup as HTMLElement).getAllByRole("heading", {
+ name: "Event Lineage",
+ });
+ expect(lineageHeadings).toHaveLength(2);
+ expect(
+ screen.getByRole("status", { name: "Evidence next action" }).compareDocumentPosition(
+ lineageHeadings[1],
+ ) & Node.DOCUMENT_POSITION_FOLLOWING,
+ ).not.toBe(0);
+ expect(await within(popup as HTMLElement).findByText("직접")).toBeInTheDocument();
+ expect(screen.getByText("직접").closest("li")).toHaveTextContent("Public post");
await waitFor(() => expect(document.getElementById("post-ask")).toHaveFocus());
});
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index afb493fd..34957ddc 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -165,10 +165,12 @@ function ChatPanel({
postId,
accessToken,
nameFirstAsk,
+ onSelectPost,
}: {
postId: string;
accessToken: string;
nameFirstAsk?: boolean;
+ onSelectPost?: (postId: string) => void;
}) {
const [question, setQuestion] = useState("");
const [exchanges, setExchanges] = useState
@@ -267,6 +295,19 @@ function ChatPanel({
{landedEvidenceNextAction(firstCitedTitle)}