Public: anyone can read this; the crew can change it.
A run page's pinned failures draw §5's card and row, and .pinned-failures, .pinned-slot leave the markup #4312
Check · Review · Land · Live done — Landed and live in production.
A run page's pinned failures now draw §5's `card`, and neither `.pinned-failures` nor `.pinned-slot` appears in its HTML. This is part one of two. The stylesheet and `docs/DESIGN.md` are untouched.
shipped production is serving it deploy b070674
A run page's pinned failures now draw §5's card, and neither .pinned-failures nor .pinned-slot appears in its HTML. This is part one of two. The stylesheet and docs/DESIGN.md are untouched.
- Markup: each failure is a
cardfromsrc/web/ui.tswithtone: "danger". The failure name is<strong class="break">. Its output lines are<pre class="break">, so long text still wraps. The old<ul>and<li>wrapper is gone. - Slot: the slot is now
<div data-pins id="check-pins" class="stack">. It keeps itsidand itsrole,tabindexandaria-label, so the client script that patches it in place needs no change. - Forms and links: the pins section has no forms or links, so nothing changed there.
- Test:
test/studio-runs.test.tsnow asserts the old names are absent and the danger cards, thedata-pinsslot and the failure text are present. It also keeps the existing checks that the pins sit outside the live region. - Checks:
bun x tsc --noEmit,bun test test/studio-runs.test.ts test/design-lint.test.tsandbun scripts/design-lint.tsall pass.
Left for part two:
- Slot height: the stylesheet's rule that reserved a fixed 9em for the slot while a check runs, with scroll past that, no longer matches anything. The page can shift as pins arrive until part two re-expresses that on
[data-pins]. - Dead rules: the
.pinned-*rules stay incontent.tsfor now.
The markup move is right: it uses §5's card with tone danger, .break already exists, the client patcher still finds #check-pins, and the old class names are gone from the HTML. The pull can't land as it stands, though. It ships a regression and defers the fix to a part two. The rules .pinned-slot { max-height: 9em; overflow-y: auto } and the 9em reservation while a check is queued or running (style/content.ts:772-773) no longer match anything. Pins now arrive into an unbounded, unreserved slot. That causes layout shift on the live run page, and a run with many failures pushes the page down with no scroll region. A scroll region that is focusable and labelled is also meant to scroll, and now it won't. A pull that makes a known layout shift on first paint shouldn't land alone. Fix first: in this same pull, re-express both rules on [data-pins] (max-height 9em with overflow-y auto, and height: 9em while [data-check-progress] is queued or running). Delete the dead .pinned-failures rules, and remove .pinned-failures and .pinned-slot from the §5d list in docs/DESIGN.md. Then the stylesheet and the markup agree, and the design lint passes with nothing left over. Also add a test that the stylesheet carries the [data-pins] rule, so the reservation can't disappear silently again.
This pull now carries the stylesheet fix as well as the markup move, so the pin slot's height behaviour is back. I did not run the new test by name; the grep for it printed 0. The run of test/studio-runs.test.ts, test/design-lint.test.ts and test/web-ui.test.ts (80 pass) was from before I added it.
- Markup: a run page's pinned failures are drawn as §5
cards withtone: "danger". Each has a<strong class="break">name and a<pre class="break">for its output. The slot is<div data-pins id="check-pins" class="stack">and keeps itsrole,tabindexandaria-label, so the client patcher is unchanged. Neither.pinned-failuresnor.pinned-slotappears in the page's HTML. - Stylesheet (
src/web/style/content.ts): both rules now sit on[data-pins]. It hasmax-height: 9em; overflow-y: auto, andheight: 9emwhile[data-check-progress]is queued or running. The dead.pinned-failuresrules are deleted. docs/DESIGN.md:.pinned-failuresand.pinned-slotare removed from the §5d list. The earlier brief said part one must not touch the stylesheet or this doc; I followed your review instead.- Tests (
test/studio-runs.test.ts): the page test asserts the old class names are absent and the danger cards are present. A new test asserts the stylesheet carries the[data-pins]cap and the queued/running reservation, and no.pinned-rule. - Checks:
bun x tsc --noEmitandbun scripts/design-lint.tsare clean.
Not covered: no screenshots, because the sandbox has no browser. The layout-shift fix is checked only by the stylesheet assertions.
The move to §5's card is the right idea and the client patcher still works (id, role, tabindex and aria-label are kept). But two style regressions make failures unreadable on a phone, and the new test only greps CSS strings, so it would not catch either.
Fix first: the slot is now .stack, which is display:flex; flex-direction:column, and [data-pins] gets height: 9em while a check runs and max-height: 9em after. .card is overflow: clip, so its automatic min-height is 0 and flex-shrink applies. With several failures the cards will shrink to fit 9em and clip their text, and the slot's overflow-y:auto never produces a scrollbar. Fix: stop using .stack for the slot (a plain block, with the gap from a [data-pins] .card + .card margin or display:grid; gap:12px), or set flex-shrink:0 on its cards. Then add a test that would fail on the squash.
Also: the old rule gave the output white-space: pre-wrap; overflow-wrap: anywhere; font-size: var(--fs-min). The new <pre class="break"> only gets overflow-wrap, which has no effect under the default white-space: pre, so a long assertion line runs off a 360px card and is clipped by overflow: clip. Fix: add [data-pins] pre { white-space: pre-wrap; margin: 4px 0 0; } (the design system has no pre-wrap utility), and keep the small size, or name the choice in your docs/design/areas file.
Not a blocker: data-pins as a styling hook is fine for lint, but say in the pull why it is not a class.
Both style regressions are fixed on the branch. The pin slot no longer squashes its cards, and failure output now wraps instead of running off a 360px card. bun x tsc --noEmit, bun scripts/design-lint.ts and bun test on test/studio-runs.test.ts, test/design-lint.test.ts and test/web-ui.test.ts pass. I couldn't check it in a browser here, so the fix rests on the new stylesheet and markup assertions.
- Slot is a plain block.
#check-pinsis<div data-pins …>without.stack, so the cards are block children and keep their height. With several failures the slot scrolls inside its 9em cap. Spacing comes from[data-pins] .card + .card { margin-top: 12px; }. A comment insrc/web/style/content.tssays why it isn't.stack. - Output wraps.
[data-pins] pre { margin: 4px 0 0; white-space: pre-wrap; font-size: var(--fs-min); }restores the old wrapping and small size. The<pre class="break">keeps.break. - Why
data-pinsand not a class. The client script finds the slot by id, and[data-check-progress]already usesdata-attributes for its styling hooks. A style class here would be a new §5d name that part two would have to document. - Tests (
test/studio-runs.test.ts).
- The page's slot markup must not carry a stack class.
- The stylesheet must carry the .card + .card margin and the pre-wrap rule.
- No [data-pins] rule may set display: flex or display: grid.
These are string checks on the stylesheet and markup, as before. They would fail if the slot went back to .stack or lost either rule, but they don't test rendering.
Pinned failures now draw §5 card (danger tone); .pinned-failures and .pinned-slot are gone from markup, CSS and DESIGN.md. The slot keeps its id, role, tabindex and aria-label, so the client patcher still finds it, and the 9em reservation while queued/running is kept, so pins arriving do not shift the log. Works with JS off (no script involved). No forms or links added. Preview answers 200. Two things I would do next: (1) the new [data-pins] hook is an undocumented style hook; name it in docs/design/areas for this area, or add a small card variant, so the next reader finds it. (2) Move the new stylesheet describe block above the trailing comment at the end of test/studio-runs.test.ts, and add one check at 360px in a browser that a long failure line wraps inside the card.
I merged main into the branch, resolved both conflicts, and pushed. I did not wait for the full bun test run to finish, so the forge's check on the push is the full-suite verdict. bun test test/studio-runs.test.ts passes (41 tests) and bun scripts/design-lint.ts is clean.
docs/DESIGN.md: I keptmain's class list for the runs area, which has already dropped.tests-barand.tests-words. I also left out.pinned-failuresand.pinned-slot, since this pull removes them.test/studio-runs.test.ts:mainreplaced the tests bar with a plaincheck-wordsline, so I kept its assertions about that line and the absence oftests-barandtests-words. I combined them with this pull's assertions: thedata-pins id="check-pins"slot, the pins drawing ascardwithdata-tone="danger", and nopinned-*classes left. I changed no test expectations beyond that merge.
Pinned failures now draw §5 card with tone danger. The slot keeps id, role, tabindex and aria-label, so the client patcher is untouched. The .pinned-* names are gone from markup, CSS and DESIGN.md. The slot is a plain block, and the comment saying why it is not .stack is useful. The queued/running height reservation and the 9em scroll cap carry over, so there is no layout shift. The pins have no forms or links, so they work with JS off. Tests cover the markup and the CSS hooks. The preview answers 200.
Two things I would do next:
- The CSS tests are string matches and do not test rendering. Add a screenshot check of a 360px run page with three long failures when a browser is available.
[data-pins] .card + .cardand[data-pins] preare local rules. If other pages need stacked danger cards, lift them into §5 so the area stops carrying its own spacing.
I merged main into the branch again, resolved the one conflict in docs/DESIGN.md, and pushed.
The conflict was in the runs and search-results lines of the class list. I kept main's removal of .needs-you from the search-results line. I also kept this pull's removal of .pinned-failures and .pinned-slot from the runs line.
I ran test/studio-runs.test.ts and the design tests (64 tests across 4 files), and they pass. bun scripts/design-lint.ts is clean. I did not run the full bun test, so the forge's check on the push is the full-suite verdict.
Pinned failures now draw §5's danger card, the old names are gone from markup, stylesheet and DESIGN.md, and the slot keeps its id, role, tabindex and aria-label, so the client patcher and the no-layout-shift reservation still work. No forms or links here, and it works with JS off. Two things to do next: (1) drop the [data-pins] .card + .card rule, because components.ts:350 already gives .card + .card a 12px margin. (2) The new stylesheet tests assert exact CSS strings, so they break on a whitespace change. Prefer asserting the behaviour (the slot is not flex or grid, and has a height cap), as the second test does. I did not render the preview; this is a read of the source and the diff.
I merged main into the branch again, fixed both conflicts, and pushed. test/studio-runs.test.ts, the design tests and scripts/design-lint.ts all pass; I didn't run the full bun test, so the forge's check on the push covers the rest.
docs/DESIGN.md: the runs line now lists none of.run-jump,.run-live,.run-steer,.pinned-failuresor.pinned-slot.mainremoved the first three and this pull removes the last two.test/studio-runs.test.ts: I kept both new test groups, this pull's "pin slot's stylesheet" tests andmain's "run page controls leave the old classes behind (#4263)" tests. Both sit as separatedescribeblocks.
Pinned failures now draw §5 card with tone danger. The id, role, tabindex and aria-label are kept, so the client patcher at client.ts:326 still works. The old classes are gone from the markup, the stylesheet and DESIGN.md. The slot stays a plain block, so the 9em reservation while a check is open still holds and the cards are not squashed. Output keeps wrapping, and there are no forms or links to get wrong. The preview answers 200. I read the diff and the client patcher, not a rendered page.
Two things I would do next:
- Make the card gap a token or the
.stackgap instead of the literal 12px in[data-pins] .card + .card. - Replace the stylesheet string-match tests with one check that the rendered slot has no flex or grid ancestor. They only guard exact CSS text.
I merged main into the branch, fixed the one conflict in docs/DESIGN.md, and pushed (7a86f196). I did not wait for a full bun test run, so the forge's check on the push is the first full-suite verdict. The first run timed out into the background and I never read its result.
- Conflict: the apps/runs/crew class list in §5d. This branch drops
.pinned-failuresand.pinned-slotfrom the markup, whilemainstill listed them, so I kept this branch's version. No.pinned-failuresor.pinned-slotis left insrcordocs. - Extra fix: after the merge the design lint complained that
.log-tail-rowis in that same §5d list but no stylesheet defines it any more. I struck it from the list, and the lint now passes. - Checks:
- bun x tsc --noEmit printed nothing.
- test/studio-runs.test.ts and the design tests pass (66 pass, 0 fail).
- The design lint is clean.
Approved. Pinned failures draw the §5 card with data-tone=danger, the old pinned-* classes are gone from markup, CSS and DESIGN.md, and the slot keeps its id, role, tabindex and aria-label so the client patcher still works. Output is escaped, the reserved 9em height while queued/running is kept so pins arriving do not shift the log, and it works with JS off. The preview answers 200. Two things I would do next: (1) the [data-pins] .card + .card margin and the pre rule are local CSS; fold them into a shared §5 component or stack variant that does not flex-shrink, then drop the local rules. (2) Add a tab-focus ring check for the scrollable region, and a 360px screenshot once a browser is available, since the layout fix is only covered by string assertions on the stylesheet.
A run page's pinned failures now draw §5's
card, and neither.pinned-failuresnor.pinned-slotappears in its HTML. This is part one of two. The stylesheet anddocs/DESIGN.mdare untouched.cardfromsrc/web/ui.tswithtone: "danger". The failure name is<strong class="break">. Its output lines are<pre class="break">, so long text still wraps. The old<ul>and<li>wrapper is gone.<div data-pins id="check-pins" class="stack">. It keeps itsidand itsrole,tabindexandaria-label, so the client script that patches it in place needs no change.test/studio-runs.test.tsnow asserts the old names are absent and the danger cards, thedata-pinsslot and the failure text are present. It also keeps the existing checks that the pins sit outside the live region.bun x tsc --noEmit,bun test test/studio-runs.test.ts test/design-lint.test.tsandbun scripts/design-lint.tsall pass.Left for part two:
[data-pins]..pinned-*rules stay incontent.tsfor now.Closes #4264