Fix the combined model picker's harness list and sizing

Merged
TE
9d ago
+482-302

Summary

The compact model menu can gain peer-machine harness rows and a blank block below Fast mode. Keep the bottom chip, list each current-machine harness once in a horizontal strip, size the menu to its visible content and window, and keep its opening side as tabs shrink. Fast mode is now a visible switch.

Leo's requirement (relayed): “harness list current machine only, each harness once; machines stay in machine chip.” Launch configurations such as claude-sr now live under Profile; Account keeps the existing signed-in subscription/API-key route choices. Before a session exists, the account API is unavailable, so New Tab offers profiles without inventing account identities.

Cause and related work

At original reproduction base 80818cb07d6b8cab7dd0622f39c5259d9bf72956; the rebased PR base is c5dd46c48719bb4403ec517e76b32a8c85da62ed, modelCatalog.ts:12,43–45 explicitly promotes probe-only IDs, including peers. direct.ts:5573–5579 merges local harness names with those model probes. The picker now admits only named local harnesses and ignores peer probes.

The vertical rail introduced by c61789058e363 stretches the short model list: modelPicker.css:265,308,327–332. The downward Claude browser reproduction leaves 131px after Fast with ten harnesses. Downward New Tab already has holdHeight=false on this base; its gap comes from the rail. Chat also reserves hidden tallest-tab rows. Both sizing paths are replaced here with content sizing and a strip at the chip-facing edge. The separate full picker's d9ce210e height floor is not involved.

I read the full #24194 diff at 724ea2ddd590960b5131bd415e2557a94234b433. This PR supersedes its tallest-tab/spacer sizing approach for the compact picker while retaining its no-jump intent through fixed opening side and chip-facing harness controls. No changes were made to #24194 or Lucas's branch. Requested lucasr1b review.

Takeback rationale

Takes back #24224: replace its bare Fast Off/On state text with the owner-requested accessible switch; the underlying Fast mode behavior and coverage remain.

Testing

On GCP gcp-agent-lane-1, worktree /home/cmux/Projects/checkouts/cmux/lane--nx-model-picker-toggle:

  • Red first: peer probes add extra harnesses; Fast says Fast modeOff; downward Claude leaves 131px; midpoint tall→short tabs change top→bottom. The repaired discriminators pass.
  • 44 focused tests pass across the layout, quick menu, local catalog, New Tab default, and model-pick suites. Seven are real Chromium tests covering downward/upward/flipped/midpoint placement, narrow windows, keyboard harness visibility, fade reset, Profile/Account separation and Fast.
  • All four production suites pass in separate Bun processes: compact 37, short-list 8, started-chat-fork 10, composer-fast-toggle 9 (64 total).
  • scripts/web-lint.sh --base c5dd46c48719bb4403ec517e76b32a8c85da62ed --new-only and the exact-head prepush gate pass. Two formatter findings are unchanged on the base.
  • New picker.profile text has 21 nonempty translations. The broad localization audit is blocked by existing catalog parity debt.
  • Fresh independent Codex gpt-6-astra xhigh review: SHIP at 9ce57d085312549d6e1386c9e00c4104f7f71116; both initial review blockers repaired and re-reviewed.

Observed / Not run

Real Chromium renders and records the shipped component through its existing gallery fixture; five final variants pass with no page errors. This is browser evidence, not a native app capture. Native builds/tests were not run locally.

A combined four-file JSDOM invocation fails the Effort-slider focus assertion. Restoring the exact base QuickModelMenu reproduces that same focus failure; each of the four suites passes in its own process.

Changelog

Fixed: The model picker shows local harnesses once, distinguishes profiles from accounts, and fits its content without jumping across the composer chip.

Proof

Matched cmux-design-references/apps/claude/live/model-picker-open.png: compact model/effort rows, quiet chip and a proper Fast switch. Before uses base picker source; after uses exact head 9ce57d085312549d6e1386c9e00c4104f7f71116. Gallery states include downward Claude, ten-harness stress, combined chat, Fast on, signed out, Profile and Account submenus. The shared gallery fixture supplies deterministic route identities; pre-session production API availability remains as described above.

Media upload was attempted through `scripts/pr-media.py`; the broker accepted the plan but did not return a write receipt before the bounded wait. Exact-head screenshots and recordings are retained under `/tmp/nx-picker-evidence` for the owner to attach through the media helper.\n\n

Agent session: agent session