Skip to content

feat(ui): D.7 migrate SessionMusicianPanel + MixDoctorPanel - #79

Merged
slittycode merged 3 commits into
mainfrom
claude/ui-restyle-pr11-session-mix-doctor
May 19, 2026
Merged

feat(ui): D.7 migrate SessionMusicianPanel + MixDoctorPanel#79
slittycode merged 3 commits into
mainfrom
claude/ui-restyle-pr11-session-mix-doctor

Conversation

@slittycode

Copy link
Copy Markdown
Owner

Summary

PR 11 of 16 in the UI consistency overhaul / Live 12 restyle stack.

SessionMusicianPanel

  • Outer <section> + custom header → <DeviceRack name="Session Musician" subtitle="· Pitch & Melody"> with the collapse chevron in the title-strip action slot (<Button variant="ghost" iconOnly>).
  • Off-banner div → <EmptyState tone="warning">. Preserved data-testid="session-musician-off-banner".
  • No-data div → <EmptyState tone="neutral">. Preserved data-testid="session-musician-no-data" and the title text the analysisResultsUi.test.ts:1344 assertion locks ("PITCH &amp; MELODY UNAVAILABLE").

MixDoctorPanel

  • 3-card top row (Target Genre / Health Score / Loudness Offset) → 3 × <MetricTile size="md" accent="accent">.
  • Advisory summary rows → <Panel variant="surface" padding="md">.
  • StyledDataTableDataTable (API parity drop-in).

Bundled fix — MetricTile accent stripe class string

Changed border-l-2 border-l-{tone}border-l-2 border-{tone}. Visually identical (only the left border has thickness; tone applies to all borders but only the left is visible). Matches the literal class the analysisResultsUi.test.ts:533 regex asserts against the OLD AccentMetricCard's class string. The L-suffixed form was a hidden regression introduced when D.5a / D.6a migrated AccentMetricCards to MetricTile — the test happened to still pass when SOME AccentMetricCards remained (their border-l-2 border-accent string carried the ≥4 count), but with D.6a completing the migration the test would fail. Fixing here unblocks the dashboard PRs.

Preserved verbatim

  • All data-testid hooks.
  • All ARIA labels on the collapse toggle.
  • Off-banner / no-data copy strings.
  • The data-text-role attributes inside StatusBadge / DeltaBadge (unchanged primitives).
  • MixDoctor advisory tone vocabulary.

Test plan

  • npm run lint — clean
  • npm run test:unit — 628/628 passing
  • npm run build — clean

Up next

  • D.8 — Smaller components (IdleValuePropPanel, WaveformPlayer, SpectrogramViewer, StickyNav, DiagnosticLog, Phase2ConsistencyReport, StemListeningNotesPanel, structure/harmony lane components, etc.).
  • D.9 — DenseDawConcept + RetroVisualizer.
  • D.10 — Cleanup (delete MeasurementPrimitives.tsx + Tooltip.tsx + unused .ableton-* aliases).

https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe


Generated by Claude Code

slittycode pushed a commit that referenced this pull request May 18, 2026
analysisResultsUi.test.ts:533 asserts ≥4 occurrences of the literal
class string `border-l-2 border-accent` in the rendered HTML. That
string was what AccentMetricCard emitted before the D.5a / D.6a
MetricTile migration; my MetricTile primitive used the directional
`border-l-{tone}` form (visually identical but a different literal),
so the test broke once D.6a removed the last AccentMetricCard.

Switch to `border-l-2 border-{tone}` — `border-l-2` carries the 2px
left thickness; the tone applies to all borders but only the left is
visible. Matches AccentMetricCard's class exactly and restores the
brittle assertion.

Same fix as the bundled patch in PR #79; cherry-pick to this branch
so #78 can complete its own CI gate independently.

https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe
slittycode added a commit that referenced this pull request May 18, 2026
* feat(ui): D.6c rename local SectionHeader to NumberedSectionToggle

PR 10 (sub-step c) of 16. Last of three small PRs against
MeasurementDashboard.tsx — closes out the dashboard migration.

The local SectionHeader at :293 is structurally a collapsible toggle
button (the whole row IS the click target for open/close), not a
static h2 like the ui/SectionHeader primitive. Substituting the
primitive would either nest interactive elements or swallow the
collapsibility, so the local component stays — but it gets renamed
to NumberedSectionToggle so the distinction is obvious and the name
no longer shadows the primitive.

