Prompt rail: one Codex-sized height that nothing changes; the wave keeps up with a sweep

Merged
TE
2d ago
+123-59

Leo, 2026-11-04:

hovering across the session rail gets a bit laggy and the missing chunks of the wave bother me :( it needs to get faster

also the left side session rail should just be having a nicer max height instead of going all the way up and down. make it look like codex's size.

also the height of the left scroll rail should never be affected by anything

Leo-ask: ask-0eea9d95e5

What changes

  • One height for every chat, the Codex rail's size. The prompt rail's box was max(count Ɨ 10, 320) capped at 92% of the window, so in a long chat it ran from the top of the pane to the bottom. It is now 240 px for every chat. The prompt count, the window, the pane's height, the prompts on screen (the band) and the bottom stack don't change it. Past 24 prompts its list scrolls and keeps the band in view (railScrollTop). Only a view too short for 240 px clips it (railRoom). A composer or tray that grows tall enough to reach the rail lays over its foot: the rail neither moves nor shortens (Leo, 2026-11-03: "i just don't like it when the thing shifts"). The other arms keep the old foot-shortening (railClearHeight). height.experiment.ts gains fixed-200, fixed-240 (default) and fixed-280 (fixed: true in RAIL_HEIGHTS), and the agent-pane.thread-minimap-height gallery entry's notes describe them beside the old arms.
  • No holes in the wave on a sweep. In the zipper (the shipped wave), every tick that was not the hovered one eased to its new length over 180 ms. So during a sweep the hovered tick snapped long, but the rows ahead of it were still short, and the trailing rows were still long. The bump had holes on its leading side. Now growing ticks ease over the quick step (80 ms), like the hovered tick does on arrival, and shrinking ticks keep 180 ms as the zipper's tail. The hovered tick is still the single longest every frame.

The hover lag itself (React work per row change, the preview card) is measured separately, and its fix follows in a separate PR.

Tests

Red first (fa0b8ea), then the fix:

  • bun test test/thread-minimap-wave-model.test.ts: new "a sweep keeps the bump whole". On base, after one frame of a 60 Hz sweep, the row ahead has 0.18 of its length; it needs more than 0.35. Passes on head.
  • bun test test/thread-minimap-rail.test.tsx: new "the rail is one height, the Codex rail's, whatever the prompt count or the pane's height" (1 to 1,000 prompts, 400 to 2,100 px views → 240). Fails on base (320, 450, 662, …), passes on head.
  • bun test test/thread-minimap-rail.test.tsx: the band (1, 24, 50 and 1,000 prompts on screen) keeps 240. Fails at 8a21b182 (500 for 50), passes on head.
  • bun test test/thread-rail-layout-box.test.tsx: the rail's box is identical with a 120 px, a 188 px and a rail-reaching stack. Fails at 8a21b182 (the height shrank), passes on head.
  • test/thread-rail-full-height.test.tsx was updated to the fixed box: the rows not drawn are counted through the list's gaps.
  • All test/thread-minimap* and test/thread-rail* jsdom suites pass locally.

Observed / Not run

  • Observed: the bun suites above, red on base and green on head; vp fmt --check on changed files. scripts/web-lint.sh fails only on base files (pages/changelog/updateSurfaces.css design token, App.tsx and others' format).
  • Not run: the type-aware lint/type check (left to CI on this shared host), and gallery captures.

Follow-ups

Review follow-ups: #35239.

Spec

design/session-rail.md "Height and overflow" (leo-workspace) should read: the compact rail is one fixed height, 240 px (the Codex rail's size), for every chat. Prompt count, window, pane height, the band and the bottom stack never change it or move it (a stack tall enough lays over its foot), and a view shorter than that clips it. Past 24 prompts its list scrolls. This replaces "starts at 320 px, grows toward 92%" (last good commit d53567b44a41). This host can't publish to leo-workspace, so that edit follows from a lane that can.

Changelog

  • Changed: The agent chat's prompt rail is one compact height for every chat, and its hover wave keeps up with a quick sweep.

risk:normal

šŸ¤– Generated with Claude Code

Agent session: agent session