Lane 1, Home: Needs you, the campaign cards, New campaign as a page, Join, the put-away fold, and J1/J2 (#727) #749

Merged
claude-bot merged 2 commits from build/lane1-home into main 2026-09-22 07:53:17 +00:00
Collaborator

Lane 1's Home PR (#727, series item 4: HOME-1 to HOME-4). Home replaces the dashboard; New campaign is a page; Join stays on Home; archived and binned campaigns fold at the foot. J1 and J2 are filled in as far as Home carries them and pass in all three projects.

Home (/dashboard, the path kept): Needs you from /api/me/attention, one row per thing with a button that is a link to where it is done, a session being played at the top, absent entirely when empty, and a banner with Try again when it could not load while the campaigns carry on. One star, one wish (IS-213) as a card between Needs you and the campaigns, asked once the day after a session, with Send and "Not this time". The campaign cards from a new GET /api/me/home aggregate (six queries whatever the campaign count): This week (the next session in the campaign's time zone with a live countdown, or "being played now · Join the table", or "voting on a time, 4 options", or "Nothing scheduled yet"), Last time with the recap's first sentence (J6's line), Open and "Read the last recap" only when there is one, and for a fresh campaign "Schedule the first session" and "Invite players". Join in place with the four outcomes. The fold: "1 archived · 1 in the bin", dimmed archived cards with Un-archive where it can work, the bin as a list with "gone for good in 5 days, 3 hours" or "waiting for the next clear-out", Restore for the owner and the owner's name for everyone else, absent when both are empty and open when nothing is on the go.

New campaign (/campaigns/new): opens on the four choices (from nothing, from a template, a one-shot, import a file), then the form for the choice: the game picker rebuilt on the library (registry, "Something else — I will type it", "Rules linked" when a system is chosen, the two empty and loading states), the three templates, the one-shot's "When, roughly", import disabled until a file is chosen and its success panel with the claimed-member count. Created lands on Home with the new card first and the "New" chip. The hosted slot line (IS-376) waits for HOME-7 and #642's provider.

Three components added to the library, each with states on /design and a test: CampCard/CampGrid, Choices (the kit's radios-with-reasons, which lane 3 reuses), and Form/FormTwo/FormActions.

Three defects the journeys found in the shell, fixed here: the countdown and "Join the table" were links in a sentence with no underline at 2.23:1 (link-in-text-block), now linkish as the prototype drew them; the bell counted twelve kinds but drew eight, so it said "2 unread" over "Nothing needs you" for most of what the product sends; and the bell's "Notification settings" link sat at 1.07:1 because the bar's link colour reached into the popover (the same shape as #745, in the places a colour is set rather than inherited).

Deliberate departures from the drawing, both in comments: Join's "That code has expired" is not built, because the server gives one message for unknown, revoked, expired and used-up codes on purpose (#643: refusals do not leak); the banner reads "That link is no longer valid" / "Ask the GM for a new link." And "Read the last recap" is offered only when there is a recap; a session played yesterday with no summary yet says "no recap yet" instead of opening an empty page.

Not built, each named in a comment: IS-195 (the ownership-offer row on Home) wants a row on /api/me/attention first, since the offer is readable only one campaign at a time; IS-152 (Discussions kinds) is lanes 7 and 8.

For the owner: Needs you rows say the time in the reader's zone (the attention API carries none) while the card says it in the campaign's; a zone on the attention response would settle it. And the sign-in rate limit (10 a minute per IP) is shared by every test in the container, so the fixture waits it out rather than the product bending for tests; a journey costs three sign-ins.

Coverage: 42 of the 45 drawn/replaced placements on HOME-1 to HOME-4 (lane1b.py), the three above excepted. Tests: frontend 1,200 (Home 31, New campaign 19, the three components 13, the frame 3 more); backend tests/test_home.py 25; journeys 18 passed in the three projects, /dashboard and /campaigns/new clean under the strict axe gate, /login the only tolerated entry left. Lint, ruff and the build clean. Render-checked from the running e2e stack against the prototype's stills.

🤖 Generated with Claude Code

Lane 1's Home PR (#727, series item 4: HOME-1 to HOME-4). Home replaces the dashboard; New campaign is a page; Join stays on Home; archived and binned campaigns fold at the foot. J1 and J2 are filled in as far as Home carries them and pass in all three projects. **Home** (`/dashboard`, the path kept): Needs you from `/api/me/attention`, one row per thing with a button that is a link to where it is done, a session being played at the top, absent entirely when empty, and a banner with Try again when it could not load while the campaigns carry on. One star, one wish (IS-213) as a card between Needs you and the campaigns, asked once the day after a session, with Send and "Not this time". The campaign cards from a new **`GET /api/me/home`** aggregate (six queries whatever the campaign count): This week (the next session in the campaign's time zone with a live countdown, or "being played now · Join the table", or "voting on a time, 4 options", or "Nothing scheduled yet"), Last time with the recap's first sentence (J6's line), Open and "Read the last recap" only when there is one, and for a fresh campaign "Schedule the first session" and "Invite players". Join in place with the four outcomes. The fold: "1 archived · 1 in the bin", dimmed archived cards with Un-archive where it can work, the bin as a list with "gone for good in 5 days, 3 hours" or "waiting for the next clear-out", Restore for the owner and the owner's name for everyone else, absent when both are empty and open when nothing is on the go. **New campaign** (`/campaigns/new`): opens on the four choices (from nothing, from a template, a one-shot, import a file), then the form for the choice: the game picker rebuilt on the library (registry, "Something else — I will type it", "Rules linked" when a system is chosen, the two empty and loading states), the three templates, the one-shot's "When, roughly", import disabled until a file is chosen and its success panel with the claimed-member count. Created lands on Home with the new card first and the "New" chip. The hosted slot line (IS-376) waits for HOME-7 and #642's provider. **Three components added to the library**, each with states on `/design` and a test: `CampCard`/`CampGrid`, `Choices` (the kit's radios-with-reasons, which lane 3 reuses), and `Form`/`FormTwo`/`FormActions`. **Three defects the journeys found in the shell, fixed here:** the countdown and "Join the table" were links in a sentence with no underline at 2.23:1 (`link-in-text-block`), now `linkish` as the prototype drew them; the bell counted twelve kinds but drew eight, so it said "2 unread" over "Nothing needs you" for most of what the product sends; and the bell's "Notification settings" link sat at 1.07:1 because the bar's link colour reached into the popover (the same shape as #745, in the places a colour is set rather than inherited). **Deliberate departures from the drawing, both in comments:** Join's "That code has expired" is not built, because the server gives one message for unknown, revoked, expired and used-up codes on purpose (#643: refusals do not leak); the banner reads "That link is no longer valid" / "Ask the GM for a new link." And "Read the last recap" is offered only when there is a recap; a session played yesterday with no summary yet says "no recap yet" instead of opening an empty page. **Not built, each named in a comment:** IS-195 (the ownership-offer row on Home) wants a row on `/api/me/attention` first, since the offer is readable only one campaign at a time; IS-152 (Discussions kinds) is lanes 7 and 8. **For the owner:** Needs you rows say the time in the reader's zone (the attention API carries none) while the card says it in the campaign's; a zone on the attention response would settle it. And the sign-in rate limit (10 a minute per IP) is shared by every test in the container, so the fixture waits it out rather than the product bending for tests; a journey costs three sign-ins. Coverage: 42 of the 45 drawn/replaced placements on HOME-1 to HOME-4 (`lane1b.py`), the three above excepted. Tests: frontend 1,200 (Home 31, New campaign 19, the three components 13, the frame 3 more); backend `tests/test_home.py` 25; journeys 18 passed in the three projects, `/dashboard` and `/campaigns/new` clean under the strict axe gate, `/login` the only tolerated entry left. Lint, ruff and the build clean. Render-checked from the running e2e stack against the prototype's stills. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
`/dashboard` is Home now — the first page of the redesign built out of the
component library, and the end of `Dashboard.jsx` and `components/NeedsYou.jsx`.
The address does not change, because paths are contracts (build plan §2.4);
only what a person reads does.

HOME-1. Needs you keeps its two rules and gains the one it was missing: absent
entirely when nothing is waiting (SH-040), a kind this build does not know
dropped rather than drawn wrong (SH-048), and — new — a warn banner with Try
again when it cannot be loaded, with the campaigns below it carrying on
(SH-049). It used to vanish without a word, which reads as "nothing is waiting
on you". A session being played goes to the top and its button goes to the
table, where the frame's live bar already sends you.

Each campaign is a card: name, the game with its Rules-linked chip, the
members, what you are to it; This week (the next session with a countdown that
ticks once a minute and is a link, "being played now", or "voting on a time, 4
options"), Last time, and the first line of that session's recap. A fresh
campaign says "Nothing scheduled yet" and offers the two things it actually
needs next (SH-054).

HOME-3. Join is a small form in place on Home that takes a pasted link as
readily as a code, and says by name which of joined, asked-to-join and
already-a-member happened. One departure from the drawing: the refusal does
*not* say "that code has expired", because the server gives one answer for
unknown, revoked, expired and used-up on purpose (#643) and saying which would
tell a stranger with a guessed code what they had found.

HOME-4. Archived and binned campaigns fold at the foot — "1 archived · 1 in the
bin", absent when there are none, open when they are all there is — with the
bin counting down to the clear-out and naming the owner where Restore is not
yours to press.

HOME-2. New campaign is a page of its own at `/campaigns/new` that opens on a
choice (D46): from nothing, from a template, a one-shot, or a file to import.
`useActiveCampaignId` learns that "new" is a page and not a campaign id, or the
frame would draw a campaign's Contents and poll `/api/campaigns/new/live`. The
hosted slot line and its "no free slot" state (IS-376) are deliberately not
built: there is no entitlement API to ask, and HOME-7 and #642 own it.

Three components the library lacked, each in its own folder with its states and
its test: `CampCard` (with `CampGrid`), `Choices`, and `Form` (with `FormTwo`
and `FormActions`).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
test(e2e): J1 and J2 as far as Home carries them, and the three things they found (#727, #726)
All checks were successful
CI / Summarisation accuracy eval harness (stub provider) (pull_request) Successful in 54s
CI / Backend lint (ruff) (pull_request) Successful in 28s
CI / Bot tests and audit (pull_request) Successful in 2m0s
CI / Docker image build (pull_request) Successful in 40s
CI / Bot/backend version sync (pull_request) Successful in 41s
CI / Feedback site tests (pull_request) Successful in 59s
CI / Frontend tests, audit, and build (pull_request) Successful in 2m57s
CI / End-to-end journeys (desktop, phone, keyboard-only) (pull_request) Successful in 2m43s
CI / Backend migration, tests, and audit (pull_request) Successful in 8m51s
CI / Synthetic session harness (no GPU, no LLM) (pull_request) Successful in 18m23s
306152b629
The journeys stop being stubs where lane 1's surfaces start.

**J1** — a first-time GM signs in with no campaigns and is offered the two ways
in and nothing else; then Dana starts one from nothing and lands back on Home
with it first, wearing its "New" chip and offering the two things a campaign
that has never been played needs next. Two tests rather than one, because the
three projects share one database and run one after another: "a person with no
campaigns" is single-use, so Wren is only looked at and stays campaign-less for
lane 3's invite step.

**J2** — Priya is asked whether she is in, in both of the places the product
asks: the Needs you row on Home, and the bell, where the record the server
wrote when Dana confirmed the session is waiting. Read-only, so the next
project finds the same state.

`a11y-baseline.js` loses `/dashboard` and both `kind: "bug"` entries: #745/#747
fixed the two the harness found, and Home is a new page. `/dashboard` and
`/campaigns/new` are now strictly clean, and one entry is left in the file.

Three defects the run found, all in lane 1's own chrome, all fixed here:

1. **The countdown and "Join the table" were links in a sentence with no
   underline** — 2.23:1 against the text around them where 3:1 is the bar
   (WCAG 1.4.1). They are `.linkish` now, which is how the prototype drew them.
2. **The bell listed nothing while counting everything.** `/api/me/notifications`
   speaks twelve kinds, the kit's bell knows eight and drops the rest, and the
   frame handed the former straight to the latter: "2 unread" over "Nothing
   needs you". `NOTE_KIND` in `AppFrame.jsx` maps them, and `NOTE_ICON` gains
   the two people-shaped kinds it had no row for.
3. **The bell's "Notification settings" link was invisible** — `.appbar a`
   colours the bar's links for the dark chrome and the panel is a descendant of
   the bar, so it came out at 1.07:1 on paper. Search's "All N in …" had it too.

And two smaller things: a campaign whose last session has no summary yet no
longer offers "Read the last recap" for a recap that is not there, and the page
fills the Book so the paper reaches the foot.

`signInAs` now waits out a 429 rather than failing. The suite signs somebody in
twelve times a run and `/auth/login` is limited to 10/minute per IP, which every
test in the container shares — real product behaviour, so the suite waits for it
instead of it being turned off.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign in to join this conversation.
No description provided.