Also tightens the a11y of the toggle: adds aria-expanded={isOpen} on
the button and aria-hidden on the +/− glyph (purely decorative once
aria-expanded carries the state).

Preserved verbatim:
- data-text-role="meta" + data-text-role="section-title" attributes
  (analysisResultsUi.test.ts spec-level vocabulary).
- All call sites — only the local component name changes; the props
  and behavior are unchanged.
- All Section IDs / data-testid hooks (rhythm-grid-*, spectral-*).

Verified: lint clean, 628/628 unit tests passing.

D.6 (MeasurementDashboard) is now fully migrated across 10a/b/c.

https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe

* fix(ui): MetricTile accent stripe uses border-{tone} not border-l-{tone}

analysisResultsUi.test.ts:533 asserts ≥4 occurrences of the literal
class string `border-l-2 border-accent` in the rendered HTML. That
string was what AccentMetricCard emitted before the D.5a / D.6a
MetricTile migration; my MetricTile primitive used the directional
`border-l-{tone}` form (visually identical but a different literal),
so the test broke once D.6a removed the last AccentMetricCard.

Switch to `border-l-2 border-{tone}` — `border-l-2` carries the 2px
left thickness; the tone applies to all borders but only the left is
visible. Matches AccentMetricCard's class exactly and restores the
brittle assertion.

Same fix as the bundled patch in PR #79; cherry-pick to this branch
so #78 can complete its own CI gate independently.

https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe

---------

Co-authored-by: Claude <noreply@anthropic.com>
slittycode pushed a commit that referenced this pull request May 18, 2026
PR #79 Frontend CI failed on tests/smoke/upload-phase1-midi.spec.ts:631
which uses `page.locator('section').filter({ hasText: /SESSION
MUSICIAN/i })` to find the panel. My D.7 migration replaced the
outer `<section>` with `<DeviceRack>` (a div), so the locator
returned 0 elements.

Wrap the DeviceRack in a `<section data-testid=
"session-musician-panel" aria-label="Session Musician">`. The
section now owns the semantic element + the data-testid; the
DeviceRack provides chrome inside it. The DOM contains "Session
Musician" (case-insensitive match for /SESSION MUSICIAN/i) so the
smoke locator resolves correctly.

Verified: lint clean, 628/628 unit tests passing.

https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe
slittycode added a commit that referenced this pull request May 18, 2026
tests/smoke/responsive-layout.spec.ts:192 fails at the 375px mobile
viewport with `expect(getByText('Analysis Results')).toBeVisible()`
resolving to a hidden h2. Root cause: my D.5a migration replaced the
original `flex flex-col md:flex-row` layout for the Analysis Results
page header with the SectionHeader primitive which used
`flex items-center justify-between` unconditionally. At 375px the
two Download buttons (~280px combined) squeeze the title to zero
width and the parent `.ableton-shell overflow-hidden` clips the
title off-screen, so Playwright sees it as hidden.

Restore the responsive collapse: mobile-first
`flex flex-col items-start gap-2`, then `md:flex-row md:items-center
md:justify-between md:gap-3` at the 768px+ breakpoint. Matches the
pre-D.5a Analysis Results header behavior. Other consumers of
SectionHeader (the many ResultsSectionHeader call sites) have small
rightSlot content (badges, single pills, icons) — stacking those
below the title on mobile is a tiny visual improvement, not a
regression.

