From 8d9026fc67ec5c8f74e431091e9a333b59e5fde3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 15:25:54 +0900 Subject: [PATCH] feat: name Keyman and evaluation after the current Event Lineage node (v1.5.0) Opening Public post from Demo Corp members now names Keyman and evaluation after the current Event Lineage node. Home list opens do not add that copy. --- .../1.5.0-event-lineage-keyman-eval-next.md | 4 ++ CHANGELOG.md | 9 +++++ CLAUDE.md | 4 +- frontend/package.json | 2 +- frontend/src/App.test.tsx | 38 +++++++++++++++---- frontend/src/App.tsx | 14 +++++++ lineageweave/__init__.py | 2 +- pyproject.toml | 2 +- uv.lock | 2 +- 9 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 CHANGELOG.d/1.5.0-event-lineage-keyman-eval-next.md diff --git a/CHANGELOG.d/1.5.0-event-lineage-keyman-eval-next.md b/CHANGELOG.d/1.5.0-event-lineage-keyman-eval-next.md new file mode 100644 index 000000000..f047f5137 --- /dev/null +++ b/CHANGELOG.d/1.5.0-event-lineage-keyman-eval-next.md @@ -0,0 +1,4 @@ +# 1.5.0 Name Keyman and evaluation after the current Event Lineage node + +Open Public post from the landed Demo Corp members and the popup names +Keyman and evaluation after the current Event Lineage node. diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a0f85648..8860a5b58 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). +## [1.5.0] - 2026-08-17 + +### Added + +- Opening Public post from the landed Demo Corp members names the next + action after the current Event Lineage node: read Keyman and + evaluation. Home list opens do not add that copy. No TEPP theta is + invented. No cutoff body is invented (ADR 0016). + ## [1.4.0] - 2026-08-17 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index f73c15501..92725c1ae 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,6 +49,8 @@ mean θ. The period-report panel says Demo Corp is the opened grouping and to read its mean θ and member posts, then open a post. Those members land immediately under that next action, ahead of Other Corp and the week strip. Opening Public post names the next action: read -Event Lineage, Keyman, and evaluation on that post. Changing the week +Event Lineage, Keyman, and evaluation on that post. The popup Event +Lineage DAG marks that post current. After that current node, the +popup names Keyman and evaluation as the next read. 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 c29108ea1..8bc2c48e2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "1.4.0", + "version": "1.5.0", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index f96a80009..3aa56e4d3 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -1471,6 +1471,9 @@ describe("App, authenticated", () => { expect(screen.getAllByLabelText("A-100 lineage").length).toBeGreaterThanOrEqual(2); expect(screen.getAllByLabelText("Open post: Pricing renegotiation follow-up").length).toBeGreaterThanOrEqual(2); expect(document.getElementById("post-event-lineage")).not.toHaveFocus(); + expect( + screen.queryByRole("status", { name: "Event Lineage next action" }), + ).not.toBeInTheDocument(); }); it("shows a seeded Ask exchange without an orchestrator round-trip", async () => { @@ -2258,24 +2261,40 @@ describe("App, authenticated", () => { await userEvent.click(member); await waitFor(() => expect(screen.getByText("The full body text.")).toBeInTheDocument()); expect(member).toHaveAttribute("aria-current", "true"); - expect(screen.getByRole("status")).toHaveTextContent( - "Public post is open from Demo Corp. Read Event Lineage, Keyman, and evaluation on this post.", - ); - expect(screen.getByRole("status")).not.toHaveTextContent("then open a post"); + expect( + screen.getByText( + "Public post is open from Demo Corp. Read Event Lineage, Keyman, and evaluation on this post.", + ), + ).toBeInTheDocument(); + expect( + screen.getByText( + "Public post is open from Demo Corp. Read Event Lineage, Keyman, and evaluation on this post.", + ), + ).not.toHaveTextContent("then open a post"); expect( screen.getAllByRole("heading", { name: "Event Lineage" }).length, ).toBeGreaterThanOrEqual(2); expect(document.getElementById("post-event-lineage")).toHaveFocus(); const popup = document.querySelector(".popup-panel"); expect(popup).not.toBeNull(); - expect(within(popup as HTMLElement).getByLabelText("Open post: Public post")).toHaveAttribute( - "aria-current", - "true", - ); + const currentNode = within(popup as HTMLElement).getByLabelText("Open post: Public post"); + expect(currentNode).toHaveAttribute("aria-current", "true"); const homeNode = screen .getAllByLabelText("Open post: Public post") .find((node) => !popup?.contains(node)); expect(homeNode).not.toHaveAttribute("aria-current"); + const lineageNext = screen.getByRole("status", { name: "Event Lineage next action" }); + expect(lineageNext).toHaveTextContent( + "Public post is current in Event Lineage. Read Keyman and evaluation next.", + ); + expect( + currentNode.compareDocumentPosition(lineageNext) & Node.DOCUMENT_POSITION_FOLLOWING, + ).not.toBe(0); + expect( + lineageNext.compareDocumentPosition( + within(popup as HTMLElement).getByRole("heading", { name: "Keyman" }), + ) & Node.DOCUMENT_POSITION_FOLLOWING, + ).not.toBe(0); } finally { HTMLElement.prototype.scrollIntoView = originalScrollIntoView; } @@ -2540,6 +2559,9 @@ describe("App, authenticated", () => { expect(screen.getAllByText(/Ada West/).length).toBeGreaterThan(0); expect(screen.getAllByLabelText("A-100 lineage").length).toBeGreaterThanOrEqual(2); expect(document.getElementById("post-event-lineage")).toHaveFocus(); + expect(screen.getByRole("status", { name: "Event Lineage next action" })).toHaveTextContent( + "Public post is current in Event Lineage. Read Keyman and evaluation next.", + ); }); it("lets post_admin rebuild the period report", async () => { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 81f2173b8..d0de5ce18 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -271,16 +271,22 @@ function ChatPanel({ postId, accessToken }: { postId: string; accessToken: strin ); } +function eventLineageCurrentNextAction(postTitle: string): string { + return `${postTitle} is current in Event Lineage. Read Keyman and evaluation next.`; +} + function EventLineageSection({ lineage, graph, postId, onSelectPost, + currentNextAction, }: { lineage: PostLineage | null; graph: LineageGraph | null; postId: string; onSelectPost?: (postId: string) => void; + currentNextAction?: string | null; }) { if (!lineage) return

Loading lineage...

; const scoped = graph ? subgraphForPost(graph, postId) : { nodes: [], edges: [] }; @@ -305,6 +311,11 @@ function EventLineageSection({ {scoped.nodes.length > 0 && onSelectPost && ( )} + {scoped.nodes.length > 0 && currentNextAction ? ( +

+ {currentNextAction} +

+ ) : null} {hasLinks && (