Skip to content

fix(ui-core): a long description clamps, and the rest of the quality pass is measured - #773

Merged
YaelAnaya merged 2 commits into
mainfrom
refactor/quality-pass-part-2
Aug 24, 2026
Merged

fix(ui-core): a long description clamps, and the rest of the quality pass is measured#773
YaelAnaya merged 2 commits into
mainfrom
refactor/quality-pass-part-2

Conversation

@YaelAnaya

Copy link
Copy Markdown
Collaborator

The rest of the cross-product quality pass, measured. Thirteen batches were
audited; one produced a defect worth fixing, two produced findings that turned out
not to be defects at all, and the remainder were already sound.

Stacked on #772 and should merge after it.

The defect

A project's description is free text in a narrow column, and nothing clamped it. A
long one wrapped a word-fragment per line and took the row to roughly five hundred
pixels, so one project pushed every other one off the screen. At a narrow width it
reads worse than that: the table scrolls sideways there, so the column is out of
view and what remains is a tall empty row with nothing in it to explain itself.

It now clamps to two lines with the full value on the element's title, and the
project's own page still carries the whole of it. A description is a label, and a
label may truncate where its value is available elsewhere; the name beside it is
deliberately not clamped, because the name is what the row is for.

It was found by pointing the responsive sweep at a project named and described at
116 characters instead of at the fixtures that happened to exist - which is the
point of a content-stress pass, and the reason the first sweep missed it.

Two findings that were not defects

Both are recorded because the wrong conclusion was the tempting one.

The dialog does not swallow the press after it closes. Phase 6 fixed exactly
that defect in the menu and named Dialog as the likely next instance, since it
animates out through the same mechanism. Measured on /styleguide, it reopens
five times out of five. The menu's trigger toggles, so one pointer-down was read
as both an open and an outside-dismiss; a dialog trigger only opens, so there is
nothing to cancel. Nova's dialog animation is therefore unchanged, per the rule
that an unreproduced defect is not a defect.

A failed read is not stuck on "Loading". A probe that forced a 500 and looked
after a second found a loading state and nothing else, which reads like a screen
that never recovers. It is the retry: TanStack Query attempts three times, and at
three seconds the screen shows the message, the code and a "Try again". The probe
was too impatient, and reporting it would have been a defect that does not exist.

What was audited and found sound

Every number below is from a run, and each check prints what it inspected so that
a zero cannot be a broken probe reporting nothing.

Accessibility. 132 visible controls and 11 form fields across nine routes: all
have an accessible name or a label. One <h1> per route, main and nav
landmarks on every one.

Keyboard. Tab reaches the rail and the page's own controls in order; Enter
opens a project and moves between sections; a batch menu opens from the keyboard,
ArrowDown lands on a menuitem, and Escape returns focus to the trigger it came
from. Schema offers 25 distinct stops with no repeat, so nothing traps.

Scroll ownership. No route runs an inner scroller against a scrolling document.

Text scaling. At 200% no route scrolls sideways.

Dialogs at small viewports. At 320x600 the dialog fits horizontally, does not
widen the page, and its close control stays on screen.

Focus. A focused control paints a ring - read off the computed style, since
Tailwind renders ring-3 as a box-shadow and a class assertion would prove
nothing.

Theme and colour. No raw palette utility and no raw white/black in product
class strings. The one hit is bg-black/10 on the dialog overlay, which DESIGN.md
specifies. The design-token gate independently bans arbitrary colour values.

Motion. The product declares one animation of its own, a loading skeleton's
pulse. prefers-reduced-motion collapses every animation and transition in the
base layer, so no component opts in and none can forget to.

Rhythm. Six product screens share one page padding.

What is deferred, and why

A visual-regression baseline is not introduced here. The value of screenshots
is in catching what assertions cannot see, and the cost is a suite that fails on
an anti-aliasing change. This product's surfaces carry live thumbnails, relative
timestamps ("4m ago") and generated ids, so a useful baseline needs stabilised
fixtures first. Adding fragile snapshots now would spend the team's trust on
noise. The recommendation is a small set - the shell, one data screen, one
form-heavy screen, one floating surface - built on frozen fixtures, as its own
piece of work rather than as a footnote to this one.

Hostile content beyond a long name and description. A long class name, a long
model reference and a large annotation count are each worth the same treatment;
the schema write path refuses the shape this pass used to seed them, so they want
a fixture rather than an API call.

Test plan

Every command ran inside Docker/Linux; no repository validation ran natively on
the host. The probes ran against a real stack, with the worktree served by its own
vite inside the compose network and /api proxied at the running service.

install (pnpm install --frozen-lockfile)  PASS
build (pnpm -r build)                     PASS
@visionset/ui-core lint (incl. typecheck) PASS
@visionset/ui-core test                   PASS
@visionset/app build                      PASS
@visionset/app lint                       PASS
@visionset/annotator test                 PASS
pnpm test:scripts                         PASS
pnpm version:check                        PASS

full browser suite                        261 passed

The project created to stress the layout was deleted afterwards; the workspace is
back to the single project it held. Its DELETE asking for confirm=true first
is the domain behaving correctly, not a failure.

Scope

Shared primitive changes:  None
Routes changed:            No
Product IA changed:        No
Backend / wire / domain:   No

… its row

The description column is narrow and its content is free text, so a long one
wrapped a word-fragment per line and took the row to roughly five hundred pixels
- one project pushing every other one off the screen. At a narrow width it reads
worse than it sounds: the table scrolls sideways there, so the column is out of
view and what is left is a tall empty row with nothing in it to explain itself.

Two lines and an ellipsis, with the full text on the element's `title` and the
project's own page carrying it in full. A description is a label here, and a label
may truncate where its value is available elsewhere; the name beside it is not
clamped, because that one is what the row is for.

Found by pointing the responsive sweep at a project named and described at 116
characters rather than at the fixtures that happened to exist.
Base automatically changed from refactor/cross-product-quality-pass to main August 24, 2026 21:42
@YaelAnaya
YaelAnaya merged commit c84e1d8 into main Aug 24, 2026
15 checks passed
@YaelAnaya
YaelAnaya deleted the refactor/quality-pass-part-2 branch August 24, 2026 21:49
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.

1 participant