This is the failure that's been blocking #79, #80, #81, #82 — none
of those PRs introduced the bug; they all inherit it from main
because D.5a (#71) landed this regression. The fact that #71 itself
merged green is either CI luck (the test passed on its first run)
or the test was added later and not re-checked.

Landing this hotfix lets the four open PRs rebase and pick up the
fix to clear their CI.

Verified: lint clean, 628/628 unit tests passing, build clean.

https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe

Co-authored-by: Claude <noreply@anthropic.com>
claude added 3 commits May 18, 2026 23:58
PR 11 of 16 in the UI consistency overhaul.

SessionMusicianPanel:
- Outer <section> + custom header div → <DeviceRack name="Session
  Musician" subtitle="· Pitch & Melody"> with the collapse chevron
  in the title-strip action slot (<Button variant="ghost" iconOnly>).
- Off-banner div → <EmptyState tone="warning" title="Pitch/note
  translation is off" description={offBannerCopy}>. Preserved
  data-testid="session-musician-off-banner".
- No-data div → <EmptyState tone="neutral" title="PITCH & MELODY
  UNAVAILABLE" description=...>. Preserved
  data-testid="session-musician-no-data" and the title text the
  analysisResultsUi.test.ts:1344 assertion locks
  ("PITCH &amp; MELODY UNAVAILABLE").
- Drop the unused formatDisplayText import (its only consumer — the
  h2 title — was replaced by the DeviceRack name prop).

MixDoctorPanel:
- 3-card top row (Target Genre / Health Score / Loudness Offset) →
  3 × <MetricTile size="md" accent="accent">. Each card's eyebrow +
  primary value + footer/footer-badge map directly to MetricTile's
  label / value / footer props.
- Advisory summary rows (Dynamics / Loudness / Stereo) → <Panel
  variant="surface" padding="md">. The hand-rolled bg-bg-card/35
  inset-shadow div disappears in favor of the canonical primitive.
- StyledDataTable → DataTable (API parity drop-in; same columns,
  same row data).
- Drop StyledDataTable + formatDisplayText imports.

Bundled fix — MetricTile accent stripe class string:
- Changed `border-l-2 border-l-{tone}` → `border-l-2 border-{tone}`.
  Visually identical (only the left border has thickness; the tone
  applies to all borders but only the left is visible). Matches the
  literal class the analysisResultsUi.test.ts:533 regex was
  asserting against the OLD AccentMetricCard's class string. The
  L-suffixed form was a hidden regression introduced when D.5a /
  D.6a migrated AccentMetricCards to MetricTile — the test happened
  to still pass when SOME AccentMetricCards remained (their
  border-l-2 border-accent string carried the ≥4 count), but with
  D.6a completing the migration the test would fail. Fixing here
  unblocks the dashboard PRs.

Preserved verbatim:
- All data-testid hooks (session-musician-panel, session-musician-
  off-banner, session-musician-no-data on the SM side; mix-doctor
  surfaces have no data-testids to begin with).
- All ARIA labels on the collapse toggle.
- Off-banner copy strings, no-data copy strings.
- The data-text-role attributes inside StatusBadge / DeltaBadge
  (those come from the unchanged primitives).
- MixDoctor advisory tone vocabulary (success/warning/error mapping
  by toneForScore/toneForMixIssue/toneForDynamicsIssue/
  toneForStereoAdvice).

Verified: lint clean, 628/628 unit tests passing, build clean.

https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe
PR #79 Frontend CI failed on tests/smoke/upload-phase1-midi.spec.ts:631
which uses `page.locator('section').filter({ hasText: /SESSION
MUSICIAN/i })` to find the panel. My D.7 migration replaced the
outer `<section>` with `<DeviceRack>` (a div), so the locator
returned 0 elements.

Wrap the DeviceRack in a `<section data-testid=
"session-musician-panel" aria-label="Session Musician">`. The
section now owns the semantic element + the data-testid; the
DeviceRack provides chrome inside it. The DOM contains "Session
Musician" (case-insensitive match for /SESSION MUSICIAN/i) so the
smoke locator resolves correctly.

Verified: lint clean, 628/628 unit tests passing.

https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe
tests/smoke/upload-phase1-midi.spec.ts:360 asserts
`panel.getByRole('heading', { name: /SESSION MUSICIAN/i })` — the
panel must contain at least one heading element with that name.
My D.7 migration replaced the original <h2>Session Musician</h2>
with a DeviceRack title strip whose name renders as a styled
<span>, removing the heading role.

Add `<h2 className="sr-only">Session Musician</h2>` inside the
section wrapper — visually hidden but accessible to screen readers
and Playwright getByRole. DeviceRack title strip continues to
carry the visible label.

https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe
@slittycode
slittycode force-pushed the claude/ui-restyle-pr11-session-mix-doctor branch from 7973851 to 4a9c950 Compare May 18, 2026 23:58
slittycode pushed a commit that referenced this pull request May 18, 2026
PR 14 of 16 in the UI consistency overhaul. Final cleanup pass.

Removes three CSS utility classes from index.css:
- .ableton-panel
- .ableton-device
- .ableton-header

All three were retired by D.* migrations — every former consumer now
uses the canonical primitives from components/ui/ (Panel, DeviceRack,
SectionHeader). `grep -rn` against apps/ui/src/ confirms zero
remaining usages.

.ableton-shell and .ableton-toolbar STAY because App.tsx:952,956 still
consumes them for the outer app chrome (the load-bearing
section-grid shell). A focused follow-up could migrate those two to
DeviceRack / a future AppShell primitive; out of scope here.

Deferred (preserved as-is):
- components/MeasurementPrimitives.tsx cannot be fully deleted yet —
  5 consumers still depend on timeline/lane primitives (LaneContainer,
  LaneRow, StatsBar, TimeRuler) that the plan explicitly preserved.
  The shipped primitives (StatusBadge, DeltaBadge, MetricBar,
  MetricBarRow, OutlinePillButton, TokenBadgeList, StyledDataTable,
  AccentMetricCard) also still have consumers in MeasurementDashboard
  and AnalysisResults sections that weren't migrated (StructureLanes,
  HarmonyLanes, AnalysisResults remaining sections). Keep the file
  intact.
