Skip to content

fix(web): screen readers read the Update everything machine list as a table - #36445

Merged
juliusmarminge merged 2 commits into
mainfrom
factory/issue-36441
Nov 14, 2026
Merged

juliusmarminge merged 2 commits into
mainfrom
factory/issue-36441

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

Nothing needed changing. All 8 required checks passed on 241b915 and Macroscope approved the PR. Macroscope's approvability comment raised no findings, and no bot left review comments on lines. The fix is unchanged: the Update everything dialog's machine grid has table/row/columnheader/cell roles, and the machine name cell exposes the full label to screen readers (sr-only) while the visual MiddleTruncate is hidden from them with aria-hidden.

Fixes #36441

Reproduction on main

Commit 3c1be11 (origin/main). Ran the desktop dev app (T3CODE_DEV_SEED=0 T3CODE_DESKTOP_REMOTE_DEBUGGING_PORT=<port> headless-desktop vp run dev:desktop) on Linux/Xvfb with a fresh database, clicked Start on onboarding, then clicked the sidebar's update button (it offered a Claude provider update), which opened the 'Update 1 machine?' dialog. Dumped the dialog over CDP with Playwright: ariaSnapshot gives a single text: Machine T3 Code Providers <host>- <tail> Claude node; the Chromium AX tree has only generic/StaticText nodes, with no table/row/columnheader/cell roles; dialog textContent is Update 1 machine?1 provider updateMachineT3 CodeProvidersf-92f0586e-ljd6uClaudeCancelUpdate, matching the reporter's run-on output. The machine name is exposed as two StaticText nodes (head and tail from MiddleTruncate). The test machine name was short enough not to truncate, so the '…' being announced was not observed directly; it follows from MiddleTruncate's CSS ::before ellipsis. Not run on Windows or with a real screen reader, and no T3 Code app update was available, so only the provider column was filled.

Evidence

Steps: On Linux/Xvfb, run each real Electron desktop build with a fresh isolated database and the same synthetic long hostname. Disable history import, click Start, click Update 1 provider, and wait for checking to finish. Capture at 1280×800 in light theme only after two screenshots 500 ms apart match. Both retained stills were opened and visually inspected; both show Update 1 machine? with the Claude row. Recordings are omitted.

Before After
3c1be119b9 241b9156cb
Before: populated update dialog After: populated update dialog
Accessibility snapshot: headers and machine values collapse into one text node. Accessibility snapshot: table, rows, column headers, and cells; full machine name.
Chromium AX tree: no table roles; split machine-name StaticText exposes an ellipsis. Chromium AX tree: one table, two rows, headers and cells; truncated rendering hidden.

Reproduction: capture driver, synthetic hostname fixture, desktop launch script.

Not shown:

  • Actual spoken output with a screen reader and Windows accessibility behavior were not exercised; proof uses the real Linux Electron app's accessibility tree.
  • The T3 Code update-value column was empty because no app update was available; only the Claude provider column was populated.
  • Multiple machine rows were not exercised because each isolated app had one local environment.
  • Whether the previous recording's transient zero-machine state recurs was not investigated; this submission uses settled static captures and accessibility trees instead.

Tests

No new runs this round. CI: all 8 required checks passed on 241b915. Earlier round: vp test run src/components/sidebar/SidebarUpdatePill.browser.test.tsx passed 5/5 with the fix and the repro test failed without it; vp run check:changed passed.

Not in this change

  • The collapsible 'N skipped' list in the same dialog also renders machine names with MiddleTruncate, so a long skipped machine name is still read in its truncated form; it is a separate list, not the machine table this issue covers.
  • Other MiddleTruncate call sites across the app expose the split, ellipsized text to assistive tech; a general fix inside MiddleTruncate would change every consumer.

Who did the work

  • Written by Claude Opus 5.5, in Claude Code
  • Reviewed by GPT-6.1 Sol, in Codex, and by Claude Opus 5.5, each on its own
  • Proof captured by GPT-6.1 Sol and checked by Claude Opus 5.5

Run by the t3code factory in T3 Code.

