From ac7eada56eb88f973a0e45b863a1edbd33529517 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 16 Aug 2026 16:18:10 +0000 Subject: [PATCH] fix(ui): pin pending next-action copy to registered kinds Pending lineage detail now repeats that reconstruction has not started. Pending TEPP rows no longer reuse the reconstruction sentence. Co-authored-by: Seongho Bae --- ARCHITECTURE.md | 3 +- .../0.86.0-related-nodes-team-org-walk.md | 3 +- CHANGELOG.md | 6 ++ CLAUDE.md | 3 +- docs/adr/0014-authorized-analysis-run-read.md | 3 +- frontend/src/App.test.tsx | 7 ++- frontend/src/App.tsx | 56 +++++++++++++------ 7 files changed, 59 insertions(+), 22 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index b66c7cde7..3a4d0ac4a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -491,7 +491,8 @@ measurement service) so `tepp_not_available` is not mistaken for a calibrated negative result. A failed lineage row tells the operator to retry reconstruction, not to connect TEPP. A failed period-report row tells the operator to rebuild the report. A pending TEPP row -does not claim a calibrated measurement. The +does not claim a calibrated measurement. A pending lineage row +says reconstruction has not started yet. The payload is lookup labels plus non-negative aggregate counts -- never source SQL, a DSN, a raw record, or a provider body. After `make seed`, Demo Analyst and Demo Admin see "Lineage reconstruction · Succeeded · diff --git a/CHANGELOG.d/0.86.0-related-nodes-team-org-walk.md b/CHANGELOG.d/0.86.0-related-nodes-team-org-walk.md index 4989a054f..6e4605d5a 100644 --- a/CHANGELOG.d/0.86.0-related-nodes-team-org-walk.md +++ b/CHANGELOG.d/0.86.0-related-nodes-team-org-walk.md @@ -1,4 +1,5 @@ Related-node walks include team and organization mention edges. Click an R&R team to open sibling posts. Thread-group run lists honor knowledge_cutoff. Failed period-report rows rebuild the report; a pending TEPP corpus -does not claim a calibrated measurement. +does not claim a calibrated measurement. A pending lineage row says +reconstruction has not started yet. diff --git a/CHANGELOG.md b/CHANGELOG.md index 13aeb02f9..d30ae14aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,12 @@ All notable changes to this project are documented here. Format follows whose body includes a data-URI image shows the picture; Extract Keyman or Ask still runs OCR on that image for search. +### Fixed + +- Opening a Pending lineage run repeats that reconstruction has not + started. Pending next-action copy is pinned to the registered run + kinds, so a Pending TEPP row does not say reconstruction. + ## [0.86.0] - 2026-08-16 ### Added diff --git a/CLAUDE.md b/CLAUDE.md index a11127584..c5a1828f2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,7 +14,8 @@ theta or a local psychometric substitute. The home list caption stays (ADR 0014). Open a Failed TEPP row, then connect a live TEPP transport. A failed lineage row retries reconstruction -- it does not mention TEPP. A failed period-report row rebuilds the report. A -pending TEPP row does not claim a calibrated measurement. +pending TEPP row does not claim a calibrated measurement. A pending +lineage row says reconstruction has not started yet. Digest prefixes stay audible; hover a prefix to read the full digest. Opening a cutoff title shows the live post -- compare it with the cutoff before treating the body as reconstructed evidence (ADR 0016). diff --git a/docs/adr/0014-authorized-analysis-run-read.md b/docs/adr/0014-authorized-analysis-run-read.md index 29c074c8f..500c2bc2a 100644 --- a/docs/adr/0014-authorized-analysis-run-read.md +++ b/docs/adr/0014-authorized-analysis-run-read.md @@ -48,7 +48,8 @@ service. A failed lineage row tells the operator to retry reconstruction, not to connect TEPP. A failed period-report row tells the operator to rebuild the report from a current snapshot. A pending or running TEPP row must not claim a calibrated -measurement. The detail now shows the legal +measurement. A pending lineage row says reconstruction has not +started yet. The detail now shows the legal lifecycle the registry already stored. `POST /api/analysis-runs` now records a Pending run on an authorized cutoff capture (ADR 0017). Reconstruction, a live TEPP transport, and a fuller Analysis Run diff --git a/frontend/src/App.test.tsx b/frontend/src/App.test.tsx index 65d25259b..60d06c8de 100644 --- a/frontend/src/App.test.tsx +++ b/frontend/src/App.test.tsx @@ -1772,6 +1772,7 @@ describe("App, authenticated", () => { ).toBeInTheDocument(); expect(screen.queryByText(/replace Failed/i)).not.toBeInTheDocument(); expect(screen.queryByText(/this TEPP run measured/i)).not.toBeInTheDocument(); + expect(screen.queryByText(/Reconstruction has not started yet/)).not.toBeInTheDocument(); }); it("does not tell a succeeded TEPP run to replace Failed", async () => { @@ -1799,7 +1800,11 @@ describe("App, authenticated", () => { expect( await screen.findByRole("heading", { name: "Lineage reconstruction · Pending · Demo Corp" }), ).toBeInTheDocument(); - expect(screen.getByText(/has not started yet/)).toBeInTheDocument(); + expect( + screen.getByText( + "Open this run to confirm which posts it will use. Reconstruction has not started yet.", + ), + ).toBeInTheDocument(); const postCall = fetchMock.mock.calls.find( (call) => String(call[0]).endsWith("/api/analysis-runs") && call[1]?.method === "POST", ); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index a511f713d..d589a3644 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1451,28 +1451,48 @@ function analysisRunCaption(run: AnalysisRun): string { } /** - * Next action for a failed run on the home list. + * Next action for a pending or failed run on the home list and detail. * * The machine `failure_code` stays on detail history (ADR 0014). Copy - * is kind-specific so a failed lineage reconstruction is not mistaken - * for a missing TEPP transport. + * is pinned to registered kinds so a pending TEPP row is not mistaken + * for reconstruction, and a failed lineage row is not mistaken for a + * missing TEPP transport. */ function analysisRunNextAction(run: AnalysisRun): string | null { - if (run.status_code === "analysis_status_pending") { - return "Open this run to confirm which posts it will use. Reconstruction has not started yet."; - } - if (run.status_code !== "analysis_status_failed") { - return null; - } - switch (run.run_kind_code) { - case "analysis_run_tepp": - return "Open this run to see why it failed, then connect the measurement service and re-run."; - case "analysis_run_lineage": - return "Open this run to see why it failed, then retry reconstruction from a current snapshot."; - case "analysis_run_report": - return "Open this run to see why it failed, then rebuild the period report from a current snapshot."; + switch (run.status_code) { + case "analysis_status_pending": + switch (run.run_kind_code) { + case "analysis_run_lineage": + return "Open this run to confirm which posts it will use. Reconstruction has not started yet."; + case "analysis_run_tepp": + return "Open this run to confirm which posts TEPP will measure. Measurement has not started yet — this is not a calibrated result."; + case "analysis_run_report": + return "Open this run to confirm which posts the period report will use. The report has not been built yet."; + default: { + const unexpected: never = run.run_kind_code; + return unexpected; + } + } + case "analysis_status_failed": + switch (run.run_kind_code) { + case "analysis_run_tepp": + return "Open this run to see why it failed, then connect the measurement service and re-run."; + case "analysis_run_lineage": + return "Open this run to see why it failed, then retry reconstruction from a current snapshot."; + case "analysis_run_report": + return "Open this run to see why it failed, then rebuild the period report from a current snapshot."; + default: { + const unexpected: never = run.run_kind_code; + return unexpected; + } + } + case "analysis_status_running": + case "analysis_status_succeeded": + case "analysis_status_cancelled": + case null: + return null; default: { - const unexpected: never = run.run_kind_code; + const unexpected: never = run.status_code; return unexpected; } } @@ -1648,6 +1668,7 @@ function AnalysisRunsPanel({ if (runs === null) return

Loading analysis runs...

; const corpusHint = selected ? analysisRunCorpusHint(selected) : null; + const selectedNextAction = selected ? analysisRunNextAction(selected) : null; return (
@@ -1699,6 +1720,7 @@ function AnalysisRunsPanel({ {selected && (

{analysisRunCaption(selected)}

+ {selectedNextAction &&

{selectedNextAction}

}

Cutoff {selected.knowledge_cutoff.slice(0, 10)} {" · "}