Today a failed re-run hides the report the researcher already had: detect_status
intercepts /report/* whenever the last terminus isn’t completed, so a
provider outage takes away finished work. D4-B serves the last good report instead and
discloses the failure. This is the surface that does the disclosing.
The report exists on disk and is perfectly readable. The researcher cannot reach it.
Last run failed.
Provider returned 503 — the service is temporarily unavailable.
The last good report, with the two facts the researcher is owed: what they are reading, and that the run they started since then failed.
Showing the report from 28 August. The latest run failed.
category: api_server code: 503 stage: s10_quote_extraction provider: anthropic Provider returned 503 — the service is temporarily unavailable.
“I couldn’t tell whether it had saved, so I just pressed it again.”
“The price at the top and the price in the bag were different.”
Kind: WARNING, not ERROR. The five-kind taxonomy
(bristlenose/ui_kinds.py) is explicit that a sixth is not to be invented, so the
banner picks from what exists. ERROR means “did not complete; action needed” —
right for the status page, where there is nothing to show. Here a complete artefact is
on screen and only its currency is in question, which is what WARNING
(“recoverable / partial / soft-degrade”) names. Reaching for ERROR would teach the
researcher to distrust a report that is fine.
It is the status page folded to one line. Same glyph, same kind colour
(--bn-sentiment-surprise), same <details> + <pre>
disclosure carrying the same cause block. Nothing new is being said, so nothing new is being
drawn — the two surfaces are one message at two sizes.
Genuinely new element, flagged. No banner/notice component exists in
frontend/src/components/ or in theme/{atoms,molecules,organisms} —
I checked before drawing. Every value above is an existing token; the component
is new and needs your nod. Home would be theme/molecules/report-notice.css plus a
small React component, not inline styles.
A failed first run, or a destructive re-analysis that consumed the artefact, leaves nothing coherent to serve. The status page keeps that case, unchanged.
Last run failed.
Provider returned 503 — the service is temporarily unavailable.
Which of the two you get is decided by evidence, never by how bad the failure looked: is there a coherent last-good artefact? That keeps us out of the business of maintaining a severity taxonomy of failures.
It also needs a real fix underneath, and this is the part worth scrutinising. The pipeline rewrites intermediate JSON stage by stage, so a failed run can leave stages 1–9 new and 10–12 old. A running serve only re-imports on a completed terminus, so today’s common case (provider outage, network, crash) never touches the DB — yesterday’s report is intact. The hole is a serve restart, whose startup import would happily ingest that mixed state. So the rule is one line with two consumers: the DB advances only on a completed terminus — the importer skips, and the page gate reads the same fact.
All three are one component in different states. Copy is deliberately unsettled — English first, then 21 locales.
Showing the report from 28 August. The latest run failed.
category: api_server code: 503 stage: s10_quote_extraction provider: anthropic
Showing the report from 28 August. The latest run failed.
category: api_server code: 503 stage: s10_quote_extraction provider: anthropic Provider returned 503 — the service is temporarily unavailable. — recent log — 2026-09-02 19:04:11 INFO s09_topic_segmentation complete (51 sessions) 2026-09-02 19:04:12 INFO s10_quote_extraction start 2026-09-02 19:04:44 ERROR provider says: 503 upstream unavailable
Showing the report from 28 August. The latest run was cancelled.
INFO with no disclosure, because there is no cause to show and the researcher
did it on purpose. But the sidebar’s own glyph rule already decided the sibling case —
“a run they stopped is not news” — and the consistent reading of that is
no banner for a cancelled run, only for a failed one. I lean to dropping it;
the counter-argument is that “this isn’t the run you started” outlives the memory of
cancelling.docs/design-shared-formats.md is explicit that a
format with no shared stem is a format that drifts, and this one has a Python, a TypeScript
and a Swift renderer to agree with.Copy, unsettled on purpose (English gets hand-tuned before it is seeded to 21 locales). Three candidates for the leading sentence:
The desktop sidebar row keeps its own failure glyph and diagnostic popover. That is a different fact in a different place — the row says this study’s run failed, the banner says this report predates it — and per the house rule status lives where its subject lives. Browser and CLI have no row at all, so the banner is their only signal either way.
One consequence to accept knowingly: with D4-B in, a failed-but-previously-analysed project
serves the SPA, so its lenses are live and correctly lit. That is the same one-line
flip in ArtifactPrior the lens work left waiting, and it lands in the same commit
as the serve rule — the prior must always mirror the serve that is actually running.