From c3a2f550f6dbced165c169af2aaaf407a05e5fa2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 12:57:43 +0900 Subject: [PATCH] feat: land Demo Corp members under the opened-report next action (v1.1.0) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After Open period report names the next action, Demo Corp mean θ and member posts land immediately below it, ahead of Other Corp and the week strip. --- ....1.0-analysis-run-opened-report-members.md | 5 + CHANGELOG.md | 10 ++ CLAUDE.md | 7 +- .../0024-seed-period-report-analysis-run.md | 7 +- frontend/package.json | 2 +- frontend/src/App.test.tsx | 30 +++- frontend/src/App.tsx | 162 ++++++++++-------- lineageweave/__init__.py | 2 +- pyproject.toml | 2 +- uv.lock | 2 +- 10 files changed, 149 insertions(+), 80 deletions(-) create mode 100644 CHANGELOG.d/1.1.0-analysis-run-opened-report-members.md diff --git a/CHANGELOG.d/1.1.0-analysis-run-opened-report-members.md b/CHANGELOG.d/1.1.0-analysis-run-opened-report-members.md new file mode 100644 index 000000000..d4a9b2c02 --- /dev/null +++ b/CHANGELOG.d/1.1.0-analysis-run-opened-report-members.md @@ -0,0 +1,5 @@ +# 1.1.0 Land Demo Corp members under the opened-report next action + +Open period report 2026-W02 puts Demo Corp mean θ and member posts +immediately under the next action, ahead of Other Corp. Mean θ stays +on the report panel. diff --git a/CHANGELOG.md b/CHANGELOG.md index bd9a3aa06..0aa82319b 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). +## [1.1.0] - 2026-08-17 + +### Added + +- Opening **Open period report 2026-W02** now puts the Demo Corp + report (mean θ and member posts) immediately under the named next + action, ahead of Other Corp and the week strip. The Public post + member stays clickable. Mean θ stays on the report panel. No TEPP + theta is invented. No cutoff body is invented (ADR 0016). + ## [1.0.0] - 2026-08-17 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index 4f9b0b182..a9b7bfd7c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -46,6 +46,7 @@ then **Open period report 2026-W02**. The home week is already grouping is Corporate entity and Demo Corp is current. The focused chip name contains `Corporate entity: Demo Corp` and the persisted mean θ. The period-report panel says Demo Corp is the opened grouping -and to read its mean θ and member posts, then open a post. Changing -the week first still focuses the report period field. Mean θ stays on -the period-report panel. +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. Changing the week first still focuses the report +period field. Mean θ stays on the period-report panel. diff --git a/docs/adr/0024-seed-period-report-analysis-run.md b/docs/adr/0024-seed-period-report-analysis-run.md index 9e824e7e0..3a8e29c09 100644 --- a/docs/adr/0024-seed-period-report-analysis-run.md +++ b/docs/adr/0024-seed-period-report-analysis-run.md @@ -53,9 +53,10 @@ current, using the persisted scope grouping key. When the operator is already on that week, the comparison strip lands on Demo Corp. The focused chip name contains the visible Corporate entity caption and the persisted mean θ. The period-report panel names the next action: -read that grouping's mean θ and member posts, then open a post. Mean θ -remains on the period-report panel. Re-seed is idempotent on -`demo-report-seed-2026-w02`. +read that grouping's mean θ and member posts, then open a post. Those +members land immediately under that next action, ahead of other +groupings and the week strip. Mean θ remains on the period-report +panel. Re-seed is idempotent on `demo-report-seed-2026-w02`. ## References — APA 7th diff --git a/frontend/package.json b/frontend/package.json index 30a383f95..17ae5ab37 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "1.0.0", + "version": "1.1.0", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index e0335f531..fbb93620e 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -1,4 +1,4 @@ -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { fireEvent, render, screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import App from "./App"; @@ -2191,6 +2191,16 @@ describe("App, authenticated", () => { ); expect(await screen.findByText(/Demo Corp: mean θ 0\.42/)).toBeInTheDocument(); expect(screen.queryByText(/corp-1: mean θ/)).not.toBeInTheDocument(); + const openedReport = screen.getByRole("list", { name: "Opened grouping report" }); + expect(openedReport.textContent ?? "").toMatch(/Demo Corp: mean θ 0\.42[\s\S]*Other Corp: mean θ/); + expect( + within(openedReport).getByRole("button", { name: /open report post: public post/i }), + ).toBeInTheDocument(); + const status = screen.getByRole("status"); + const demoMean = screen.getByText(/Demo Corp: mean θ 0\.42/); + const weekChip = screen.getByRole("button", { name: /open report period 2026-W03/i }); + expect(status.compareDocumentPosition(demoMean) & Node.DOCUMENT_POSITION_FOLLOWING).not.toBe(0); + expect(demoMean.compareDocumentPosition(weekChip) & Node.DOCUMENT_POSITION_FOLLOWING).not.toBe(0); }); it("lands the comparison strip on Demo Corp when already on that week", async () => { @@ -2227,6 +2237,24 @@ describe("App, authenticated", () => { "Demo Corp is the opened grouping. Read its mean θ and member posts below, then open a post.", ); expect(await screen.findByText(/Demo Corp: mean θ 0\.42/)).toBeInTheDocument(); + const openedReport = screen.getByRole("list", { name: "Opened grouping report" }); + expect(within(openedReport).getByText(/Demo Corp: mean θ 0\.42/).closest("li")).toHaveAttribute( + "aria-current", + "true", + ); + expect(openedReport.textContent ?? "").toMatch(/Demo Corp: mean θ 0\.42[\s\S]*Other Corp: mean θ/); + expect(openedReport.textContent ?? "").not.toMatch(/Other Corp: mean θ[\s\S]*Demo Corp: mean θ 0\.42/); + const member = within(openedReport).getByRole("button", { + name: /open report post: public post/i, + }); + expect(member).toHaveTextContent("θ 0.91"); + const status = screen.getByRole("status"); + const demoMean = screen.getByText(/Demo Corp: mean θ 0\.42/); + const weekChip = screen.getByRole("button", { name: /open report period 2026-W03/i }); + expect(status.compareDocumentPosition(demoMean) & Node.DOCUMENT_POSITION_FOLLOWING).not.toBe(0); + expect(demoMean.compareDocumentPosition(weekChip) & Node.DOCUMENT_POSITION_FOLLOWING).not.toBe(0); + await userEvent.click(member); + await waitFor(() => expect(screen.getByText("The full body text.")).toBeInTheDocument()); } finally { HTMLElement.prototype.scrollIntoView = originalScrollIntoView; } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 921959e03..63eb0fc32 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -2116,6 +2116,18 @@ function openedReportNextAction(groupingLabel: string): string { ); } +function openedReportsFirst( + reports: T[], + isOpened: (groupingKey: string, groupingLabel?: string) => boolean, +): T[] { + const opened = reports.filter((report) => isOpened(report.grouping_key, report.grouping_label)); + if (opened.length === 0) { + return reports; + } + const rest = reports.filter((report) => !isOpened(report.grouping_key, report.grouping_label)); + return [...opened, ...rest]; +} + function ReportsPanel({ accessToken, canRebuild, @@ -2205,6 +2217,85 @@ function ReportsPanel({ } } + const orderedReports = payload + ? openedReportsFirst(payload.reports, (groupingKey, groupingLabel) => + groupingIsOpened(grouping, groupingKey, groupingLabel), + ) + : []; + const reportList = + payload === null && !error ? ( +

