From 32b09a72acb4046dcbcbfb5850b99dd61e55b3fe Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 10:41:27 +0900 Subject: [PATCH] feat: land the comparison strip on the opened Demo Corp row (v0.99.0) When the operator is already on 2026-W02, Open period report focuses the Demo Corp comparison chip instead of the unchanged period field. --- ...0-analysis-run-comparison-strip-landing.md | 4 ++ CHANGELOG.md | 10 +++++ CLAUDE.md | 8 ++-- .../0024-seed-period-report-analysis-run.md | 5 ++- frontend/package.json | 2 +- frontend/src/App.test.tsx | 32 +++++++++++++++ frontend/src/App.tsx | 39 ++++++++++++++++++- lineageweave/__init__.py | 2 +- pyproject.toml | 2 +- uv.lock | 2 +- 10 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 CHANGELOG.d/0.99.0-analysis-run-comparison-strip-landing.md diff --git a/CHANGELOG.d/0.99.0-analysis-run-comparison-strip-landing.md b/CHANGELOG.d/0.99.0-analysis-run-comparison-strip-landing.md new file mode 100644 index 000000000..1b3df70fd --- /dev/null +++ b/CHANGELOG.d/0.99.0-analysis-run-comparison-strip-landing.md @@ -0,0 +1,4 @@ +# 0.99.0 Land the comparison strip on the opened Demo Corp row + +Open period report 2026-W02 when already on that week. The grouping +comparison strip lands on Demo Corp. Mean θ stays on the report panel. diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cec99dfa..328aec876 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). +## [0.99.0] - 2026-08-17 + +### Added + +- Opening **Open period report 2026-W02** when the operator is already + on that week lands the grouping comparison strip on Demo Corp. The + Demo Corp chip is current and focused. Changing the week still + focuses the report period field. Mean θ stays on the report panel. + No TEPP theta is invented. + ## [0.98.1] - 2026-08-17 ### Fixed diff --git a/CLAUDE.md b/CLAUDE.md index 5d246f6ac..239d659f2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,6 +41,8 @@ envelope is Failed. Failed TEPP is terminal — request a new run, then start. Do not invent a theta. Hover the Result prefix to read the parent-choice digest. After `make seed`, open **Period report · Succeeded · Demo Corp**, -then **Open period report 2026-W02**. The report period field is -focused. Report grouping is Corporate entity and Demo Corp is current. -Mean θ stays on the period-report panel. +then **Open period report 2026-W02**. The home week is already +2026-W02, so the grouping comparison strip lands on Demo Corp. Report +grouping is Corporate entity and Demo Corp is current. 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 a392de46f..eac3ad477 100644 --- a/docs/adr/0024-seed-period-report-analysis-run.md +++ b/docs/adr/0024-seed-period-report-analysis-run.md @@ -49,8 +49,9 @@ After `make seed`, Demo Analyst opens Analysis runs and sees rows. Opening it shows the cutoff posts and **Open period report 2026-W02** (the week stored on `scope_key`). That click also switches Report grouping to Corporate entity and marks the Demo Corp grouping -current, using the persisted scope grouping key. Mean θ remains on -the period-report panel. Re-seed is idempotent on +current, using the persisted scope grouping key. When the operator is +already on that week, the comparison strip lands on Demo Corp. 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 9385e34e0..7095b7fc7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "0.98.1", + "version": "0.99.0", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 55d7b24b6..ee9d00ea5 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -2190,6 +2190,38 @@ describe("App, authenticated", () => { expect(screen.queryByText(/corp-1: mean θ/)).not.toBeInTheDocument(); }); + it("lands the comparison strip on Demo Corp when already on that week", async () => { + stubBackend({ succeededReportRun: true }); + const scrollIntoView = vi.fn(); + const originalScrollIntoView = HTMLElement.prototype.scrollIntoView; + HTMLElement.prototype.scrollIntoView = scrollIntoView; + try { + render(); + + const periodInput = await screen.findByLabelText("Report period"); + expect(periodInput).toHaveValue("2026-W02"); + expect(screen.getByLabelText("Report grouping")).toHaveValue("process_unit"); + + await userEvent.click( + await screen.findByRole("button", { + name: "Open analysis run: Period report · Succeeded · Demo Corp", + }), + ); + await userEvent.click(screen.getByRole("button", { name: "Open period report 2026-W02" })); + + expect(periodInput).toHaveValue("2026-W02"); + expect(screen.getByLabelText("Report grouping")).toHaveValue("corporate_entity"); + const demoChip = screen.getByRole("button", { name: "Compare corporate_entity: Demo Corp" }); + expect(demoChip).toHaveAttribute("aria-current", "true"); + expect(demoChip).toHaveFocus(); + expect(scrollIntoView).toHaveBeenCalled(); + expect(periodInput).not.toHaveFocus(); + expect(await screen.findByText(/Demo Corp: mean θ 0\.42/)).toBeInTheDocument(); + } finally { + HTMLElement.prototype.scrollIntoView = originalScrollIntoView; + } + }); + it("does not tell a failed period report to connect the measurement service", async () => { stubBackend({ failedReportRun: true }); render(); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 570355774..7c9b02229 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1742,10 +1742,12 @@ function analysisRunPostOpenOptions(run: AnalysisRun, postId: string): SelectPos function AnalysisRunsPanel({ accessToken, + currentReportPeriod, onSelectPost, onSelectReportPeriod, }: { accessToken: string; + currentReportPeriod?: string; onSelectPost: (postId: string, options?: SelectPostOptions) => void; onSelectReportPeriod?: ( periodCode: string, @@ -1930,13 +1932,16 @@ function AnalysisRunsPanel({ onClick={() => { const periodCode = analysisRunReportPeriod(selected); if (periodCode) { + const alreadyOnWeek = currentReportPeriod === periodCode; onSelectReportPeriod( periodCode, analysisRunReportGrouping(selected) ?? undefined, analysisRunReportGroupingKey(selected), selected.scope_entity_name, ); - document.getElementById("report-period")?.focus(); + if (!alreadyOnWeek) { + document.getElementById("report-period")?.focus(); + } } }} > @@ -2098,6 +2103,7 @@ function ReportsPanel({ openedGroupingKey, openedGroupingLabel, onOpenGrouping, + landOnComparison, }: { accessToken: string; canRebuild: boolean; @@ -2109,12 +2115,14 @@ function ReportsPanel({ openedGroupingKey?: string | null; openedGroupingLabel?: string | null; onOpenGrouping?: (groupingKey: string, groupingLabel: string) => void; + landOnComparison?: boolean; }) { const [payload, setPayload] = useState(null); const [index, setIndex] = useState(null); const [comparison, setComparison] = useState(null); const [error, setError] = useState(null); const [rebuilding, setRebuilding] = useState(false); + const openedComparisonRef = useRef(null); const groupingLabels: Record = { process_unit: "Process unit", @@ -2147,6 +2155,18 @@ function ReportsPanel({ .catch((err) => setError(String(err))); }, [accessToken, grouping, period]); + useEffect(() => { + if (!landOnComparison) { + return; + } + const current = openedComparisonRef.current; + if (!current) { + return; + } + current.scrollIntoView({ block: "nearest" }); + current.focus(); + }, [landOnComparison, grouping, openedGroupingKey, openedGroupingLabel, comparison]); + async function handleRebuild() { setRebuilding(true); setError(null); @@ -2202,6 +2222,11 @@ function ReportsPanel({