The adapter is only worth having if the call sites exist, so this wires the ten elements `UX_VERTICAL_SLICE.md` actually names and stops there. The shell root is an application; the sidebar, its row list and the workspace are named regions; every workspace panel is a pane carrying its label, its execution target, its waiting state and whether it owns the keyboard; every live terminal surface is a terminal; the command palette and the add-panel chooser are dialogs; the footer's usage strip is a status. Seven elements gained a stable GPUI id along the way, because an element worth naming to a screen reader is an element worth keeping state on. The other 137 divs are left alone deliberately. Fixed-width slots, meters, chips, borders and painted terminal cell runs have no identity to hang a node on, and publishing 80x24 nodes a frame would be a tree nobody can navigate and a cost on every repaint. No new strings were invented for the screen reader where the model already had one. `describe()` labels each sidebar row -- that is its caller, so its `#[allow(dead_code)]` is deleted rather than carried, as decision 0023 requires. The three words in a pane header's corner and the three words its description leads with now come from one function. The two lines a pane header prints about where it runs and what its process is doing moved out of `pane_context` into `pane_header_lines`, because the pane's semantic node is built one level up in `workspace_panel` and recomputing them there would have meant two expressions that agree today and disagree after the first edit. The add-panel chooser's heading and its accessible name are one constant. Four labels are new strings, because nothing on screen names these areas: "Lumbridge", "Workspace", "Sidebar" and "Harness usage". Each is the name the code and the docs already use for the thing it labels. The scorecard's accessibility row now reads fail rather than a hedge. The call sites are wired; the semantics are absent, because the adapter no-ops. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SPYebLiN2w4TqnHUYGdECq
133 lines
8.0 KiB
Markdown
133 lines
8.0 KiB
Markdown
# Native UI spike scorecard
|
||
|
||
The GPUI and Floem programs under `spikes/` consume the same six-pane fixture.
|
||
No product framework decision is accepted until both rows contain measurements
|
||
from macOS and Linux and the hard gates pass.
|
||
|
||
| Criterion | Hard gate | GPUI | Floem |
|
||
|---|---:|---:|---:|
|
||
| Builds on macOS Apple Silicon | yes | pending | pending |
|
||
| Builds on Ubuntu | yes | conditional | pass |
|
||
| Builds on Omarchy/Arch | yes | pending | pending |
|
||
| Dependency/license closure permits Apache-2.0 distribution | yes | pending | pending |
|
||
| Keyboard navigation + AccessKit tree | yes | fail: keyboard passes and the call sites are wired, but the adapter no-ops on 0.2.2, so no accessibility tree is produced | fail: no AccessKit integration at pinned revision |
|
||
| IME and composed Unicode input | yes | framework API exists; end-to-end pending | editor API exists; end-to-end pending |
|
||
| Isolated system browser child | yes | pending | pending |
|
||
| Cold startup, p50/p95 | record | pending | pending |
|
||
| Idle RSS / six-stream RSS | record | pending | pending |
|
||
| Key-to-present p50/p95 | record | pending | pending |
|
||
| Six-stream frame p95/p99 | record | pending | pending |
|
||
| Release binary/package size | record | pending | pending |
|
||
| Native menu/window/clipboard/drag-and-drop | review | pending | pending |
|
||
| API clarity and maintenance burden | review | pending | pending |
|
||
|
||
The current programs establish dependency, build, launch, and interaction
|
||
baselines. GPUI now routes a real PTY through a VT engine and keyboard encoder,
|
||
paints coalesced styled cell runs and cursor shapes, and derives PTY rows/columns
|
||
from the 60% terminal region inside each responsive one/three/five-panel layout
|
||
when the window or attached panel count changes. Retained-history
|
||
page/top/bottom navigation is wired. Panel detach/reattach keeps background
|
||
surface updates alive and exposes detached sessions in the sidebar. Text
|
||
selection, mouse modes, a native Markdown editor, and one isolated browser child
|
||
remain.
|
||
|
||
## Ubuntu baseline — metal, 2026-08-31
|
||
|
||
Host: Ubuntu 24.04 x86_64, Rust 1.94.1. Both candidates used the same 1280×800
|
||
six-pane fixture and were launched under the active X11 desktop.
|
||
|
||
| Observation | GPUI 0.2.2 | Floem `778bb5f2` |
|
||
|---|---:|---:|
|
||
| `cargo check` from downloaded dependency cache | 20.76 s, 1.04 GiB max RSS | 24.26 s first attempt + 4.06 s after enabling required editor feature, 753 MiB max RSS |
|
||
| Debug executable link | pass with a user-local linker symlink for installed `libxkbcommon-x11.so.0` | pass |
|
||
| Debug executable size | 442 MiB | 475 MiB |
|
||
| Native window launch and six-pane render | pass | pass |
|
||
| Root workspace CI | 8/8 tests, strict Clippy and doctests pass in 10.79 s | shared result |
|
||
|
||
These are cold-development baselines, not startup, release-size, or runtime
|
||
performance numbers. GPUI's Ubuntu row remains conditional because the host has
|
||
the runtime `libxkbcommon-x11.so.0` but lacks the unversioned development linker
|
||
name normally supplied by `libxkbcommon-x11-dev`. Floem current main also
|
||
requires its `editor` feature for the style/label modules used by this shell;
|
||
that feature is now explicit in the spike. Neither build result by itself
|
||
decides the UI stack.
|
||
|
||
## Accessibility gate and provisional direction
|
||
|
||
The published `gpui 0.2.2` used by the visual shell has focus and keyboard
|
||
actions but does not expose the current AccessKit element API. An isolated probe
|
||
therefore pins GPUI directly to Zed commit
|
||
`ce48461eaadd16c65c31f835511ab96bd3b6e746` with its matching Rust 1.97.1
|
||
toolchain. The real element wiring compiles with stable accessibility IDs,
|
||
workspace/pane/terminal roles, selected state, focus tracking, and a needs-input
|
||
description. The same probe installs real `EntityInputHandler` and
|
||
`ElementInputHandler` implementations and tests marked-text commit, a composed
|
||
accent, and a multi-codepoint emoji without splitting UTF-8. Three deterministic
|
||
tests pass. AT-SPI/OS IME on Linux and VoiceOver/IME on macOS remain end-to-end
|
||
gates.
|
||
|
||
### Where the adapter has got to, and what it does not do
|
||
|
||
`apps/lumbridge/src/a11y.rs` is the adapter decision 0017 promised and never
|
||
wrote, landed as the first stage of decision 0023. Ten elements now declare what
|
||
they mean — the shell root, the sidebar and its row list, every sidebar row,
|
||
the workspace region, every workspace pane, every live terminal surface, the
|
||
command palette, the add-panel chooser, and the footer's usage strip — using the
|
||
role, label, description, selected-state and stable-identity vocabulary the probe
|
||
proves exists at Zed `ce48461e`. `sidebar::model::describe`, written and tested
|
||
under decision 0017 and called by nothing for the whole life of that record, is
|
||
now what labels a sidebar row, and its `#[allow(dead_code)]` is deleted.
|
||
|
||
**The gate is still failed, and this work does not move it.** The adapter's
|
||
bodies take the value they are given and drop it, because published `gpui 0.2.2`
|
||
has no AccessKit dependency to hand it to. Nothing reaches AT-SPI or VoiceOver;
|
||
there is no accessibility tree to inspect. What has changed is that the four
|
||
facts `UX_VERTICAL_SLICE.md` requires — which pane, its selected state, its
|
||
execution target, its waiting state — are now derived in one tested place
|
||
instead of being absent from the code entirely, so stage 5 of decision 0023 is a
|
||
change to one file rather than a pass over the renderer. Eight unit tests cover
|
||
the derivation. None of them is an assistive-technology claim.
|
||
|
||
The pinned Floem revision has keyboard focus and editor IME plumbing but no
|
||
AccessKit dependency or semantic tree. That fails Lumbridge's accessibility
|
||
gate without a maintained framework fork or adapter. The provisional direction
|
||
is therefore **GPUI-first using current Zed GPUI behind a narrow Lumbridge UI
|
||
adapter**. The published GPUI shell remains the lightweight interaction and
|
||
visual benchmark until the dependency/toolchain migration is accepted.
|
||
|
||
This is not the final cross-platform release decision. Current-GPUI validation
|
||
on amd-server required a 624 MiB Rust 1.97.1 toolchain, a 691-package lockfile,
|
||
and 4.4 GiB of debug artifacts across check, test, Clippy, and build. Packaging,
|
||
license closure, IME, platform assistive technology, browser parenting, macOS,
|
||
and Omarchy still have to pass.
|
||
|
||
The comparable Floem shell passes build, test, strict Clippy, live rendering,
|
||
streaming, mouse selection, and numeric pane selection on metal. Its command
|
||
palette opens through the visible clickable affordance and uses Floem's native
|
||
`TextInput`, but Ctrl/Cmd+K did not reach the handler in the X11 automation
|
||
probe. That unresolved focus/event-routing behavior is another current strike
|
||
against adopting Floem; it is recorded rather than hidden behind the clickable
|
||
fallback.
|
||
|
||
## Measurement semantics
|
||
|
||
Both renderers retain the same all-deterministic six-surface action stream for
|
||
comparison. GPUI now layers an unbounded, SQLite-snapshotted panel registry over
|
||
that benchmark and presents one, three, or five vertical panels, each with its
|
||
own 20/60/20 context/work/decision composition. The Add Panel chooser creates
|
||
Terminal, Browser, Markdown, and Review panels beside the selection or
|
||
reattaches an existing session. Every Terminal panel receives an independent
|
||
actor-owned VT session; the three seed non-terminal surfaces keep deterministic
|
||
updates running. Counters
|
||
separate external PTY batches/lines from total model updates. The GPUI footer's
|
||
usage zone is no longer a constant string: it renders a `lumbridge-core`
|
||
projection for the selected panel's account profile, with a provenance chip and
|
||
explicit unavailable phrases, and its sidebar attention count and runtime rows
|
||
are derived from live panel and ledger state. The Floem shell still renders the
|
||
static footer fixtures, so the two candidates are no longer comparable on that
|
||
strip. The GPUI footer also
|
||
reports dispatch-to-element-build p50/p95 over a bounded 256-sample window. It
|
||
is deliberately not called key-to-present or frame-present latency: neither
|
||
candidate exposes a reliable public cross-platform post-present callback. True
|
||
present latency requires an external platform probe.
|