Skip to content

feat: surface update failures from any Settings tab - #701

Merged
enaboapps merged 6 commits into
mainfrom
feat/update-status-off-tab-697
Sep 8, 2026
Merged

feat: surface update failures from any Settings tab#701
enaboapps merged 6 commits into
mainfrom
feat/update-status-off-tab-697

Conversation

@enaboapps

@enaboapps enaboapps commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Closes #697. Stacked on #699base is feat/setting-note-disclosures-687.

Since the tabbed restructure, the updater's status line lived only in the Updates panel, which is unmounted on every other tab. The global banner deliberately shows nothing for failed or cancelled (an existing test asserts that), so a download that failed after the user switched to Pointer left no visible or announced sign until they happened to return.

What changes

While another tab is selected and the updater is failed or cancelled:

  • A marker appears on the Updates tab (.tab-attention, aria-hidden).
  • A visually hidden live regionrole="alert" for failed, role="status" for cancelled — reads the same status text UpdateControls would, plus "Open the Updates tab to retry."
  • The Updates tab gets aria-describedby pointing at that region, so assistive tech gets the reason on the tab itself.

The region unmounts on the Updates tab, where the panel's own live region takes over, so a failure is announced once, not twice. The tab's accessible name stays exactly "Updates", so speech input and existing queries keep working. States the banner already covers (available, downloading, readyToInstall) get no marker.

Validation

Check Result
npm run lint pass
npm test pass — 98 tests (95 → 98)
npm run build pass

New tests cover: alert + marker + describedby on General; exactly one alert once on the Updates tab, with no describedby; the notice returning on Pointer; polite status for cancelled; no marker for banner-covered states.

Not screenshotted: the browser-mode API cannot put the updater into failed, so the marker is verified at the DOM level; its CSS is an 8px dot.

🤖 Generated with Claude Code


Review history

  • The live region fired on every tab move for an unchanged failure, and when Settings opened straight to Updates it announced for a tab already being opened. It now changes only when the updater does, stays silent when the change lands on Updates, is retired on arrival there, and is not mounted on that tab; opening via the banner or Support seeds the Updates tab. Re-entering Settings with a standing failure announces once, as the audible counterpart of the tab marker.
  • Backend failure text has no terminal punctuation; it is closed as a sentence before the hint.
  • The tab's aria-describedby now carries only the reason, not "Open the Updates tab" read from the Updates tab itself.
  • The failed/cancelled politeness rule is one exported updateStatusRole used by both the panel and the notice.

@enaboapps
enaboapps force-pushed the feat/update-status-off-tab-697 branch 2 times, most recently from 91b81ae to 72f7a75 Compare September 8, 2026 16:07
@enaboapps
enaboapps changed the base branch from feat/setting-note-disclosures-687 to main September 8, 2026 16:26
OwenMcGirr and others added 3 commits September 8, 2026 17:31
Since the tabbed restructure, the updater's status line lived only in
the Updates panel, which is unmounted on every other tab. The global
banner deliberately shows nothing for failed or cancelled, so a download
that failed after the user switched to Pointer left no visible or
announced sign until they happened to return.

Failed and cancelled now do two things while another tab is selected: a
marker appears on the Updates tab, and a visually hidden live region —
assertive for failed, polite for cancelled — reads the same status text
UpdateControls would, plus where to go. The region unmounts on the
Updates tab, where the panel's own live region takes over, so a failure
is announced once rather than twice.

The tab's accessible name stays "Updates"; the reason is attached with
aria-describedby instead, so speech input and existing queries keep
working. States the banner already covers get no marker.

Tests: 95 -> 98.

Closes #697

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e hint

Review follow-ups on the off-tab update notice.

The live region was mounted whenever the Updates tab was not selected,
so it fired on every tab move for an unchanged failure, and when
Settings opened straight to Updates it committed General for one frame
and announced a failure for a tab that was already being opened, which
the panel then repeated. It now changes only when the updater does,
stays empty when the change lands on the Updates tab, is retired on
arrival there, and is not mounted on that tab at all. Opening via the
banner or Support seeds the Updates tab directly. Re-entering Settings
with a standing failure still announces it once, as the audible
counterpart of the marker on the tab.

Backend failure text is "context: error" with no terminal punctuation,
so it is closed as a sentence before the hint is appended.