Loading reports...

+ ) : payload && payload.reports.length === 0 ? ( +

+ No calibrated report for this grouping and period. Evaluate posts, then rebuild. +

+ ) : payload && payload.reports.length > 0 ? ( + + ) : null; + return (
@@ -2275,6 +2366,7 @@ function ReportsPanel({ {openedReportNextAction(openedGroupingLabel)}

)} + {openedGroupingLabel && reportList} {index && index.periods.length > 0 && (
    {index.periods.map((row) => ( @@ -2306,75 +2398,7 @@ function ReportsPanel({
)} {error &&

{error}

} - {payload === null && !error &&

Loading reports...

} - {payload && payload.reports.length === 0 && ( -

- No calibrated report for this grouping and period. Evaluate posts, then rebuild. -

- )} - {payload && payload.reports.length > 0 && ( -
    - {payload.reports.map((report) => ( -
  • - - {report.grouping_label ?? report.grouping_key}: mean θ {report.mean_theta.toFixed(2)} ({report.selected_model} - {report.fit_converged ? ", converged" : ", not converged"}) - - {report.post_count} posts - {report.link_method === "fipc" && report.anchor_period_code && report.delta_mean_theta != null && ( - - vs {report.anchor_period_code}: {report.delta_mean_theta >= 0 ? "+" : ""} - {report.delta_mean_theta.toFixed(2)} - - )} - {report.link_method === "fipc" && report.delta_mean_theta == null && ( - shared metric - )} - {report.selected_items?.[0] && ( - - CAT: {criterionShortLabel(report.selected_items[0].item_code)} I= - {report.selected_items[0].information.toFixed(2)} - - )} - {report.members.length > 0 && ( -
      - {report.members.map((member) => ( -
    • - -
    • - ))} -
    - )} -
  • - ))} -
- )} + {!openedGroupingLabel && reportList}
); } diff --git a/lineageweave/__init__.py b/lineageweave/__init__.py index 107bfdb6f..fc6a0d643 100644 --- a/lineageweave/__init__.py +++ b/lineageweave/__init__.py @@ -55,4 +55,4 @@ "sentence_excerpts", ] -__version__ = "1.0.0" +__version__ = "1.1.0" diff --git a/pyproject.toml b/pyproject.toml index 6510d6e3b..9b7dfcb69 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "lineageweave" -version = "1.0.0" +version = "1.1.0" description = "Reconstructs git-branch-style lineage DAGs from scattered short records using multi-channel score fusion and LLM adjudication." readme = "README.md" license = { text = "MIT" } diff --git a/uv.lock b/uv.lock index 7ea52e063..e407904ca 100644 --- a/uv.lock +++ b/uv.lock @@ -454,7 +454,7 @@ wheels = [ [[package]] name = "lineageweave" -version = "1.0.0" +version = "1.1.0" source = { virtual = "." } dependencies = [ { name = "certifi" },