VS Code Minimap: streaming placeholder looks in the gallery; paired bench arm (4/4)

Merged
TE
11d ago
+287-19

Last of the VS Code Minimap stack: #25275, #25276 and #25185 have landed, and #25422 (the keyboard scrollbar) lands before this PR. It is stacked on #25422; its own diff over #25422 is +287/−19.

Leo's words (2026-10-26)

... the mini map ... just because something's streaming in, like you could just put skeletons or some other sort of placeholder ... You can even do, like, a cute shimmer effect.

What this adds

  • Experiment: chatMinimap/placeholder.experiment.ts (chat-minimap-placeholder) offers four looks for the streaming reply's place: skeleton, shimmer (the default, what #25185 ships), dotted and ghost lines. Only the shimmer moves. Its stop condition and Reduce Motion fallback are the same as in #25185: it stops when the placeholder unmounts at the stream's end, and it's off under Reduce Motion.

  • Gallery: the entry agent-pane.chat-minimap has two variants, "streaming" and "at-rest". Its compare view shows the four looks side by side.

  • Bench: webviews/bench/thread-minimap-frame-cost.bench.ts (landed in #25173) gains:

    • a <rail>+canvas arm (the setting turned on through a dev-server-only hook in dev.tsx, window.cmuxDevDisplay, since a standalone daemon has no host to send the display event);
    • a per-run canvas draw count;
    • SCENARIOS= selection;
    • arms interleaved in alternating order;
    • paired per-round p95 deltas (median, min, max, rounds under 1 ms).

    These are the numbers in #25185.

placeholders

The image shows skeleton, shimmer (frame held mid-sweep), dotted and ghost lines.

The 1 ms budget now fails the run (re-review P2). The default arms include the minimap's pair (off, off+canvas, then compact, full). The run exits 1 when a +canvas arm's median p95 delta over its rail is over 1 ms in scroll or stream, and prints which. It exits 2 when the budget can't be checked: no +canvas arm with its rail, scroll or stream left out, or a +canvas page that drew no minimap. It is still a bench, not wired into CI.

The gate on a dedicated 32-vCPU Linux box (decides this stack): within budget

The bench now builds its own pane from the dev entry (vite's build of vite.config.acpmux-pane.mjs) when PROD_DIR is unset. It refuses the shipped pane (build-agent-pane-web.sh's output, with pane.js at its root) with exit 2: that pane waits for the app's native bridge, never joins the bench's stand-in daemon, and so timed out on every arm on CI. If a page never shows the chat, the bench prints whether it joined the daemon and its console errors, failed requests and HTTP errors. Missing static files (the dev entry's /__dev-host/* calls) are a 404, not a thrown ENOENT.

Run 40302041033 (cmux-ci test --setup playwright, Blacksmith 32 vCPU, load ~0.5), production build, 2,000 rows, unchanged gate. Values are minimap on − off:

Default arms (off, off+canvas, compact, full), 10 rounds

p95 deltamedianminmaxrounds under 1 ms
idle+0.01−0.01+0.0610/10
scroll+0.20−1.18+2.197/10
stream+0.35−1.63+3.316/10

The on/off pair alone, 20 rounds

p95 deltamedianminmaxrounds under 1 ms
idle+0.01−0.03+0.0920/20
scroll+0.49−1.95+2.4812/20
stream+0.18−2.06+2.2517/20

Both runs printed minimap budget: within 1 ms (median p95 delta) in scroll and stream. On that run both still exited 1, from the ENOENT noise that this PR's 404 change fixes (not re-run on CI since); the median deltas are what the gate reads. Absolute busy p95 per frame, default arms: scroll 6.96 off / 7.29 on, stream 9.59 off / 10.28 on, against the compact rail's 47.09 scroll and 65.66 stream. Canvas draws per run: 0 scrolling, 4 streaming (one per reply ending). The earlier numbers in this PR came from huge-blue, a shared and loaded host (load 9–20, spreads ±15–70 ms), and are superseded by these.

Review fixes (gpt-6-astra), tested by webviews/test/chat-minimap-looks.test.ts (fails on the first commit):

  • The app always shimmers. placeholderLook() passes stored: {}, so a stored cmux.experiments override never changes the look in the app. Only the gallery, which sets globalThis.cmuxExperiments for its arms, shows the others.
  • The compare script settles on both variants. It now waits for the drawn picture, which both reach, instead of a placeholder the at-rest variant never has. In a real gallery frame all 8 cells (2 variants × 4 arms) settle, and each streaming cell shows its own look.

The gallery manifest, agent-pane entries and play-names tests pass, and chat-minimap still passes with the experiment wired in.

Risk

None at runtime beyond #25185: the default arm is the shimmer it already ships. The dev.tsx hook exists only on the dev entry with a #endpoint daemon.

Agent session: huge-blue

🤖 Generated with Claude Code