Build report: dashboard UI polish — plain Carbon tables, descriptive copy, tone-coded numbers, live fleet health
Brief: .superpowers/sdd/ui-polish-brief.md · Date: 2026-07-08 · Branch: master
What shipped
A. Off @carbon/ibm-products entirely (the slider-chrome fix)
Root cause confirmed: the app never imported the products-library CSS, so its
Datagrid's column-resize <input type="range"> chrome rendered as raw native
sliders in every header, and column sizing was unmanaged (the cramped
Event-ID/ULID overflow). Fix = migrate, not patch:
src/components/operator/CallsDatagrid.tsx→ plain CarbonDataTable
(SLAView's exact JSX pattern,size="sm"). Rows are clickable AND keyboard
operable (tabIndex=0+ Enter mirrors click); Time cells nowrap
(.calls-grid__nowrap), Model allowed to wrap (long ids). Keyset Load
more footer, loading skeleton / error notification / honest empty state all
preserved. Component keeps its historical name so callers/tests are stable.src/components/auditor/AccessLogTable.tsx→ plainDataTable. Actor +
Event ID mono cells are nowwhite-space: nowrap(ULID can never spill into
Action); container scrolls horizontally only when genuinely needed. Limit +
Refresh toolbar and all four states unchanged.src/views/OperatorView.tsx→ the products-librarySidePanelreplaced
with CarbonComposedModal(ModalHeader/ModalBody, passive,size="md"),
hosting the existingCallDetailPanelunchanged (trace fan-out + auditor
"View bodies" deep link intact). Modal is conditionally mounted so closing it
removes the detail from the DOM.grep -rn "ibm-products" src/→ no matches (comments included). The
dependency stays inpackage.jsonper the brief (nothing imports it, so it
no longer ships in the bundle) — removable in a later chore commit.
B. Copy sweep — no API paths/params user-visible
All 12 listed captions/subtitles rewritten descriptively (SLAView ×4,
AnalyticsView ×3, ExecutiveView ×4, OperatorView subtitle). PredictView and
ReportView audited — no leaks existed there. Enforced by tests: each of the six
views (Executive, SLA, Analytics, Operator, Predict, Report) now has a
"renders no API paths or query params in user-facing copy" test asserting the
rendered document.body.textContent matches neither /\/api\// nor
/group_by/. Code comments and query-param identifiers keep their paths
(allowed by the brief).
C. Tone-coded numbers
src/lib/tones.ts(+tones.test.ts) — the single home for thresholds:errorRateTone(0..1): <5% good · 5–20% warning · ≥20% criticallatencyTone(ms): <2 s good · 2–10 s warning · ≥10 s criticalqueueTone(ms): <1 s good · 1–10 s warning · ≥10 s criticalgpuUtilTone(pct): <80 good · 80–95 warning · ≥95 criticalsrc/components/charts/ToneNumber.tsx— a span coloured via Carbon
support tokens incarbon.scss(--cds-support-success,
--cds-support-warning-textfallback--cds-support-warning,
--cds-support-error), so g10/g90 themes both track. Colour is the
SECONDARY carrier — the figure text stays primary (StatTile's a11y rule).- Applied to: Overview error-rate tile (untoned at 0 calls — 0/0 is not a
measurement), SLA fleet p95/p99 tile (toned by p95), SLA error-rate +
GPU-utilization tiles, SLA per-engine table (p50/p95/p99/max → latencyTone,
avg queue → queueTone), Analytics rollup error-rate cells. Predict's
active-warnings tile already carried the exact rule (0 → good, ≥1 → warning,
any critical severity → critical) — verified, unchanged. - Deliberately NOT toned: cache-hit rate (low isn't a fault), token counts,
and every loading/unavailable/'—' cell (a tone asserts a real measurement).
D. Fleet health: stale P3 placeholder → live GPU strip
OperatorView now renders a compact live strip from client.getGPUNow() (60 s
refetch, retry: false): per GPU gpuN · util X% · mem U/T GB · temp C°C,
util tone-coded via gpuUtilTone. Honest states: empty list → "No GPU sample
in the last 2 min" (dead exporter ≠ error), query error → "GPU telemetry
unavailable", skeleton while pending — never a frozen number.
Tests
353 passed / 0 failed across 42 files (npx vitest run). Behavioral
assertions preserved and extended: row click + Enter-key open the detail
modal, keyset load-more/end-of-results, limit change refetch, all
loading/error/empty states, nowrap mono classes, tone assertions on tiles and
cells (including boundary 5% → warning), the three fleet-strip states, and the
six per-view no-API-copy tests.
Gates
npx tsc --noEmit— cleannpx vitest run— 353/353 greennpm run build— succeeds (pre-existing chunk-size warning only)grep -rn "ibm-products" src/— empty- Repo-wide
/api/·group_bygrep — hits only in code comments and API-client
param identifiers (permitted); rendered copy enforced by tests
Judgment calls
- Kept
@carbon/ibm-productsin package.json — brief says dropping it
fromsrc/(and therefore the bundle) is enough; flagged as removable. - Comment wording — two file-header comments explaining the migration
history referred to the old library by name; reworded ("products-library")
so the strictgrep -rn "ibm-products" src/gate is literally empty while
the why-history survives. - Model column wraps, Time doesn't — per brief; long model ids would
otherwise force the whole table wide. - Error-rate tiles untoned at 0 calls — 0/0 isn't a measurement; tone
only asserts on real figures (same contract as the '—' cells). - ComposedModal is passive and conditionally mounted — the detail is
read-only (no footer actions) and unmounting on close removes stale detail
DOM instead of hiding it.