Two real findings from adversarial review of the previous commit (the v4
UI port's route change), both fixed:
- app/tests-layout/*.spec.js (20 files, 133 tests): every one of these
navigated to /funpack/ and asserted on composer-specific DOM
(.cx-workspace*, window.FunPack) that no longer exists there now that
the ported v4 frontend is served at that URL instead. Left as-is they
would silently time out on every run. Each file now carries an explicit
test.skip(true, "...") with a comment explaining why and pointing at
the plan's pixel-exactness step, which is what will eventually rewrite
these against the new DOM -- declared and tracked, not quietly broken.
- core/tests/test_registry.py's fixture-based tests never exercised the
new category field through the real announcement_of()/scan() path --
only test_schema.py's direct validate() calls did, which bypass
registry.py's FIELDS name-mapping entirely. A typo there (e.g.
"Category" instead of "CATEGORY") would have passed every existing
test. The "good module" fixture gained CATEGORY = "guidance" and
test_the_good_module_loads now asserts on it, closing the gap.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* Generate was washed out on light and the fade downwards was why. Light's
accent carries WHITE text, which caps how bright the fill can go before
the label starts disappearing into it -- so the button sits AT the accent
now and DARKENS under the pointer, where white only reads better. Dark's
accent carries near-black text and has no such ceiling, so it does the
opposite: rest at the accent, lighter on hover. Measured in both, at rest
and hovered: no gradient stop under 4:1.
* A section label sat directly on the dividing line above it -- the
collapsible's body had no top padding of its own, so "APPEARANCE" read as
belonging to the divider rather than to the card under it.
* A checkbox in this app is a switch with a sentence under it, not a tick in
a list. At 4px of padding the label and its hint sat hard against the top
and bottom of their card, and a hint wrapping to two lines had nowhere to
wrap into.
* Row content is weighted to the left now: hard against the border, a card
read as leaning, because what sits opposite a control is usually the short
half of a wrapped line rather than anything at all.
And one regression caught in the screenshot: the settings row stacks below a
CONTAINER width, and that threshold was written as 300px -- which happened to
be just above what the properties column resolved to. Trimming 4px of padding
off two nested boxes widened it past the line, and every setting in that
column went back to being shredded, in a commit about something else. It is
360 now, which is what the numbers say it should always have been: a 180px
control column needs at least as much again beside it.
The layout was assembled by hand and read like it. Measured at 1440x900:
the three columns started at three different heights, a panel head was 41px
when it held a control and 34 when it did not, the gap left of the centre
was 7px and right of it 19, the properties column sat 11px further in than
the others inside a border that meant nothing, and five controls in one
list had four different widths -- a <select> takes the width of its widest
option, so the row listing checkpoint filenames was 124px wider than its
neighbours.
Now: --gutter is the space between regions, between two panels stacked in
a column, and inside the bands; the head band height is the panel head
height is the collapsible head height; --control-col gives every settings
control the same two edges. The frame's bands run edge to edge and the
content is inset by the gutter, so the app has an outline instead of a
margin that changed per region.
Also here, all of it visible in the same screenshot:
* The status sat against the Generate button with 1300px of empty bar to
its left -- everything was in one right-aligned group. What the app says
is at the start of the row now, what you press is at the end.
* A panel body is a column with a gap: two things put in it by two parts
of the app had whatever space their line boxes happened to leave.
* A container query adds no specificity, so the narrow-panel rule written
above the rules it overrides lost -- and flex-basis in a column is
HEIGHT, which turned four settings into a panel two screens long.
* The theme you picked was thrown away on every load: the appearance
module applied its own declared default over the choice the page had
already applied from storage. It adopts the live value now, and a panel
is built after setup so its control shows what setup settled on.
The plan asked for jsdom AND Playwright from the start and only jsdom was
ever built. jsdom has no layout engine: getBoundingClientRect answers zeros,
container queries never fire, a theme is an attribute rather than a computed
cascade. So every claim about POSITION or SIZE in this kit was unchecked, and
the unit suite could not have noticed either of these.
A popover bounded its height and not its width. `max-height: 60vh` was there
from the start; there was no max-inline-size at all, so a long unbroken
string -- a file path, a model filename -- made the popover wider than the
screen and anchor.js could not save it: it can move a box, not shrink one.
Measured at 1436px inside a 1280px viewport, off the right edge in all four
corners.
A horizontal split could not fit a narrow screen. The first pane carries an
inline size and `flex: 0 0 auto`, so it would not shrink, and the page
scrolled sideways at 360px -- 407px of content in a 360px viewport. It wraps
now, which stacks the panes, rather than a media query: the kit sizes itself
from its container and not from the window.
Nine layout tests: every overlay corner, an overlay taller than the viewport,
both themes resolving every token they use, light actually being lighter than
dark, and no horizontal scrollbar at five widths. `npm run test:all` runs both
suites.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>