- components/Tooltip.tsx stays as a re-export shim; the file isn't
  causing any drift and external imports may still target it.

Verified: lint clean, 628/628 unit tests passing, build clean.

D.* migrations summary (all merged or open at time of this PR):
- D.0 Foundation (#64) ✓
- D.1 Primitives complete (#65) ✓
- D.2 SamplePlayback (#66) ✓
- D.3 SignalChain marquee (#67) ✓
- D.4 FileUpload + Input Source (#69) ✓
- D.5a Results header + metric strip (#71) ✓
- D.5b Mix Chain (#73) ✓
- D.5c Patches (#74) ✓
- D.5d Section headers (#75) ✓
- D.6a Dashboard structure (#76) ✓
- D.6b Dashboard sections (#77) ✓
- D.6c Dashboard headers (#78) ✓
- D.7 SessionMusicianPanel + MixDoctorPanel (#79) — open
- D.8 Signal Monitor + SpectrogramViewer drift (#80) — open
- D.9 DenseDawConcept drift (#81) — open
- D.10 Cleanup (this PR) ✓

https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe
@slittycode
slittycode merged commit d0166f7 into main May 19, 2026
3 checks passed
@slittycode
slittycode deleted the claude/ui-restyle-pr11-session-mix-doctor branch May 19, 2026 00:09
slittycode added a commit that referenced this pull request May 19, 2026
…82)

PR 14 of 16 in the UI consistency overhaul. Final cleanup pass.

Removes three CSS utility classes from index.css:
- .ableton-panel
- .ableton-device
- .ableton-header

All three were retired by D.* migrations — every former consumer now
uses the canonical primitives from components/ui/ (Panel, DeviceRack,
SectionHeader). `grep -rn` against apps/ui/src/ confirms zero
remaining usages.

.ableton-shell and .ableton-toolbar STAY because App.tsx:952,956 still
consumes them for the outer app chrome (the load-bearing
section-grid shell). A focused follow-up could migrate those two to
DeviceRack / a future AppShell primitive; out of scope here.

Deferred (preserved as-is):
- components/MeasurementPrimitives.tsx cannot be fully deleted yet —
  5 consumers still depend on timeline/lane primitives (LaneContainer,
  LaneRow, StatsBar, TimeRuler) that the plan explicitly preserved.
  The shipped primitives (StatusBadge, DeltaBadge, MetricBar,
  MetricBarRow, OutlinePillButton, TokenBadgeList, StyledDataTable,
  AccentMetricCard) also still have consumers in MeasurementDashboard
  and AnalysisResults sections that weren't migrated (StructureLanes,
  HarmonyLanes, AnalysisResults remaining sections). Keep the file
  intact.
- components/Tooltip.tsx stays as a re-export shim; the file isn't
  causing any drift and external imports may still target it.

Verified: lint clean, 628/628 unit tests passing, build clean.

D.* migrations summary (all merged or open at time of this PR):
- D.0 Foundation (#64) ✓
- D.1 Primitives complete (#65) ✓
- D.2 SamplePlayback (#66) ✓
- D.3 SignalChain marquee (#67) ✓
- D.4 FileUpload + Input Source (#69) ✓
- D.5a Results header + metric strip (#71) ✓
- D.5b Mix Chain (#73) ✓
- D.5c Patches (#74) ✓
- D.5d Section headers (#75) ✓
- D.6a Dashboard structure (#76) ✓
- D.6b Dashboard sections (#77) ✓
- D.6c Dashboard headers (#78) ✓
- D.7 SessionMusicianPanel + MixDoctorPanel (#79) — open
- D.8 Signal Monitor + SpectrogramViewer drift (#80) — open
- D.9 DenseDawConcept drift (#81) — open
- D.10 Cleanup (this PR) ✓

https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants