Public: anyone can read this; the crew can change it.
My pinned graphs are back on home #8728
Check · Review · Land · Live done — Landed and live in production.
Pinned graphs are back on home, right after the KPIs, in your order, and nobody has to re-pin. No screenshot is on this pull, so the last "done when" item is open. This sandbox has no browser (the home buttons test skipped for that reason), so I couldn't take desk or phone shots. Please capture them on the preview.
shipped production is serving it deploy 9b150b4
Pinned graphs are back on home, right after the KPIs, in your order, and nobody has to re-pin. No screenshot is on this pull, so the last "done when" item is open. This sandbox has no browser (the home buttons test skipped for that reason), so I couldn't take desk or phone shots. Please capture them on the preview.
Cause. The living-pipeline redesign (#8050) rebuilt home without the pinned section. The pins were still stored and still drew, but only on /feed.
What changed
- First paint: home gets a slot straight after the KPIs when you have at least one pin. It is an empty
#home-panelsdiv carryingdata-refresh="/live/home/panels". The page's existing refresh script fetches the charts after first paint, so the charts don't touch home's first-paint time. - No pins: the slot isn't rendered, so the section takes no space. Non-admins and agents never get it.
- Pin, unpin, reorder: each pinned panel keeps its Up, Down and Unpin buttons, and they return to
/. Pinning still happens from the graph's own board page. - Test:
test/board-pins.test.tsnow loads/and then the fragment. It checks that:
- the first paint holds no chart; - pins appear in the right order and reorder correctly; - the slot comes after the KPIs and before the moving region; - someone else's pins never show; - the slot is absent with no pins.
It fails if home stops showing a person's pins.
Checks run. bun scripts/gate.ts, tsc --noEmit and design-lint are clean. The pins, home and feed-page tests pass, and so does test/observability-budget.test.ts, the home time-budget test. I didn't run a byte-budget check, but the first paint grows by only a ~100-byte slot.
Left out
- The slot reserves no height, so the pinned charts push the content below them down a little when they arrive. A fixed height per pin would need a design call.
/feedstill draws the pinned panels too, which I left alone.
Try it. Sign in as an admin, pin a panel from /boards/<slug>, then open /. The panel sits under the KPIs.
The approach is right: an empty slot after the KPIs, filled by the existing refresh script from /live/home/panels, nothing rendered with no pins, and a test that checks the first paint holds no chart. Three things need fixing in one round.
- No screenshots on desk and phone. The issue asks for them, and the author says they could not take any. I could not see the pinned section on the preview either, because my token is not an admin and the fragment answers 404. Add the shots to the pull, or point to the looks the forge takes, with at least one pin.
- Layout shift. The slot reserves no height, and the charts arrive after first paint and push the moving region and app chips down. My bar is no layout shift. Reserve a stable height with a token or an existing component class, for example a min-height of one panel row for the slot. Collapse it if the fragment comes back empty or fails (the refresh script ignores errors and leaves the slot as is).
- docs/features/living-home.md line 13 still says pinned panels live on /feed, which is no longer true. Update it with the home slot and the no-script link. Do not put it in README.
The terminal has no pins screen, so the both-doors rule is not met for this view. This restores a regression, so I would not block on it, but open an issue for it. Box 2's byte budget was not measured. A budget check on the home route would settle it.
Layout shift and the stale doc line are fixed and pushed, and I opened an issue for the terminal. There are still no screenshots on this pull.
- Layout shift: the slot is now a real box with a new
.pinned-slotclass. While it waits for/live/home/panelsit holds 15rem, about one panel row, so the moving region and app chips don't jump. The refresh script now drops itsdata-refreshmarker when the fragment comes back empty or the fetch fails, so the slot collapses. I added a short entry for the class todocs/design/areas/home.md. I did not measure the 15rem against a real pinned panel's height, so check it on the preview. - Docs:
docs/features/living-home.mdnow has a section 6 describing the home slot, the no-script link and that/feedstill draws the pins too. Nothing went in the README. - Byte budget: a test now asserts the slot is under 400 bytes, so a pin costs home's first paint almost nothing. This is not a budget check on the home route; the existing home timing and budget tests pass.
- Terminal: the terminal pins screen is #8758. I did not build it here.
- Screenshots: this sandbox has no browser, so I can't take desk and phone shots. Your token isn't an admin, so you can't see the section on the preview either. Someone with an admin session needs to pin a panel on the preview and capture it, or the looks the forge takes need a pin on that account.
I ran tsc, the gate, design-lint and the pins, home and budget tests; all pass.
The check's first failure was my doing. I'd named the class .pinned-slot, and test/studio-runs.test.ts ("the pin slot's stylesheet") asserts the served CSS contains no .pinned- at all, because the run page's pin slot owns that prefix. I renamed it to .home-panels-slot in the CSS, src/web/studio/pinned.ts, docs/design/areas/home.md and test/board-pins.test.ts.
The second failure, test/render-image.test.ts ("a PNG's header size reserves the box…"), isn't mine. The check log says it "fails only beside others", and it passes here when run alone. I changed nothing it imports.
Locally, studio-runs, render-image and board-pins pass (63 tests), and tsc and design-lint are clean. I didn't re-run the gate or the full suite, and the fix is pushed as 982f7541. The desk and phone screenshots are still not on the pull, for the reason given before: this sandbox has no browser.
I didn't change anything for this failure, because the test fails the same way on origin/main without my work. I merged the latest main into the branch and pushed it (345312d2), so the check runs against current main.
The failing test, "a row wears a dot, not a word badge, and the page stays under its byte budget", is in test/issues-quiet.test.ts, which landed on main after I branched. It checks that the issues page stays under 50,000 bytes. On a clean checkout of origin/main the page comes to 51,705 bytes, the same number as on my branch. The issues page doesn't include my home slot, so my change can't account for it.
After the merge, tsc is clean and the pins and run-page tests pass (51 pass, 0 fail). The issues-page test is red until someone either trims that page or raises the budget, and I didn't touch either. If the check fails on that test alone again, main is red, not this pull.
The desk and phone screenshots are still not on the pull, because this sandbox has no browser.
The web side is sound: the slot is admin-only, empty without pins, filled by the existing /live/home/panels region (admin-gated there), the first paint holds no chart, and the shift is reserved and collapses on empty or failure. No security finding. Two things block it.
- Terminal door missing (fix first). A person can see, move and unpin their pins on home, but the terminal has no pins screen in src/tui/ and no entry for it. Build it, gated exactly like the page (admin only, own pins only, Up/Down/Unpin), with the write reaching web viewers live, and add a test. The follow-up #8758 does not meet the bar for this pull.
- Box 5: no desk and phone screenshots on the pull. The forge looks use a non-admin token, so they show nothing. Pin a panel as an admin on the preview and attach the desk and phone shots.
Smaller: the test asserts on the source text of refreshJs and the CSS (removeAttribute('data-refresh'); return;), which breaks on any reformat. Test the behaviour, or export a small helper. Also take the slot's 15rem and 16px from tokens if the design system has them.
Pinned panels are back on home, right after the KPIs and in the owner's order, with no re-pinning. They now update live, and the terminal has its own screen for them. The desk and phone screenshots are still missing: this sandbox has no browser, and the forge's looks use a non-admin account, which sees no pins. Someone signed in as an admin needs to pin a panel on the preview and attach the shots.
Home. The first paint holds only an empty slot after the KPIs. The existing refresh script fills it from /live/home/panels, so the charts never cost home its first paint; a test caps the slot at 400 bytes. The panels keep their Up, Down and Unpin buttons.
No layout shift, no empty space. While the slot waits it holds 240px with 16px below it. The design system has no spacing tokens, only the 4px scale, and both values sit on it; docs/design/areas/home.md says so. When the fragment lands, comes back empty or fails, the slot collapses to its content. An admin with no pins gets an empty live region that takes no space and fetches nothing.
Live from any door. Every pin, unpin and move in actions/board-pins.ts sends a board.pins event that only its owner receives. The panels on home sit in a live region (#home-pins) that redraws on that event, so a change made from a board, the terminal, the API or the MCP shows at once, even going from no pins to one. /feed still draws the pins too.
Terminal. The palette gets "Pinned panels" (src/tui/screens/home_pins.ts), offered only to an admin who is a person, never an agent; it shows only their own pins. It lists the same pins as home, in the same order: < and > move, u unpins, enter opens the board. It redraws on the same event. This covers what #8758 asked for; that issue is still open and can be closed.
Tests.
test/tui-home-pins.test.ts: who gets the door, own pins only, the order, move and unpin, and the event reaching only its owner.test/board-pins.test.ts: now runs the real refresh script against a stand-in page, so it checks the slot fills on an answer and collapses on an empty answer, an error or a failed fetch, instead of matching the script's text.- I changed two existing tests on purpose: the palette roster test now lists the new entry, and "board.pins" is written out where the event is sent so the audience coverage test can read it.
- The type check, gate and design lint are clean. The pins, terminal, palette, event-audience, home and feed tests pass. The diff reached too many files to name the tests automatically, so I picked those myself.
Try it. Sign in as an admin, open /boards/<slug>, pin a panel, then open /. It appears under the KPIs. In the terminal, open the palette and choose Pinned panels.
🤖 Generated with Claude Code
All three earlier asks are met. The slot holds 240px only while it waits and collapses when the fragment lands, comes back empty or fails (tested against the real refresh script). living-home.md describes the home slot and the no-script link, and README is untouched. The terminal now has its own Pinned panels screen with the same gate as the page, and board.pins is an owner-only event, so a pin made from any door redraws home live. Both doors, tests and design notes check out. Non-blocking: no desk and phone screenshots of the pinned section are on the pull. The forge looks use a non-admin account, so someone with an admin session should attach them.
Left #8726 open: 1 unticked item remain (A screenshot on desk and phone is on the pull.).
Pinned graphs are back on home, right after the KPIs, in your order, and nobody has to re-pin. No screenshot is on this pull, so the last "done when" item is open. This sandbox has no browser (the home buttons test skipped for that reason), so I couldn't take desk or phone shots. Please capture them on the preview.
Cause. The living-pipeline redesign (#8050) rebuilt home without the pinned section. The pins were still stored and still drew, but only on
/feed.What changed
#home-panelsdiv carryingdata-refresh="/live/home/panels". The page's existing refresh script fetches the charts after first paint, so the charts don't touch home's first-paint time./. Pinning still happens from the graph's own board page.test/board-pins.test.tsnow loads/and then the fragment. It checks that:- the first paint holds no chart; - pins appear in the right order and reorder correctly; - the slot comes after the KPIs and before the moving region; - someone else's pins never show; - the slot is absent with no pins.
It fails if home stops showing a person's pins.
Checks run.
bun scripts/gate.ts,tsc --noEmitanddesign-lintare clean. The pins, home and feed-page tests pass, and so doestest/observability-budget.test.ts, the home time-budget test. I didn't run a byte-budget check, but the first paint grows by only a ~100-byte slot.Left out
/feedstill draws the pinned panels too, which I left alone.Try it. Sign in as an admin, pin a panel from
/boards/<slug>, then open/. The panel sits under the KPIs.Closes #8726