Skip to content

fix(preview): add an accessible view for streamed browser tabs - #25308

Draft
shivamhwp wants to merge 19 commits into
pingdotgg:mainfrom
shivamhwp:issue-watch/25271
Draft

shivamhwp wants to merge 19 commits into
pingdotgg:mainfrom
shivamhwp:issue-watch/25271

Conversation

@shivamhwp

@shivamhwp shivamhwp commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Unproven: actual screen-reader navigation and forms, native iOS/Android WebViews, and packaged Linux/macOS Electron. The desktop CDP relay rejects separate iframe targets, so some embedded content remains unavailable; Accessible view reports incomplete documents. This PR stays draft pending verification.

Approval required: this PR touches Metro bundling configuration, scroll containers, and the wire protocol. It requires Theo's approving GitHub review before merge.

Ready to merge: no. Evidence findings R1, R2 and R3 remain open, and Theo has not approved.

Streamed browser tabs expose pixels and a keyboard buffer, so screen readers cannot read the remote page. Add an opt-in Accessible view to web, remote desktop, and full-screen mobile streams. A shared renderer exposes text, headings, links, and common form controls.

The server captures full accessibility snapshots only while viewers subscribe. Read-only viewers can read them; actions retain permission and control checks. Navigation invalidates action targets, interrupted edits stop before further mutations, and updates preserve local drafts. Protected fields omit values and descendants. Text keeps inline spaces, and inaccessible frames produce an incomplete-document notice.

The mobile raw-input styles apply only to the keyboard buffer, so multiline semantic fields remain visible. Accessible mode disables that buffer to let keyboard navigation leave the document controls. Web toggles are local to each browser surface.

Refs #25271. An actual screen-reader workflow is still unverified.

Validation at head 63c8128b63b2482dcc5c749c6aaeb08a3c7443c6, with main e5559038165337caaf84ec162e3343b6c25120da:

  • Merged main and mechanically retained both mobile React test registrations: accessible-document and workspace-tab state. The sole manual resolution removes four conflict-marker lines.

  • Fresh independent GPT-6.1-sol review of 1704b217a861853b7e3c22780524bd7fb5a756cb against main e5559038165337caaf84ec162e3343b6c25120da found no new findings. Accessibility subscription lifetimes, current-document guards, control checks, backlog handling, the web toggle, and hidden-input behavior remain intact.

  • The review confirmed that main's capacity reservation, file-picker cleanup on page replacement, stale-download cleanup, serialized profile clearing, and typed viewport dimensions fixes remain preserved. Both mobile tests are registered in the correct React project.

  • M1 remains fixed. Previous raw-log evidence retains its original commit attribution; the fresh execution below covers this merged head. R1, R2 and R3 remain open.

  • V1, found by execution after the source review, is fixed in 63c8128b63b2482dcc5c749c6aaeb08a3c7443c6: the new ServerBrowserSurface browser-test stream mock now includes the accessibility method used during mount. This follow-up changes only the test fixture, with no production behavior change and no new test case.

  • Initial merge job j_2g2erzrylp2roywyvpba on 1704b217a861853b7e3c22780524bd7fb5a756cb failed its changed-file browser tests because the mock lacked client.accessibility. Its separate 153-test run passed, but that job was not a pass overall. The final-head rerun below supersedes it.

  • Fresh Linux Boat job j_b7o2prikwgf7gue6qly7, stage typecheck-ax-mobile-final, large worker, VM bx_fu2csfun, attempt 1, using the t3code template. The job finished with exit 0. Node.js 26.12.1 and vp i --frozen-lockfile.

  • vp run check:changed e5559038165337caaf84ec162e3343b6c25120da passed, including 39 package typechecks, 103 tests across eight files, and 10 selected React compiler checks. Complete commands and results are in the execution log below.

  • A separate focused vp test run covered ServerBrowser, accessibility, stream, context/page ownership, shared client renderer/stream, the mobile accessible document, and workspace-tab state. All 153 tests across nine files passed.

  • GitHub CI for this pushed head is tracked separately in the PR checks. Runs on earlier commits remain historical.

Evidence review:

  • R1 remains open: recordings of the actual web Browser panel on main and this head with a screen reader are missing.
  • R2 remains open: native iOS VoiceOver and Android TalkBack recordings, including multiline fields and keyboard navigation, are missing.
  • R3 remains open: packaged Linux/macOS Electron remote-environment recordings with screen-reader navigation and form interaction are missing.
  • R4 is resolved by fresh execution logs with the tested commit, commands, environment, and exit results below.
  • Maria's Chrome runtime report and the screenshots below cover 50a12e6daa352baf52f416ca2a235494a5b0c0f6. They are historical and do not verify this merged build. They used no screen reader, native WebView, packaged Electron, or relay.

Native screen-reader verification remains blocked by device tooling. AgentDevice refused the VoiceOver row as covered by a toolbar, including the retry after screenshot inspection. The alternative VoiceOver Settings deep link also failed twice, with iOS error 115 on the advised debug retry. The 2026-10-31 blocker recheck used a fresh Simlock iPhone 17e lease on iOS 27.0. Settings opened, but AgentDevice again refused the VoiceOver row as covered by toolbar "Toolbar" at (0, 0 390x844), diagnostic mvvvw2uq-6fe3786b. The screenshot showed VoiceOver Off. The fresh lease was released with device_close and shutdown=true. No native T3 workflow was verified. Theo's approving GitHub review remains missing and the PR remains draft.

Complete execution log for job j_b7o2prikwgf7gue6qly7

ANSI terminal control sequences removed. Original execution.log SHA-256: c366b13a4944e65f701bf93d83e9c2c2086f0e504963fcfe50f98d8b03927556.

PR 25308 mobile test registrations and browser lifecycle merge validation
63c8128b63b2482dcc5c749c6aaeb08a3c7443c6
Linux box-node-6a1069cb14bdd139 6.8.0-117-generic #117-Ubuntu SMP PREEMPT_DYNAMIC Tue May  5 19:26:24 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Using Node.js v26.12.1 (resolved from 26.12.1)
Scope: all 40 workspace projects
? Verifying lockfile against supply-chain policies (2058 entries)...
[WARN] GET https://registry.npmjs.org/@shikijs/langs/-/langs-4.2.0.tgz error (Failed to fetch https://registry.npmjs.org/@shikijs/langs/-/langs-4.2.0.tgz: error decoding response body: request or response body error: error reading a body from connection: Connection reset by peer (os error 104)) — 1
Will retry in 10s. 1 retries left.
Downloading node-pty@1.2.0-beta.15: 0.00 B/7.15 MB
Packages are hard linked from the content-addressable store to the virtual store.
  Content-addressable store is at: /home/user/.fleet-template/pnpm-store/v11
  Virtual store is at:             node_modules/.pnpm
Downloading sql.js@1.15.0: 0.00 B/13.63 MB
Downloading @rolldown/binding-linux-x64-gnu@1.0.0-rc.17: 0.00 B/9.39 MB
Downloading expo-image@58.0.15: 0.00 B/50.39 MB
Downloading expo-camera@58.0.10: 0.00 B/15.23 MB
Downloading @electric-sql/pglite@0.3.15: 0.00 B/7.96 MB
Downloading @img/sharp-libvips-linux-x64@1.3.4: 0.00 B/8.21 MB
Downloading drizzle-kit@1.0.0-rc.5-ab785fc: 0.00 B/22.92 MB
Downloading expo-video@58.0.11: 0.00 B/11.42 MB
Downloading expo-modules-core@58.0.22: 0.00 B/33.99 MB
Downloading react-native-worklets@0.13.0: 0.00 B/7.43 MB
Downloading expo-image-manipulator@58.0.14: 0.00 B/12.26 MB
Downloading @betteroffice/docx@0.4.3: 0.00 B/11.03 MB
Downloading pdfjs-dist@6.4.299: 0.00 B/8.53 MB
Downloading @rolldown/binding-linux-x64-gnu@1.2.13: 0.00 B/8.18 MB
Downloading hermes-compiler@260318099.0.4: 0.00 B/19.35 MB
Downloading three@0.180.0: 0.00 B/7.75 MB
Downloading @napi-rs/canvas-linux-x64-gnu@1.0.13: 0.00 B/15.16 MB
Downloading expo-sqlite@58.0.13: 0.00 B/10.93 MB
Downloading @betteroffice/fonts@0.4.0: 0.00 B/7.42 MB
Downloading @img/sharp-libvips-linux-x64@1.3.3: 0.00 B/8.17 MB
Downloading @oxlint-tsgolint/linux-x64@7.0.2004: 0.00 B/7.81 MB
Downloading react-native-pdf-jsi@5.0.0: 0.00 B/25.89 MB
Downloading @cloudflare/workerd-linux-64@1.20261012.1: 0.00 B/39.97 MB
Downloading @voidzero-dev/vite-plus-linux-x64-gnu@1.4.0: 0.00 B/14.80 MB
Progress: resolved 1661, reused 0, downloaded 124, added 96
Progress: resolved 1661, reused 0, downloaded 151, added 128
Progress: resolved 1661, reused 0, downloaded 156, added 154
[WARN] Tarball download average speed 6 KiB/s (size 10 KiB) is below 50 KiB/s: https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz (GET)
[WARN] Tarball download average speed 33 KiB/s (size 137 KiB) is below 50 KiB/s: https://registry.npmjs.org/@effect/openapi-generator/-/openapi-generator-4.0.5.tgz (GET)
Downloading heic-to@1.5.2: 0.00 B/5.89 MB
Downloading effect@4.0.5: 0.00 B/9.25 MB
Downloading @react-native-async-storage/async-storage@3.1.1: 0.00 B/15.03 MB
Downloading @cursor/sdk-linux-x64@1.0.38: 0.00 B/5.85 MB
Downloading expo-file-system@58.0.9: 0.00 B/8.38 MB
Downloading @oxlint/binding-linux-x64-gnu@1.89.0: 0.00 B/6.38 MB
Downloading @tsc-rs/linux-x64@0.8.0: 0.00 B/19.19 MB
Downloading @distilled.cloud/cloudflare@1.0.0-rc.17: 0.00 B/5.94 MB
Downloading expo-modules-macros@0.20.0: 0.00 B/5.93 MB
Downloading electron-winstaller@5.4.0: 0.00 B/9.14 MB
Progress: resolved 1661, reused 0, downloaded 185, added 160
Progress: resolved 1661, reused 0, downloaded 188, added 192
Progress: resolved 1661, reused 0, downloaded 252, added 247
Progress: resolved 1661, reused 0, downloaded 284, added 265
Progress: resolved 1661, reused 0, downloaded 316, added 312
Progress: resolved 1661, reused 0, downloaded 347, added 343
Progress: resolved 1661, reused 0, downloaded 538, added 529
Progress: resolved 1661, reused 0, downloaded 583, added 576
Downloading @cloudflare/workerd-linux-64@1.20261012.1: 38.36 MB/39.97 MB
✓ Lockfile passes supply-chain policies (2058 entries in 22.6s)
Lockfile is up to date, resolution step is skipped
Progress: resolved 1661, reused 0, downloaded 634, added 640
Progress: resolved 1661, reused 0, downloaded 666, added 668
Progress: resolved 1661, reused 0, downloaded 687, added 672
Downloading expo-image@58.0.15: 48.93 MB/50.39 MB
Downloading expo-image@58.0.15: 50.39 MB/50.39 MB, done
Progress: resolved 1661, reused 0, downloaded 762, added 768
Progress: resolved 1661, reused 0, downloaded 794, added 800
Progress: resolved 1661, reused 0, downloaded 826, added 822
Progress: resolved 1661, reused 0, downloaded 858, added 839
Progress: resolved 1661, reused 0, downloaded 858, added 864
Progress: resolved 1661, reused 0, downloaded 890, added 891
Progress: resolved 1661, reused 0, downloaded 954, added 960
Progress: resolved 1661, reused 0, downloaded 1082, added 1061
Progress: resolved 1661, reused 0, downloaded 1146, added 1148
Progress: resolved 1661, reused 0, downloaded 1168, added 1152
Progress: resolved 1661, reused 0, downloaded 1274, added 1249
Progress: resolved 1661, reused 0, downloaded 1274, added 1273
Progress: resolved 1661, reused 0, downloaded 1306, added 1312
Progress: resolved 1661, reused 0, downloaded 1370, added 1368
Progress: resolved 1661, reused 0, downloaded 1434, added 1435
Progress: resolved 1661, reused 0, downloaded 1466, added 1471
Progress: resolved 1661, reused 0, downloaded 1498, added 1504
Progress: resolved 1661, reused 0, downloaded 1530, added 1525
Progress: resolved 1661, reused 0, downloaded 1530, added 1530
Progress: resolved 1661, reused 0, downloaded 1562, added 1561
Progress: resolved 1661, reused 0, downloaded 1594, added 1574
Progress: resolved 1661, reused 0, downloaded 1594, added 1600
Progress: resolved 1661, reused 0, downloaded 1626, added 1623
Progress: resolved 1661, reused 0, downloaded 1626, added 1629
Progress: resolved 1661, reused 0, downloaded 1632, added 1632
Progress: resolved 1661, reused 0, downloaded 1634, added 1632
Progress: resolved 1661, reused 0, downloaded 1637, added 1632
Progress: resolved 1661, reused 0, downloaded 1654, added 1632
Progress: resolved 1661, reused 0, downloaded 1655, added 1655
Progress: resolved 1661, reused 0, downloaded 1655, added 1657
Packages: +1661
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 1661, reused 0, downloaded 1655, added 1661, done
.../node_modules/@tsc-rs/typescript postinstall$ node lib/install.js
.../esbuild@0.28.2/node_modules/esbuild postinstall$ node install.js
.../esbuild@0.25.12/node_modules/esbuild postinstall$ node install.js
.../node_modules/node-pty install$ node scripts/prebuild.js || node-gyp rebuild
.../react-native-enriched-markdown postinstall$ node postinstall.mjs
.../esbuild@0.28.2/node_modules/esbuild postinstall: Done
.../node_modules/node-pty install: > Checking prebuilds...
.../esbuild@0.25.12/node_modules/esbuild postinstall: Done
.../node_modules/node-pty install: Done
.../node_modules/node-pty postinstall$ node scripts/post-install.js
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] restoring vendored native assets ...
.../node_modules/node-pty postinstall: > Cleaning release folder...
.../node_modules/node-pty postinstall: > Moving conpty.dll...
.../node_modules/node-pty postinstall:   SKIPPED (not Windows)
.../node_modules/node-pty postinstall: Done
.../node_modules/@tsc-rs/typescript postinstall: Done
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] fetching runtime v0.26.3 from https://github.com/tree-sitter/tree-sitter/archive/refs/tags/v0.26.3.tar.gz
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] runtime -> react-native-enriched-markdown/cpp/highlight/vendor/tree-sitter/src
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-json@0.24.8 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-html@0.23.2 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-css@0.23.2 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading @tree-sitter-grammars/tree-sitter-markdown@0.3.2 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading @tree-sitter-grammars/tree-sitter-yaml@0.7.1 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-go@0.23.4 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-java@0.23.5 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-javascript@0.23.1 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-python@0.23.6 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-c@0.23.5 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-rust@0.23.2 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-bash@0.23.3 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-typescript@0.23.2 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-cpp@0.23.4 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-swift@0.7.0 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-php@0.24.2 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-ruby@0.23.1 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] downloading tree-sitter-c-sharp@0.23.1 ...
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] tree-sitter-cpp@0.23.4: download failed: terminated
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] WARNING: vendor-grammars failed. Code highlighting may not work.
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] fetching xcframework from https://github.com/erweixin/RaTeX/releases/download/v0.1.15/RaTeX.xcframework.zip
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] fetching source from https://github.com/erweixin/RaTeX/archive/refs/tags/v0.1.15.tar.gz
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] RaTeX v0.1.15 -> /tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/react-native-enriched-markdown@file+apps+mobile+deps+react-native-enriched-markdown-1.2_b1ae12d4005ca2d5b44575afb7808f60/node_modules/react-native-enriched-markdown/ios/vendor
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] done.
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] Some downloads failed. Ensure network access to registry.npmjs.org and github.com, then re-run: node node_modules/react-native-enriched-markdown/postinstall.mjs
.../react-native-enriched-markdown postinstall: [react-native-enriched-markdown] postinstall complete.
.../react-native-enriched-markdown postinstall: Done
. prepare$ vp config --no-agent
. prepare: Done