The tab's description now carries only the reason. Reading "Open the
Updates tab" from the Updates tab itself was self-referential, and for
a cancelled download said retry twice.

The failed/cancelled politeness rule lives in one exported helper used
by both the panel and the notice, so they cannot drift apart.

Tests: 98 -> 101.

Refs #697

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Third review pass on the off-tab update notice.

The backend re-checks for updates every few hours, and for an offline
user that cycles a standing failure through "checking" and back with the
same text. The notice was keyed on the raw state, so every cycle
unmounted and re-announced it and blinked the marker. The last settled
state is now held through transient ones, and the notice remembers the
text it last spoke or that the user saw on the Updates panel, so an
unchanged failure is silent until a settled recovery resets it.

The live region is always mounted, expressed through aria-live rather
than a role, so it exists before text arrives and never registers as a
second alert or status beside the panel's own. The marker and the tab's
description stand down on the Updates tab, where the reason is on
screen, which also removes the description text from that tab's reading
order. Tabs now takes the reason as `attention` and renders the marker
and the description itself, so the consumer no longer mints an id and
threads it through two fields.

The failure text is closed as a sentence inside updateDescription, so
the panel, the description and the notice all agree. The retry hint is
appended only for failed; the cancelled text already says it. The
marker is positioned out of flow, so it cannot wrap the label and grow
the tab row, which it did between 681 and 750px wide.

Following the hint to the Updates tab still hears the panel announce on
entry, exactly as before this change; the notice is scoped to failures
the user has not yet been shown.

Verified in headless Chrome, including the tab-row height with a marker
at 700px and 1280px.

Refs #697

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@enaboapps
enaboapps force-pushed the feat/update-status-off-tab-697 branch from 18572e1 to e625f4e Compare September 8, 2026 16:31
OwenMcGirr and others added 3 commits September 8, 2026 17:38
…rechecks

Fourth review pass on the off-tab update notice.

What the user had already been told lived in SettingsView, which App
unmounts whenever another view is open, so a failure read on the
Updates panel was announced again on every return to Settings. That
memory now lives in App, next to focusUpdates, and is forgotten only
when the updater settles into a state with nothing to act on, so the
next failure is news.

The scheduled check builds its message as "context: error" where the
error half is transport text that can change wording between cycles.
Announcing is now keyed on the state and the context before the colon,
so an offline user is not interrupted every few hours by the same
failure in different words. The marker and description still show the
current text.

The held-through-transient state is stored during render rather than
written from an effect, which removes a commit per updater change and
the identity churn that was recomputing the tab list.

Tests: 102 -> 104.

Refs #697

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Fifth review pass on the off-tab update notice, and the change that
makes the earlier ones hold together.

Everything about a standing update failure — what is standing, what has
been said about it, and the live region that says it — now lives in
App. SettingsView unmounts whenever another view is open, so anything
it held was lost on every visit: a failure read on the Updates panel was
announced again on return, a failure standing during the scheduled
check lost its marker when Settings opened mid-check, and the live
region was created and filled in the same breath, which assistive
technology need not speak. The region now exists for the life of the
shell, and SettingsView only reports whether the Updates panel is on
screen and receives the text for its marker.

A check the user asks for is not the scheduled one: nothing is held for
it, and whatever it returns is announced even if it reads the same,
because the user asked. An install in progress is not held either, so a
stale failure no longer sits on the tab while the installer runs.

A same failure in different words no longer leaves the old words in the
live region contradicting the tab's description; it is cleared without
an interruption. The state partition — standing, in flight — is one pair
of exported helpers rather than three hand-spelled copies.

A focused tab is lifted above its selected neighbour so its focus ring
is not overpainted, and the marker carries a transparent outline that
becomes a visible ring under forced colours.

Tests: 104 -> 107.

Refs #697

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The backend always publishes "checking" before a check result, and the
notice relies on that to know a user-started check is new. The test
now mirrors it instead of resolving straight from failed to failed.

Refs #697

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@enaboapps
enaboapps merged commit 704ea24 into main Sep 8, 2026
6 checks passed
@enaboapps
enaboapps deleted the feat/update-status-off-tab-697 branch September 8, 2026 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Updater status is only visible on the Settings Updates tab

2 participants