Status: planned 2026-05-24 (epic cppmega-mlx-v9 — to be created)
Driver: post-V8 operator-feedback cycle. V8 closed the gallery→train round trip (R01-R12). V9 closes the visual surface the operator interacts with every minute: canvas chrome, sidebar ergonomics, theme consistency, and discoverability.
"Цвета, фонты, ux — куча компонентов и непонятно зачем. mtp это не компонент? зачем оно тут банером? memory bar длиннюща, как ты это покажешь на h100:8? ckpt path виден когда idle. parallel/insert/ transplant — ugly full-width strips. draft 1 + new draft — для чего? TopBar 18 элементов, цвета непоследовательны."
| U# | scope | priority | depends on |
|---|---|---|---|
| U01 | Draft tabs strip (browser-tab style) in TopBar left group | P2 | - |
| U02 | Floating canvas toolbar (vertical 32px icon-strip) | P2 | - |
| U03 | Mass hex-literal migration — 592 → ≤ 150 across vbgui/src/components |
P3 | UX#8 ratchet |
| U04 | Theme tokens v2 — layered surfaces + elevation scale | P3 | U03 |
| U05 | Sidebar tab strip — collapse 10 tabs into grouped accordion | P2 | - |
| U06 | Empty-state contracts for Loss/Optim/Memory/Gotchas tabs | P3 | - |
| U07 | BrickNode unified styling — Palette item == canvas chip | P3 | U04 |
| U08 | TopBar responsive collapse — groups stack < 1024px | P3 | UX#7 |
| U09 | Help icon catalogue audit — every topic has content or 404 | P2 | - |
| U10 | Keyboard shortcuts overlay (? key) | P3 | - |
The operator-feedback redesign sprint closed these between
2026-05-23 and 2026-05-24 (commits 23bb694, 7908932, 6fe5518,
7bc0b43, 5a4e314, 7e1a031):
| # | Title | Commit |
|---|---|---|
| #0 | HelpModal Portal — escape transformed ancestor (position:fixed containing-block trap) |
S3615 |
| #1 | FeatureInjectionBar dedupe → chip with ×N count + per-chip remove |
6fe5518 |
| #2 | DimEnvEditor relocated to right Sidebar Dimensions tab |
7bc0b43 |
| #3 | TrainOptionsPanel + RunHistoryPicker → new TrainOps Sidebar tab |
7bc0b43 |
| #4 | TrainLiveControls conditional {trainInFlight && ...} |
7bc0b43 |
| #5 (interim) | Parallel / Insert / Transplant bars removed from canvas, hosted in TrainOps tab | 7bc0b43 |
| #6 | MemoryBar compact (100×18 pill) + topology-aware N-rank mini-bars | 23bb694 |
| #7 | TopBar 3 flex groups (left/center/right) + single Precision dropdown | 5a4e314 |
| #8 (ratchet) | HexColorRatchet.test.ts + per-file baseline + DimensionsTab migration |
7e1a031 |
V8 delivered the journey. V9 delivers the finish:
- discoverability (Draft tabs, keyboard shortcuts, help catalogue)
- visual consistency (theme tokens, BrickNode unity, mass hex migration ratcheted down from 592 to ≤ 150)
- canvas chrome (floating toolbar instead of buried sidebar splicing section; responsive TopBar)
- empty-state polish (so first-time operators see prompts instead of white space)
Operator opens the GUI cold. Without reading docs they can:
- Recognise every clickable region from visual weight alone.
- Find every action through ≤ 2 clicks (TopBar + Sidebar grouped).
- Use
?overlay to discover all keyboard shortcuts. - Switch between concurrent specs via Draft tabs.
- Splice graphs (parallel/insert/transplant) from a fixed-position floating toolbar instead of scrolling a tab.
Why: operator currently sees [Draft 1] [+ New Draft] with no
visual taxonomy. Should be browser-tab-style strip wedged into
TopBar left group, right of project-name.
Subs:
- U01.1
vbgui/src/components/DraftTabsStrip.tsx: render N tabs[Untitled] [Draft 1] [Draft 2 ×] [+]. Active tab highlighted. Close button (×) only on inactive tabs. - U01.2
vbgui/src/state/drafts.ts:useDrafts()hook persists drafts tolocalStorageundervbgui_drafts_v1(array of full spec snapshots + name + timestamp). - U01.3 Vitest: switching draft swaps
nodes+edges+specon canvas; closing draft does NOT lose data of OTHER drafts.
Why: Parallel / Insert / Transplant currently live in
TrainOpsTab (a hidden tab). They should be a fixed-position
vertical strip 32px wide, left edge of canvas, between Palette
and FlowCanvas.
Subs:
- U02.1
vbgui/src/components/CanvasToolbar.tsx: vertical icon strip with three icons. Each icon opens a popover (positioned to the right of the icon) that contains the existingParallelComposeBar/InsertIntoEdgeBar/TransplantBar. - U02.2 Remove the splicing section from
TrainOpsTab(revert linter's interim placement). Update testtests/TrainOpsTab.test.tsxto drop the splicing assertions. - U02.3 Popovers close on click-outside and on Esc; icons show active-state ring while popover is open.
- U02.4 Vitest: 3 icons render; opening one closes any other
already-open popover; ParallelComposeBar still fires
onCompose.
Why: tests/HexColorRatchet.test.ts locks in baseline 592. The
target is ≤ 150 by end of V9 (75% reduction). High-frequency
literals: #6b7280 (55), #374151 (36), #94a3b8 (30),
#e5e7eb (29).
Subs:
- U03.1 Map every hex literal to the closest semantic token in
src/theme.ts— producevbgui/MIGRATION_TABLE.mdwith rowshex → T.token category notes. - U03.2 Migrate
Sidebar.tsx+ every file undersrc/components/sidebar/(target: sidebar drops to ≤ 10 hex total). - U03.3 Migrate
BrickContextPanel.tsx(currently 32 hex — highest single offender after TrainLiveControls). - U03.4 Migrate
TrainLiveControls.tsx(46 hex — relocate its ad-hoc colour table intoT.live*extension if any unique values remain after migration).
Why: existing tokens (T.surface, T.surface2, T.surface3)
are flat — there's no notion of "card on card" or "modal vs
popover" depth. Adding T.surfaceLayered{1,2,3} and T.elevation*
gives the migration target enough semantic vocabulary.
Subs:
- U04.1 Extend
vbgui/src/theme.css+theme.tswith:surfaceLayered1/2/3(each a darker variant ofsurfacewith a hairline border);elevationLow/Mid/High(box-shadow tokens);liveAccent,liveAccentSoft(semantic for live-train UI). - U04.2 Pin the additions in
vbgui/STYLE.md(see Spec §2).
Why: Sidebar now has 10 tabs (Loss, Optim, Rewriters, Side
Ch., Sharding, Gotchas, Dimensions, Train Ops, Ablations, Memory).
At width 320px with flex: 1 0 33% they wrap to 4 rows of 3 — eats
sidebar headroom.
Subs:
- U05.1 Group tabs into 3 sections (Spec / Diagnostics / Train) — visible header per section, tabs underneath as smaller chips.
- U05.2 OR: dropdown picker for less-used tabs (Ablations, Memory). A/B both, pick one with screenshots.
- U05.3 Vitest: every existing
sidebar-tab-{name}testid still resolves (back-compat).
Why: opening LossTab / MemoryMatrixTab / GotchasTab cold gives blank panels. Operator can't tell whether the tab is broken or empty.
Subs:
- U06.1 Each of {LossTab, MemoryMatrixTab, GotchasTab,
AblationsTab} renders an empty-state block when its data array
is
[]. Block = icon + headline + 1-sentence prompt + CTA. Example for GotchasTab: "✓ No issues yet — run Smoke to populate". - U06.2 Vitest: each tab in empty state has
data-testid="<tab>-empty-state"and renders the CTA text.
Why: Palette items (left dock) and canvas nodes use different chrome — Palette is white-bg + grey border, canvas is dark + accent glow. Single brick should look the same in both places (different backgrounds, identical typography + accent treatment).
Subs:
- U07.1 Extract shared
BrickChipprimitive used by bothPaletteitems andBrickNodecanvas nodes. - U07.2 Vitest: Palette item and BrickNode for the same kind have
same
data-brick-kind+ same--vb-node-accentCSS variable.
Why: UX#7 split into 3 flex groups. Below 1024px width they overflow horizontally — need to stack groups onto 2 rows when viewport is narrow.
Subs:
- U08.1
@containerormin-widthmedia query — when< 1024pxstack the center group below left+right. - U08.2 Vitest with jsdom-resize: at 800px width
top-bar-group-center.style.flexDirection === "column"OR a wrap container.
Why: HelpIcon topic="..." references ~80 topics. Many may
have drifted (renames, broken slugs) — operator clicks ? and
sees "missing" modal. Need a programmatic audit + autofix path.
Subs:
- U09.1 vitest scans every
<HelpIcon topic="X">use, everyTooltip name="X">, and everyExplainModal name="X">invbgui/src/components/**/*.tsx. For each, asserts the topic exists inHELP_TOPICSmap OR acatalog.explainRPC response. Failing topics listed. - U09.2 Add missing topics to
HelpIcon.tsxHELP_TOPICS map (one paragraph each) OR remove the reference if the surface is dead. - U09.3 Add
topicautocomplete TS type so future references type-check.
Why: power users want ? to bring up a list of all shortcuts.
Currently only Cmd/Ctrl+Z (undo) + Shift+Cmd/Ctrl+Z (redo) are
hinted in button titles.
Subs:
- U10.1
vbgui/src/components/KeyboardShortcutsOverlay.tsx: modal triggered by?(and dismissed by?or Esc) listing every registered shortcut grouped by section (Canvas / Sidebar / Train / Help). - U10.2
vbgui/src/state/shortcuts.ts: central registry — every bound shortcut registers{key, label, section, handler}so the overlay is generated, not hand-edited. - U10.3 Vitest: pressing
?opens overlay; overlay lists ≥ 1 shortcut per section.
- Read
VisualBuilderSpec-v9.mdfor the relevant U-section. - Create files per spec, with the listed data-testids.
- Write vitest tests first (TDD); they should fail.
- Wire the component; tests pass.
- Run full
npx vitest runfromvbgui/to confirm zero regression. - Commit with
UX-U0#: <title>message; close the bd ticket. - Push to main.
- 10 U-epics → 26 sub-tickets created in bd as
cppmega-mlx-v9/U01..U10(one parent + 10 child epics). - Each sub-ticket has acceptance criteria copied from §4.
- New vitest count: ≥ 25 (across all U-stages).
HexColorRatchet.test.tsbaseline drops from 592 to ≤ 150 by end of U03 (≥ 75% reduction).
- True theming (user-switchable light/dark/contrast).
- Drag-to-reorder canvas nodes (current ELK auto-align only).
- Multi-user collaboration (CRDT spec sync).
- Mobile/tablet viewports (focused on ≥ 1024px desktop).
- Internationalisation (English-only UI text).
V9 is done when:
- All 10 U-epics closed in bd (sub-tickets either closed or deferred to V10 with explicit reason).
npx vitest runfromvbgui/: 0 failures (counting only V9-relevant test files; pre-existing HelpModal/Palette/Backward failures are tracked separately).HexColorRatchetbaseline ≤ 150.VisualBuilderPlan-v9.md+VisualBuilderSpec-v9.md+vbgui/STYLE.mdshipped onmain.- A 5-min screen-recording captures Draft tabs + Canvas toolbar +
empty states +
?overlay (UAT footage).