devDependencies:
+ @coderabbitai/config 1.1.0
+ @shadcn/lint 0.1.5
+ @types/node 24.12.4
+ knip 6.34.0
+ typescript <- @tsc-rs/typescript 0.8.0
+ vite-plus 1.4.0

Done in 1m 18.8s using pnpm v12.14.0

COMMAND: vp run check:changed e5559038165337caaf84ec162e3343b6c25120da
$ node scripts/check-changed.ts e5559038165337caaf84ec162e3343b6c25120da ⊘ cache disabled
check:changed: 22 files since e55590381653 (e5559038165337caaf84ec162e3343b6c25120da)
Runs everything: packages/client-runtime/package.json

> vp format  pass  0.3s
Checking formatting...

All matched files use the correct format.
Finished in 174ms on 22 files using 8 threads.

> vp lint  pass  1.3s
Found 0 warnings and 0 errors.
Finished in 1.2s on 21 files with 200 rules using 8 threads.

> vp knip 1/2  pass  17.7s

> vp unused patches  pass  26.8s
Scope: all 40 workspace projects
[WARN] 12 deprecated subdependencies found: @oslojs/asn1@1.0.0, @oslojs/binary@1.0.0, @oslojs/cbor@1.0.0, @oslojs/crypto@1.0.0, @oslojs/webauthn@1.0.0, boolean@3.2.0, crypto-js@4.2.0, glob@7.2.3, inflight@1.0.6, lodash.isequal@4.5.0, rimraf@2.6.3, uuid@7.0.3
[WARN] Issues with peer dependencies found. Run "pnpm peers check" to list them.
Done in 25.2s using pnpm v12.14.0