juliusmarminge and others added 2 commits November 13, 2026 23:24
Fails on main: the machine list is a CSS grid of spans with no table,
row, column header or cell roles, so screen readers read it as one
run-on string (#36441).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
… table

The machine list was a CSS subgrid of spans with no table semantics, so
screen readers read the header and rows as one run-on string, and the
machine name came through MiddleTruncate's split, ellipsized form. Give
the grid table/row/columnheader/cell roles and expose the full machine
name to assistive tech while hiding the truncated rendering.

Fixes #36441

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@github-actions github-actions Bot added vouch:trusted Author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Nov 13, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 241b915

Macroscope's review found this PR approvable — The machine list gains accessible table semantics and full screen-reader labels without changing its visual layout or update behavior. The change is localized to presentation and introduces no material operational exposure.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The update-everything dialog now exposes its machine list as an accessible table and provides the full machine name to screen readers. A browser test supplies a machine row and checks the table headers and values.

Changes: Update dialog accessibility

Layer / File(s) Summary
Table semantics and coverage
apps/web/src/components/sidebar/UpdateEverythingDialog.tsx, apps/web/src/components/sidebar/SidebarUpdatePill.browser.test.tsx
The dialog adds table, row, column-header, and cell roles. Screen readers receive the full machine name while the visual label remains truncated. The browser test checks the headers, machine label, and provider value.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: t3dotgg

Merge Risk: Minimal · up to 241b9

This change makes the Update everything dialog's machine list readable as a table by screen readers, with full machine names. Visual behavior is unchanged and the risk of merging is minimal.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title names the fix and its scope: screen readers announce the Update everything machine list as a table. It matches the changeset, which adds table, row, columnheader, and cell roles to the dialo…
Linked Issues check Passed Issue #36441 has one coding requirement: the Update everything machine table must expose table structure, with each machine as a row, each value tied to its column (Machine, T3 Code, Providers), and t…
Out of Scope Changes check Passed The whole-PR diff against the merge base 3c1be11 changes UpdateEverythingDialog.tsx for the machine table roles and screen-reader label. The summary also lists changes to SidebarUpdatePill.browser.…
Description check Passed The description follows the repository template's sections: Problem, Change, Scope, and Verification, plus the agent attribution line. It names the issue it fixes and gives detailed reproduction, befo…
Full details: Title check

Explanation

The title names the fix and its scope: screen readers announce the Update everything machine list as a table. It matches the changeset, which adds table, row, columnheader, and cell roles to the dialog and adds a test for them. The title is concise and follows the conventional commit form the template suggests.

Full details: Linked Issues check

Explanation

Issue #36441 has one coding requirement: the Update everything machine table must expose table structure, with each machine as a row, each value tied to its column (Machine, T3 Code, Providers), and the machine name read in full. The reviewed head meets this in UpdateEverythingDialog.tsx. The grid container has role="table". The header div has role="row", and its four spans have role="columnheader" (the fourth is empty). Each machine div has role="row". Each of the four value spans has role="cell". The machine cell renders row.label in an sr-only span, and the MiddleTruncate visual is passed aria-hidden, so the full name is available to assistive technology. The DOM, classes, and grid layout are otherwise unchanged. The test file adds a browser test that checks the table, its column headers, and the machine and provider values. The PR reports that this test fails without the fix. Limits: the reported reproduction ran on Linux/Xvfb with a provider update only. Windows and real screen reader behavior were not verified. The issue's reproduction includes a T3 Code update, which was not present in the PR's run. The code changes cover the coding requirement for any update set, so these limits do not change the verdict. I did not read the MiddleTruncate source to confirm that it forwards the aria-hidden prop to the DOM. The prop type checks, as the PR reports, and the PR's accessibility-tree evidence reflects the intended behavior.

Full details: Out of Scope Changes check

Explanation

The whole-PR diff against the merge base 3c1be11 changes UpdateEverythingDialog.tsx for the machine table roles and screen-reader label. The summary also lists changes to SidebarUpdatePill.browser.test.tsx that add a test and mock row configuration for the same dialog. Both files support the objective in #36441. The PR does not change the collapsible 'N skipped' list or the general MiddleTruncate component. The PR excludes those items explicitly, and they are not part of the issue's machine table requirement. No unrelated change is demonstrated.

Full details: Description check

Explanation

The description follows the repository template's sections: Problem, Change, Scope, and Verification, plus the agent attribution line. It names the issue it fixes and gives detailed reproduction, before/after evidence, and test results. The Problem section is missing its own explanation, however. The author-provided text opens with 'Nothing needed changing' and does not state the bug in a sentence or two, nor does it use the template's section headings. The Scope section does not explain why this is a bug fix rather than a feature, though it does link issue #36441. The Verification section is thorough, and it notes what was not checked (Windows, real screen reader). The 'Tests' section mentions only earlier runs, and the UI before/after screenshots are present. Overall the content is largely complete, but the Problem heading and the template structure are not followed cleanly.

Finishing Touches

Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between ab9e6a2 and 241b915.

Files selected for processing: 2

  • apps/web/src/components/sidebar/SidebarUpdatePill.browser.test.tsx
  • apps/web/src/components/sidebar/UpdateEverythingDialog.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.

@juliusmarminge
juliusmarminge merged commit cbf0f0a into main Nov 14, 2026
37 checks passed
@juliusmarminge
juliusmarminge deleted the factory/issue-36441 branch November 14, 2026 00:52
amv146 added a commit to amv146/t3code that referenced this pull request Nov 14, 2026
* fix(server): Claude can show the user mid-turn text in full (pingdotgg#36384)

* fix(cli): tagged source builds report the release version (pingdotgg#36350)

Co-authored-by: Lakshmi Tanmay <[email protected]>

* fix(server): storage cleanup prunes idle No project folders under ~/.t3/scratch (pingdotgg#36369)

* fix(terminal): trimmed history no longer replays half of a control sequence (pingdotgg#36368)

* fix(usage): a re-emitted Codex snapshot is no longer billed as a counter rewind (pingdotgg#36367)

Co-authored-by: rihanaws <[email protected]>

* fix(server): a Claude Monitor line no longer wakes a delegated child's parent (pingdotgg#36339)

* fix(opencode): a lost subagent report no longer leaves a resumed call running (pingdotgg#36386)

* fix(web): a new worktree thread opened during a clone bases on the real default branch (pingdotgg#36379)

* fix(server): unauthenticated token requests no longer write DPoP replay markers (pingdotgg#36393)

* fix(server): other sites can no longer frame the web app (pingdotgg#36395)

* fix(server): a server browser tab survives a renderer crash, and a service worker badge call no longer causes one (pingdotgg#36389)

* fix(web): T3 Connect sign-in offers Retry after Clerk fails to load (pingdotgg#23620)

Co-authored-by: Claude Opus 5.5 <[email protected]>

* fix(ci): macOS PR previews no longer run the PR's bundle next to signing secrets (pingdotgg#36407)

* fix(mobile): a new thread's first message no longer returns to the composer after a lost launch reply (pingdotgg#32330)

* fix(web): size markdown media whose width and height carry a px unit (pingdotgg#32108)

* fix(web): file links the agent cited from a checkout it cd'd into open that file (pingdotgg#36364)

* ci(mobile): iOS jobs run on macos-27, store builds require the final Xcode 27.1 (pingdotgg#36421)

* fix(server): Claude context meter no longer shows an auto-compact point when auto-compaction is off (pingdotgg#36417)

* fix(web): a run waiting on foreground subagents says so instead of Thinking (pingdotgg#36334)

* fix(server): a follow-up to a delegated child waits for its awaited background work (pingdotgg#36411)

* fix(provider-grok): Grok follow-ups queue instead of cancelling the running tool (pingdotgg#36422)

* fix(server): thread list builds metadata only for the page it returns (pingdotgg#36434)

* fix(web): middle-clicking empty chat space on Linux no longer pastes into the composer (pingdotgg#36436)

* fix(web): closing Settings no longer leaves it as a back/forward stop (pingdotgg#36437)

* fix(opencode): OpenCode 1.x threads report context-window usage (pingdotgg#36430)

* fix(web): bare @ in the composer lists workspace files (pingdotgg#36435)

* fix(mobile): thread list project filter lists recently active projects first (pingdotgg#36433)

* fix(clients): live working timers count on the host's clock (pingdotgg#36420)

* perf(relay): lighter Postgres load and PS-160 cluster (pingdotgg#36442)

Co-authored-by: Claude Opus 5.5 <[email protected]>

* fix(mobile): mobile:install --session works on pooled devices (pingdotgg#36447)

* fix(native): KDE SnapShot no longer loses the first reply from KWin (pingdotgg#36218)

Co-authored-by: Claude Fable 5.2 <[email protected]>

* fix(server): t3 connect status no longer reports a publish-only link as exposed (pingdotgg#33967)

* fix(web): don't label Windows paths outside the workspace as relative (pingdotgg#28469)

Co-authored-by: Julius Marminge <[email protected]>

* fix(server): multi-line guest messages are no longer refused or stored with CRLF (pingdotgg#26542)

* perf(desktop): provider checks no longer compete with server startup (pingdotgg#35712)

Co-authored-by: Claude Opus 5.5 <[email protected]>

* fix(web,mobile): explain missing file access for host videos (pingdotgg#24637)

* fix(scripts): iOS scenarios prepare the dev client before leasing a device (pingdotgg#36456)

* perf(server): a new thread's first turn starts sooner (pingdotgg#35710)

Co-authored-by: Claude Opus 5.5 <[email protected]>

* fix(provider-pi): running shell output no longer stores a snapshot row per update (pingdotgg#36429)

* fix(web): NVDA browse mode reads the current thread's branch, not the previous one (pingdotgg#34446)

Co-authored-by: nibarAhmed <[email protected]>
Co-authored-by: Julius Marminge <[email protected]>

* fix(server): T3 Connect clients are named "T3 Connect", not "T3 Connect connect" (pingdotgg#27887)

* fix(web): screen readers read the Update everything machine list as a table (pingdotgg#36445)

* feat: agents can restyle T3 Code with theme colors and CSS (pingdotgg#35247)

Co-authored-by: maria-rcks <[email protected]>
Co-authored-by: Claude Fable 5.2 <[email protected]>

* fix(mobile): long-pressed iOS blockquotes no longer draw over the thread (pingdotgg#36461)

* fix(cli): npm launcher no longer leaves a runtime running after a stop signal (pingdotgg#30487)

* feat(connect): require approval for new T3 Connect devices (pingdotgg#36419)

Co-authored-by: Claude Opus 5.5 <[email protected]>

* fix(server): run the Azure CLI in UTF-8 on Windows (pingdotgg#25801)

Co-authored-by: Julius Marminge <[email protected]>

* fix(server): preview navigation leaves a page whose script never yields (pingdotgg#36365)

* fix(server): the auto-settle sweep no longer rereads every idle branch every few minutes (pingdotgg#36371)

* fix(web): rewind no longer offers file restore in project-folder threads (pingdotgg#36467)

* fix(server): stop the relay client a crashed server left running (pingdotgg#36465)

* fix(server): read Azure DevOps pull request templates (pingdotgg#22881)

* perf(azure-devops): PR Code tab loads a page's files in one az run instead of two per file (pingdotgg#35295)

Co-authored-by: Julius Marminge <[email protected]>

* fix(web): copying a file preview selection returns the selected lines after scrolling (pingdotgg#36466)

* fix(mobile): push-token failures no longer report notifications as enabled (pingdotgg#26557)

* fix(provider-core): mise updates a tool configured by its backend name (pingdotgg#36472)

* fix(server): parent turns no longer duplicate delegated task thread items (pingdotgg#36473)

* fix(server): Windows drive paths open under WSL (pingdotgg#26030)

* fix(client-runtime): new T3 Connect machines appear without signing in again (pingdotgg#29788)

* fix(azure-devops): local pull request checkout no longer fails on --detect (pingdotgg#31170)

Co-authored-by: maria-rcks <[email protected]>
Co-authored-by: Julius Marminge <[email protected]>

* fix(usage): count shared Windows and WSL transcripts once (pingdotgg#24319)

* fix(azure-devops): pull requests report build validation as checks (pingdotgg#31146)

Co-authored-by: maria-rcks <[email protected]>
Co-authored-by: Julius Marminge <[email protected]>

* fix(desktop): WSL backend starts in distros without automounted drives (pingdotgg#25734)

* fix(server): t3 browser setup reloads an AppArmor profile that is on disk but not loaded (pingdotgg#36490)

* Initial plan

* fix(azure-devops): finish reconciling nightly diff tests

Remove retired files-diff code and update mocks for iteration changes and blob reads. Preserve bounded paging, cache, and error-path coverage.

Co-authored-by: Copilot <[email protected]>

---------

Co-authored-by: Julius Marminge <[email protected]>
Co-authored-by: Lakshmi Tanmay <[email protected]>
Co-authored-by: rihanaws <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
Co-authored-by: Theo Browne <[email protected]>
Co-authored-by: ValeraZSD <[email protected]>
Co-authored-by: nibarAhmed <[email protected]>
Co-authored-by: nibarAhmed <[email protected]>
Co-authored-by: maria-rcks <[email protected]>
Co-authored-by: Pedro Henrique <[email protected]>
Co-authored-by: Kieren-Foenander <[email protected]>
Co-authored-by: Pavel Kroupa <[email protected]>
Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Alex Vallone <[email protected]>
Co-authored-by: Copilot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted Author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Screen readers read the Update everything dialog's machine table as one run-on string

1 participant