feat: surface update failures from any Settings tab - #701
Merged
Conversation
enaboapps
force-pushed
the
feat/update-status-off-tab-697
branch
2 times, most recently
from
September 8, 2026 16:07
91b81ae to
72f7a75
Compare
enaboapps
changed the base branch from
feat/setting-note-disclosures-687
to
main
September 8, 2026 16:26
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
force-pushed
the
feat/update-status-off-tab-697
branch
from
September 8, 2026 16:31
18572e1 to
e625f4e
Compare
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #697. Stacked on #699 — base 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
failedorcancelled(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
failedorcancelled:.tab-attention,aria-hidden).role="alert"for failed,role="status"for cancelled — reads the same status textUpdateControlswould, plus "Open the Updates tab to retry."aria-describedbypointing 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
npm run lintnpm testnpm run buildNew tests cover: alert + marker + describedby on General; exactly one alert once on the Updates tab, with no describedby; the notice returning on Pointer; polite
statusfor 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
aria-describedbynow carries only the reason, not "Open the Updates tab" read from the Updates tab itself.updateStatusRoleused by both the panel and the notice.