Files
lumbridge-code/docs/decisions/0017-gpui-dependency-and-the-floem-disposition.md
T
Metal AgentandClaude Opus 5 316fa32745 Graduate the shell out of spikes/ into apps/lumbridge
The product was spikes/gpui-shell: a cargo workspace of its own, named in the
root manifest's exclude list. It inherited neither unsafe_code = "forbid" nor
clippy pedantic, and ./scripts/ci.sh never compiled it. Every test written into
it silently never ran, and apps/lumbridge was an eleven-line stub printing a
version string.

Four separate research passes over the sidebar, settings, devices, and theme
work independently discovered they were about to write substantial new code into
that directory. Graduating first means writing it once.

- apps/lumbridge is the product; spikes/ui-shell-model becomes
  crates/lumbridge-ui-fixture and joins the workspace.
- scripts/ci.sh takes --headless and --ui. The headless pass excludes the two UI
  crates by name, so a contributor changing lumbridge-core does not wait on a
  window toolkit, and a runner that cannot carry GPUI still gates everything
  else. A new crate is headless by default rather than silently joining the slow
  job.
- scripts/native-libs.sh replaces the ad-hoc symlink in the launcher, and says
  which apt package actually fixes the problem instead of working around it
  silently. The stale libxcb/libxkbcommon symlinks in the old spike target
  directory are gone; only libxkbcommon-x11.so was ever needed.
- deny.toml and cargo deny check licenses. spikes/README.md called GPUI's
  licence closure a hard gate and the scorecard scored it pending; graduation
  makes it the product's closure, so it is enforced rather than described. Two
  rejections were reviewed and allowed with the reasoning recorded in the file:
  webpki-roots under CDLA-Permissive-2.0 (Mozilla's CA store, data not code,
  reached through ureq) and libfuzzer-sys under NCSA (reached only under
  all-features via gpui's image decoder; no shipped build links it).

Clippy pedantic across both crates is clean at -D warnings. render was 353
lines; render_sidebar, render_tabs, and render_root come out of it, which the
sidebar rework needed anyway. The remaining over-length functions are single
declarative element trees and carry per-function allows with reasons, not a
blanket suppression.

Decision 0017 records the two calls this forces: published gpui 0.2.2 behind an
accessibility adapter rather than an unpinned Zed revision and an MSRV bump, and
Floem frozen rather than maintained in parity or deleted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 23:05:12 -07:00

70 lines
3.7 KiB
Markdown

# 0017: The product graduates on published GPUI, behind an accessibility adapter, and Floem is frozen
Status: accepted. Supersedes the provisional direction in `UI_SPIKE_SCORECARD.md`.
Until now the product was `spikes/gpui-shell`: a cargo workspace of its own,
listed in the root manifest's `exclude`, so it inherited neither
`unsafe_code = "forbid"` nor `clippy pedantic`, and `./scripts/ci.sh` never
compiled it. Every test written into it silently never ran. That is the reason
this record exists before any feature work: the sidebar, settings, and devices
pages are all substantial new code, and writing them into an unlinted directory
would mean writing them twice.
## The GPUI dependency
The product ships on published `gpui 0.2.2` from crates.io, not on a Zed git
revision.
The scorecard's provisional direction was "GPUI-first using current Zed GPUI
behind a narrow Lumbridge UI adapter", and that is being inverted here, so the
cost is stated plainly: **published 0.2.2 has no AccessKit dependency.** There
is no `Role`, no `aria_label`. Every pane and every sidebar row ships
screen-reader-silent, and `UX_VERTICAL_SLICE.md`'s hard gate — "the
accessibility tree names each pane, selected state, execution target, and
waiting state" — is knowingly unmet.
It is chosen anyway because a git dependency on an unpinned upstream, plus an
MSRV move from 1.94 to 1.97.1 across every crate in the workspace, is a large
standing cost to carry for a capability we can stage.
The mitigation is a narrow `a11y` adapter trait, introduced now while there are
few call sites: it no-ops on 0.2.2 and calls real roles and labels on a git
revision. The migration is then a swap rather than a rewrite.
`spikes/gpui-accessibility-probe` (Zed revision `ce48461e`, toolchain 1.97.1) is
retained, not deleted, as the standing proof that the semantics compile with
stable IDs and roles. Reversing this decision means changing one dependency line
and one adapter implementation.
The scorecard's `pending` row for GPUI's dependency-license closure stops being
a spike question the moment 746 lockfile packages enter the root workspace: it
becomes the product's license closure. `deny.toml` and `cargo deny check
licenses` land in the same change, and the result is pasted into that row.
## Floem
`spikes/floem-shell` is **frozen**. It is no longer described as a comparable
candidate, and `ARCHITECTURE.md`'s "UI decision gate" and `TESTING.md`'s
"identical GPUI/Floem action replay" line are corrected to match.
Comparability was already gone and already conceded — the scorecard records that
"the Floem shell still renders the static footer fixtures, so the two candidates
are no longer comparable on that strip", which the usage ledger work caused. It
also records Floem failing the accessibility gate outright, with no AccessKit at
its pinned revision. Keeping true parity would mean theming it alongside every
visual change forever, which is a recurring cost for a candidate that has
already lost on a hard gate.
Freezing rather than deleting keeps the evidence trail: if the GPUI bet ever
needs revisiting, the comparison exists at the revision where it was made. What
freezing does not license is leaving falsehoods on screen — its fabricated
footer quota and its fixture worktree list naming a developer's machines were
deleted in the same pass as the GPUI shell's.
## The default theme and accent
The UI accent stays cool blue. `BRAND.md` scopes Ember (`#FF6B35`) to the
application icon and warns against low-contrast orange behind the mark;
`UX_VERTICAL_SLICE.md` commits the UI to one cool-blue action accent. Ember is
offered as a user-selectable accent rather than made the default, so neither
document needs amending.