> vp graphql (apps/server)  pass  0.5s
~/apps/server$ graphqlgen --check ⊘ cache disabled

> vp knip 2/2  pass  23.0s

> vp typecheck (39 packages)  pass  29.3s
~/apps/desktop$ tsc --noEmit
~/packages/provider-acp-registry$ tsc --noEmit

~/packages/secret-provider-onepassword$ tsc --noEmit

~/packages/provider-opencode$ tsc --noEmit

~/packages/client-runtime$ tsc --noEmit

~/apps/web$ tsc --noEmit

~/packages/source-control-gitlab$ tsc --noEmit

~/packages/source-control-core$ tsc --noEmit

~/packages/provider-grok$ tsc --noEmit

~/packages/provider-acp$ tsc --noEmit

~/packages/secret-provider-definitions$ tsc --noEmit

~/scripts$ tsc --noEmit

~/packages/source-control-definitions$ tsc --noEmit

~/packages/effect-acp$ tsc --noEmit

~/apps/server$ tsc --noEmit

~/packages/provider-fx$ tsc --noEmit

~/packages/source-control-bitbucket$ tsc --noEmit

~/packages/secret-provider-core$ tsc --noEmit

~/packages/effect-codex-app-server$ tsc --noEmit

~/infra/task-cache$ tsc --noEmit

~/packages/tailscale$ tsc --noEmit

~/packages/source-control-gitcafe$ tsc --noEmit

~/apps/mobile$ tsc --noEmit

~/packages/provider-cursor$ tsc --noEmit

~/packages/source-control-azure-devops$ tsc --noEmit

~/packages/source-control-github$ tsc --noEmit

~/packages/provider-testing$ tsc --noEmit

~/packages/ssh$ tsc --noEmit

~/infra/relay$ tsc --noEmit

~/apps/marketing$ astro check

~/packages/source-control-forgejo$ tsc --noEmit

~/packages/shared$ tsc --noEmit
21:55:31 [types] Generated 161ms
21:55:31 [check] Getting diagnostics for Astro files in /tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/apps/marketing...

~/packages/provider-core$ tsc --noEmit

~/packages/contracts$ tsc --noEmit

~/packages/provider-pi$ tsc --noEmit

~/packages/source-control-testing$ tsc --noEmit

~/evals$ tsc --noEmit
Result (22 files): 
- 0 errors
- 0 warnings
- 0 hints


~/packages/provider-muse$ tsc --noEmit

~/oxlint-plugin-t3code$ tsc --noEmit


---
vp run: 0/39 cache hit (0%), 39/39 successful. @t3tools/scripts#typecheck (and 1 more) not cached because they modified their inputs. (Run `vp run --last-details` for full details)

> vp test (8 files)  pass  19.0s

 RUN  v5.0.5 /tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src

 ✓  @t3tools/mobile (react)  src/features/browser/preview-accessible-document.test.ts (1 test) 38ms
 ✓  @t3tools/client-runtime  src/preview/accessibleDocument.test.ts (8 tests) 15ms
 ✓  @t3tools/client-runtime  src/preview/serverBrowserStream.test.ts (8 tests) 9ms
 ✓  @t3tools/web (browser) (chromium)  src/browser/ServerBrowserSurface.browser.test.tsx (3 tests) 228ms
stdout | src/preview/ServerBrowser.test.ts > a rejected download releases the original and keeps no saved copy (save failed)
[21:55:50.705] WARN (#1688): server preview download failed {
  cause: Error: save interrupted
      at Object.saveAs (/tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/apps/server/src/preview/ServerBrowser.test.ts:1280:50)
      at saveDownload (/tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/apps/server/src/preview/ServerBrowser.ts:1076:7)
}

