Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 ·
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.d/0.86.0-related-nodes-team-org-walk.md
Original file line number Diff line number Diff line change
@@ -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.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
3 changes: 2 additions & 1 deletion docs/adr/0014-authorized-analysis-run-read.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only locks the absence of the lineage sentence. A pending TEPP row that showed the period-report sentence, or no next-action at all, still passes.

Missing on this head: a positive lock of Measurement has not started yet — this is not a calibrated result; a pending-report fixture/test; running/cancelled TEPP corpus tests. The nearby getByRole name is still caption-only, which locks the AccName hole this PR leaves open.

});

it("does not tell a succeeded TEPP run to replace Failed", async () => {
Expand Down Expand Up @@ -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",
);
Expand Down
56 changes: 39 additions & 17 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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.";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pending-TEPP disclaimer never enters the list accessible name. The list button still sets aria-label={Open analysis run: ${caption}} (unchanged in this diff), so AccName 1.1 replaces the visible next-action and WCAG 2.2 SC 4.1.2 still fails on the control this sentence lives on.

Put the next-action in the accessible name (Open analysis run: {caption}. {nextAction}), or drop the override so the visible sentence is the name. #149 already does this with analysisRunAccessibleName.

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;
}
}
Expand Down Expand Up @@ -1648,6 +1668,7 @@ function AnalysisRunsPanel({
if (runs === null) return <p>Loading analysis runs...</p>;

const corpusHint = selected ? analysisRunCorpusHint(selected) : null;
const selectedNextAction = selected ? analysisRunNextAction(selected) : null;

return (
<section className="popup-section lineage-home">
Expand Down Expand Up @@ -1699,6 +1720,7 @@ function AnalysisRunsPanel({
{selected && (
<div className="popup-section">
<h3>{analysisRunCaption(selected)}</h3>
{selectedNextAction && <p className="post-meta">{selectedNextAction}</p>}
<p className="post-meta">
Cutoff {selected.knowledge_cutoff.slice(0, 10)}
{" · "}
Expand Down