stdout | src/preview/ServerBrowser.test.ts > failed session and browser launches release capacity, as does closing a tab
[21:55:50.809] WARN (#3683): server preview tab failed to start {
  cause: Error: Chromium launch failed
      at /tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/apps/server/src/preview/ServerBrowser.test.ts:2312:24
      at Generator.next (<anonymous>)
      at ~effect/Effect/successCont (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:979:28)
      at ~effect/Effect/evaluate (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/core.js:342:30)
      at FiberImpl.runLoop (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:453:97)
      at FiberImpl.evaluate (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:402:23)
      at AsyncResource.runInAsyncScope (node:async_hooks:226:14)
      at FiberImpl.evaluate (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:396:27)
      at file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:808:17
      at Array.<anonymous> (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:1137:9)
}

 ✓  t3  src/preview/ServerBrowser.test.ts (52 tests) 262ms
 ✓  t3  src/preview/ServerBrowserAccessibility.test.ts (19 tests) 13ms
 ✓  t3  src/preview/ServerBrowserStream.test.ts (11 tests) 83ms
 ✓  t3  src/provider/AgentContextBudget.test.ts (1 test) 46ms

 Test Files  8 passed (8)
      Tests  103 passed (103)
   Start at  21:55:40
   Duration  15.63s (transform 53%, import 19%, worker 13%, setup 10%, environment 3%, tests 2%)

> vp react compiler (5 files)  pass  9.0s

 RUN  v5.0.5 /tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src

 ✓  @t3tools/web (unit)  src/reactCompilerCoverage.test.ts (1290 tests | 1288 skipped) 20ms
 ✓  @t3tools/mobile (unit)  src/reactCompilerCoverage.test.ts (1003 tests | 995 skipped) 3112ms
   ✓ React Compiler coverage (1003)
     ✓ Metro's transformer applies the compiler 624ms
     ✓ caches the thread feed derivation 1116ms
     ✓ caches the new-task model options and host environments 537ms
     ✓ registers the workspace inspector only when its renderer changes 611ms

 Test Files  2 passed (2)
      Tests  10 passed | 2283 skipped (2293)
   Start at  21:55:57
   Duration  7.62s (transform 63%, tests 28%, setup 6%, import 3%)

check:changed summary
  pass  unused patches  26.8s
  pass  format  0.3s
  pass  lint  1.3s
  pass  knip 1/2  17.7s
  pass  knip 2/2  23.0s
  pass  graphql (apps/server)  0.5s
  pass  typecheck (39 packages)  29.3s
  pass  test (8 files)  19.0s
  pass  react compiler (5 files)  9.0s
  CI also runs: full test suites, build, rust, release smoke
  pass not cached: files changed during the run


check:changed exit=0

COMMAND: vp test run apps/server/src/preview/ServerBrowser.test.ts apps/server/src/preview/ServerBrowserAccessibility.test.ts apps/server/src/preview/ServerBrowserStream.test.ts apps/server/src/preview/ServerBrowserContexts.test.ts apps/server/src/preview/ServerBrowserPage.test.ts packages/client-runtime/src/preview/accessibleDocument.test.ts packages/client-runtime/src/preview/serverBrowserStream.test.ts apps/mobile/src/features/browser/preview-accessible-document.test.ts apps/mobile/src/features/workspace/workspace-tabs-state.test.ts
note: You are running `vp test` as a Vite+ built-in command. If you meant to run the test npm script, use `vpr test` instead.

 RUN  v5.0.5 /tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src

 ✓  @t3tools/mobile (react)  src/features/browser/preview-accessible-document.test.ts (1 test) 27ms
 ✓  @t3tools/client-runtime  src/preview/accessibleDocument.test.ts (8 tests) 5ms
 ✓  @t3tools/mobile (react)  src/features/workspace/workspace-tabs-state.test.ts (20 tests) 28ms
 ✓  @t3tools/client-runtime  src/preview/serverBrowserStream.test.ts (8 tests) 8ms
stdout | src/preview/ServerBrowser.test.ts > a rejected download releases the original and keeps no saved copy (save failed)
[21:56:12.631] WARN (#1688): server preview download failed {
  cause: Error: save interrupted
      at Object.saveAs (/tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/apps/server/src/preview/ServerBrowser.test.ts:1280:50)
      at saveDownload (/tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/apps/server/src/preview/ServerBrowser.ts:1076:7)
}

stdout | src/preview/ServerBrowser.test.ts > failed session and browser launches release capacity, as does closing a tab
[21:56:12.739] WARN (#3683): server preview tab failed to start {
  cause: Error: Chromium launch failed
      at /tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/apps/server/src/preview/ServerBrowser.test.ts:2312:24
      at Generator.next (<anonymous>)
      at ~effect/Effect/successCont (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:979:28)
      at ~effect/Effect/evaluate (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/core.js:342:30)
      at FiberImpl.runLoop (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:453:97)
      at FiberImpl.evaluate (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:402:23)
      at AsyncResource.runInAsyncScope (node:async_hooks:226:14)
      at FiberImpl.evaluate (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:396:27)
      at file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:808:17
      at Array.<anonymous> (file:///tmp/fleet-job/j_b7o2prikwgf7gue6qly7/src/node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/internal/effect.js:1137:9)
}

 ✓  t3  src/preview/ServerBrowser.test.ts (52 tests) 262ms
 ✓  t3  src/preview/ServerBrowserStream.test.ts (11 tests) 80ms
 ✓  t3  src/preview/ServerBrowserAccessibility.test.ts (19 tests) 12ms
 ✓  t3  src/preview/ServerBrowserPage.test.ts (22 tests) 1782ms
 ✓  t3  src/preview/ServerBrowserContexts.test.ts (12 tests) 14ms

 Test Files  9 passed (9)
      Tests  153 passed (153)
   Start at  21:56:07
   Duration  10.02s (transform 55%, import 23%, tests 12%, setup 7%, environment 3%)


preview tests exit=0
TERM environment variable not set.

Maria's historical 50a12e6 web screenshots show the same W3C page and 1440 by 1000 viewport:

main: streamed page without semantics

updated: accessible page headings and links

The earlier mobile document comparison uses the same form data and compares the original global textarea rule with the scoped rule. This was a generated document in Chrome, not a native WebView:

original mobile rule: hidden textarea

scoped mobile rule: visible textarea

Implemented with Claude Opus 5.5 in Claude Code and GPT-6.1-sol in Codex. Reviewed with GPT-6.1-sol in Codex. Maria contributed fixes and browser verification with GPT-6.1-sol.

PR Batch Tester and others added 4 commits October 26, 2026 03:55
Streamed browser tabs (web, remote desktop, mobile) were a JPEG canvas plus a
hidden input, so screen readers found one text field and nothing else.

Viewers can now turn on an accessible view. The server enables Chromium's
Accessibility domain for that tab only while someone subscribes, joins the
per-frame trees (including out-of-process iframes), drops ignored wrappers
while keeping their descendants, hides secret field values, and sends full
coalesced snapshots with backpressure redelivery. Read-only viewers may
subscribe; activate and set-value actions run only for the controlling viewer
under SessionControl and only against the current document and node ids.
A shared client-runtime renderer draws the snapshot as native headings,
landmarks, links, buttons and form fields, updating in place by node id. Web
adds a toggle to the streamed view's bar; mobile adds one to the full-screen
viewer and renders inside the same WebView. Passive floating previews never
subscribe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ntact

- Editable field values are sent exactly (whitespace and label-equal text kept), still bounded and still withheld for secret or masked fields.
- Tree items render as role=treeitem containers so nested items stay reachable and activatable; Enter and Space activate them.
- Child sync removes obsolete nodes first and keeps the focused child in place while siblings move around it.
- Out-of-process frame sessions enable the Accessibility domain and listen for changes; their listeners, domain and session are released on frame navigation, detach and unsubscribe.
- Any frame navigation or detach clears action targets until the next capture, and a capture that spans a frame change cannot be acted on.
- A viewer backlog reset keeps the newest queued accessibility document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Oct 26, 2026

maria-rcks commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

updated the original branch at 6e0ed16c7f34bc72ef6cffb994fdd8cea8671e5d, preserving its commits and merging github/main without rebasing.

thanks @shivamhwp for the shared semantic renderer, opt-in snapshots, and existing control checks. those remain intact. i scoped the mobile hidden-input styles, kept its overlay inside the viewport, disabled the raw keyboard buffer while accessible view is open, and made the web toggle local to each surface. real chromium also exposed lost inline whitespace and secret values in field descendants; both now have failing-first regressions and fixes. unread iframe content now produces an incomplete-document notice.

verification passed:

  • github ci at this head: 21 checks passed, six skipped.
  • blacksmith vp run check:changed: formatting, lint, both knip passes, graphql generation, 35 package typechecks, and 80 tests across six existing files. no new test files added.
  • current main reproduced the missing semantics: the streamed page exposed only the raw browser input. the updated real web client exposes headings, links, and form controls.
  • real streamed text and checkbox edits, fresh subscriptions, release/take control, and keyboard navigation past the semantic controls. before the keyboard fix, two consecutive tabs stayed in the hidden buffer; afterward tab exits the page controls.
  • real chromium capture keeps inline spaces and excludes one-time-code values, including their descendants.
  • the actual generated mobile document connected with a media ticket, edited multiline text on the remote page, retained it after resubscribing, restored the raw input only outside accessible mode, and fit a 390 by 844 viewport. this checks the document in chrome, not a native mobile client.

unverified: native ios/android webviews, electron, and an actual screen reader. theo's requested approval is still outstanding, so this remains a draft. @shivamhwp: the desktop cdp relay currently rejects separate iframe targets; unsupported embedded content is now reported, but complete desktop out-of-process iframe support remains a relay follow-up.

the main/updated screenshots use the same w3c page and viewport:

main: streamed w3c page without semantic content

updated: the same page rendered with headings and links

the mobile document comparison uses the same streamed form data. the before capture reapplies the original pr's global textarea rule; the after capture uses the scoped rule:

original mobile rule: delivery instructions textarea is hidden

scoped mobile rule: delivery instructions textarea is visible

real streamed client: toggle, edit, checkbox, control release and restoration

video playback and seeking passed at the uploaded url. git.cafe currently displays external videos as links; the four screenshots are native attachments.

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

verified unchanged head 50a12e6daa352baf52f416ca2a235494a5b0c0f6 on this Linux Boat VM. no commits or pushes were needed.

  • installed and ran github/main at bd84b1781a in /home/user/main. the actual streamed W3C checkbox page was visible, but its heading and controls were absent from the client's semantic tree; only the raw "Browser page" input was exposed.
  • stopped main's dev server before starting this head. installed with vp i and ran the real server/web client with isolated state. drove /usr/bin/google-chrome using the repo's Playwright dependency. projects and threads were created through the UI, pointing at the real git checkouts. real Codex gpt-6.1-sol turns completed on both revisions. a further provider turn used preview_status and preview_snapshot to read the same live form.
  • on this head, Accessible view exposes the same W3C page's headings, links and four custom checkboxes. checkbox activation changes the remote page and survives turning Accessible view off/on.
  • edited a real httpbin form's name and multiline instructions, toggled its native checkbox, and submitted through Accessible view. the actual HTTP POST response contained all three values. switching back to pixels also showed the remote edits.
  • neighboring behavior passed: release/take control preserves readable semantics and disables/restores actions; Escape cancels an unsent draft; Tab exits the last semantic control without entering the hidden keyboard buffer; navigating replaces the old semantic document; disabling Accessible view restores the pixel stream.
  • Blacksmith ran the five existing server/client-runtime preview test files: 79 tests passed. current-head CI reports 27 successful contexts, zero failing or pending. no new test files were added.

short runtime transcript:

main UI: Accessible view buttons=0, remote heading=0, Browser page input enabled
main Codex: /home/user/main; git worktree=true; MAIN_PROVIDER_OK
PR Codex: /home/user/t3code; git worktree=true; PR_PROVIDER_OK
provider browser tools: https://httpbin.org/forms/post; actual form labels returned
POST https://httpbin.org/post
form.custname = "Maria real browser verification"
form.topping = "bacon"
form.comments = "Leave at the door\r\nKeep the bell quiet"
Blacksmith: 5 test files passed, 79 tests passed

the screenshots use the same W3C page and 1440 by 1000 client viewport.

main: streamed W3C page without semantic controls

PR: same W3C page with semantic headings and links

the 15-second recording shows the actual form, pixel/semantic switching, release/take control, multiline editing and keyboard exit. playback is slowed to half speed for inspection. the exported clip and uploaded player were inspected; playback and seeking passed.

real form interaction and control release/restoration

Not verified

native iOS/Android WebViews, Electron/remote desktop, macOS/Windows, an actual screen-reader session, multi-device/relay connections, and out-of-process iframe behavior were not exercised here. this pass does not resolve the PR's existing screen-reader/native-client verification caveats or its requested approval.

startup note: the root checkout initially selected ~/.t3; that process was stopped before verification data was created and restarted with explicit isolated home /home/user/t3code/.t3. its pairing request may have added an auth session to the disposable VM's existing state.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants