Build lane 2: the public pages (PUB-1 to PUB-12) #728
Closed
opened 2026-09-22 00:12:19 +00:00 by claude-bot
·
8 comments
No Branch/Tag specified
main
feat/1328-fill-it-in
feat/1328-fill-frontend
feat/1328-fill-backend
feat/9-foundry-push
fix/9-foundry-live
feat/9-foundry-push-frontend
renovate/celery-5.x
feat/5-foundry-connect
feat/9-foundry-push-backend
feat/9-foundry-push-module
feat/5-foundry-frontend
feat/5-foundry-backend
feat/5-foundry-module
release/v4.8.0-rc1
docs/d341-convert-draft
feat/958-update-to-version
feat/958-convert-sheet
feat/958-pathbuilder-import-frontend
fix/1360-heading-order
feat/958-pathbuilder-import-backend
feat/11-weekly-digest
feat/1341-auto-update
docs/d332-superseded
chore/1345-names-cleanup
feat/1342-mentioned-pages
feat/1328-recipes
fix/1346-pgdg-key
perf/1247-shared-recording-stream
chore/132-gitleaks-allowlist
release/v4.7.1
spike/foundry-module
release/v4.7.1-rc1
docs/decisions-d332-d337
fix/bot-certifi
chore/release-4.7.0
chore/release-4.7.0-rc4
chore/deps-4.7.0
chore/release-4.7.0-rc3
fix/1280-quote-must-say-it
fix/1257-names-row-squeeze
chore/release-4.7.0-rc2
fix/1245-pg-upgrade-count
chore/release-4.7.0-rc1
feat/1257-names-in-prep
feat/1257-be
feat/1257-fe
feat/1257-rating-fixes
design/1328-fill-it-in
feat/1257-name-splits
fix/1326-redis-503
feat/1280-fact-suggestions
feat/1280-be
feat/1280-fe
design/1280-fact-suggestions
feat/1279-infobox
feat/1279-be
feat/1279-fe
feat/1321-shelf-copies
design/1279-infobox
feat/1243-table-find
feat/1257-who-rated
feat/1243-prep-drawer
feat/1243-sheet-pickers
design/1243-browse-in-place
feat/1315-hotwords-default
feat/1242-system-filters
feat/1257-more-name-styles
feat/506-leg3-hotwords
design/1242-system-filters
fix/1302-packs-polish
feat/1241-rules-library
design/1241-rules-library
feat/1245-postgres-18
integ/4.6.2
fix/1263-map-ui-2
fix/1263-map-server
fix/1263-map-ui-1
fix/1261-editor-link-menu
fix/1229-axe-4.14-name-mismatch
renovate/axllent-mailpit-1.x
renovate/eslint-monorepo
renovate/authlib-1.x
chore/release-4.6.0
chore/release-4.6.0-rc2
fix/460-rc2-screens
fix/460-rc2-server
fix/release-prerelease-exit
chore/release-4.6.0-rc1
feat/125-campaign-templates
feat/126-calendar
feat/1181-pictures-and-files
feat/1190-event-people
integ/4.6.0
feat/1191-line-of-the-night
feat/1200-starter-packs
chore/bot-multidict-and-playwright-group
fix/1202-this-week-answered-count
fix/122-124-leftovers
fix/1178-get-routes-that-write
fix/1203-journeys-check-names
design/125-campaign-templates
feat/126-calendar-engine
design/126-in-world-calendar
fix/1189-cited-stamp-in-range
fix/1189-v4-looser-check
fix/1189-richer-beats
fix/1113-export-bind-lists
fix/1154-release-notes-by-file
chore/release-4.5.0
chore/release-4.5.0-rc12
fix/1135-wiki-markup-as-text
fix/demo-usage-cost-in-window
chore/release-4.5.0-rc11
fix/1121-sheet-consistency
fix/1121-sheet-5e-terms-and-card-hp
copy/1122-busiest-pages
fix/1121-relevant-choices
fix/1121-wiki-create-npc-save-sheet-links
fix/1029-menu-stays-on-screen
docs/prototype-transcript-bin-wording
fix/1023-editor-save-row-back-scroll
fix/1020-search-exact-first
fix/1020-table-prep
fix/1020-shell-wordmark-footer-bell
fix/1020-wiki-article-party
fix/872-admin-kept-until-phone-tables
feat/l13-milestone-level-waiting
fix/1000-1001-bell-older-setup-context
fix/999-pronouns-in-prompts
fix/l19-other-class-feats
fix/1010-transcript-window-ordinary-confirm
docs/d254-d269-decisions
fix/702-member-search
fix/680-transcript-bin
fix/993-unidentified-prompts
fix/841-redis-timeouts
fix/990-binned-not-exported
fix/830-export-prep-shelf
fix/deps-audit-2026-10-01
fix/877-title-reads
fix/798-audio-received-at
build/lane11-17-j7
build/lane11-16-levelup
build/lane11-14-seams
build/lane11-14-seed
build/lane11-15-start
build/lane11-13-old-block-out
fix/980-review-r3
build/lane11-12-block
build/lane11-8-packs
fix/demo-seed-canonical-names
build/lane11-11-hot-half
docs/l11-decisions
build/lane11-7-convert
build/lane11-10-editing
fix/npm-audit-brace-expansion
build/lane11-9-sheet-page
fix/bot-pyjwt
build/lane11-6-content
fix/lane11-rank-names
build/lane11-2b-language
build/lane11-4-js-evaluator
build/lane11-3-server
build/lane11-5a-pf2e
build/lane11-5b-5e
feat/design-admin
build/lane11-2-evaluator
build/lane11-1-sheet-pieces
build/lane11-0-drawing
fix/943-quest-objectives-fk
fix/prepsheet-shelf-flake
fix/945-leftovers
build/demo-gm-copy
fix/901-email-landings
build/lane10-8-journeys
build/demo-seed-lanes-8-10
fix/887-gm-own-confirmation
build/lane9-5-j1-admin
fix/918-audience-click
fix/useasync-overtaken
ci/939-critical-path
test/937-backend-suite-speed
chore/claude-orchestration
fix/924-xp-gm-only
fix/session-stale-poll
docs/decisions-d239-d242
fix/930-pypdf
build/lane8-journeys
build/925-quest-editor
fix/894-private-page-pictures
build/lane8-p4-drafts
build/lane8-p7-map
build/lane8-p6-handouts-rules
fix/wiki-fixture-names
build/lane10-d227-test-usage
fix/rsvp-horizon-test-tuesday
fix/media-volume-owner
build/lane8-p3-editor
fix/912-unidentified-rename
build/lane8-p5-party-quests
build/lane8-handout-takeback
build/lane10-pickers
build/lane8-p2-article
build/lane8-6-map
build/lane10-7b-email-pages
build/lane8-5-handouts
build/lane10-7a-test-the-bot-pages
build/lane8-p1-pages
build/lane8-4-quests
build/lane8-2b-feeds
build/lane8-3-parties
build/lane8-2a-links
build/lane10-5-commands
build/lane9-6-seed
build/lane10-4b-reactions
build/lane9-4d-pages
build/lane9-4c-pages
build/lane10-4a-posts
build/lane10-3-email
fix/891-web-fonts
build/lane9-4b-pages
build/lane10-6-test-the-bot
build/lane10-2-notify-out
build/lane8-1-wiki-text
build/lane9-4a-frame
design/lane10-drawings
fix/j6-budget
fix/j5-phone-flake
fix/869-test-leaks
fix/843-record-start-followups
build/lane7-all
build/lane6-all
build/lane9-b2-server
chore/changelog-fragments
docs/decisions-d218
build/lane9-a-owner-overview
fix/rule-card-level-label
fix/834-retention-semantics
fix/o3c-record-without-announcement
docs/decisions-d179
docs/decisions-d131-d170
fix/851-commit-before-response
build/lane6-j3-seed
build/lane9-b1-d67-identity
fix/841-blocking-loop
build/lane9-c-backups-audit
fix/vote-race-and-start-commit
fix/recording-announcement
fix/proposal-read-leak
fix/last-admin-guard
build/lane6-p4c-planning
build/lane6-p4b-margin
build/lane6-p4a-sheet
build/lane5-j4-seed
build/lane6-base
build/lane7-pages-talk
build/lane5-pages
build/lane7-pages-safety
build/lane7-p3-safety
build/lane7-p2-notify
build/lane6-p3-planning
build/lane6-p2-history
build/lane6-p1b-items
build/lane7-p1-threads
build/lane5-p6-faces
build/lane6-p1a-sheet
build/lane5-p5-find
build/lane5-p4a-board
build/lane5-p4b-scenes
build/lane5-p3-live
build/lane5-base
build/lane5-p2-cards
docs/lane5-decisions
build/review-r2-wide
fix/review-r1
build/lane5-p1-scenes
build/demo-seed
build/lane4-journeys-j5
build/lane4-page-review-b
build/lane4-page-review-a
build/lane4-page-read
build/lane4-journeys
build/lane4-page-sess2
build/lane4-page-sess1
build/lane4-notes
build/lane4-discord-on-approval
build/lane4-scheduling
build/lane4-versions
build/760-session-number
build/lane4-decisions
build/797-erase-no-regenerate
build/test-race-audit
build/lane3-completions
build/794-dark-only
build/796-titles-scroll
build/791-retention-anchor
build/a11y-sweep
build/shell-followups
build/retention-preview
build/753-backup-readback
docs/d91-d93
build/lane3-j1
build/ci-harness-paths-selftest
fix/useauth-test-race
build/ci-harness-paths
build/777-ai-settings-read
build/lane3-settings-c
build/lane3-settings-b
build/lane3-j6
build/lane3-sessionform
build/lane3-settings-a
build/lane3-members
build/lane3-thisweek
build/lane3-story
chore/87-align-python-3.12
v4.8.0-rc1
v4.7.1
v4.7.1-rc1
v4.7.0
v4.7.0-rc4
v4.7.0-rc3
v4.7.0-rc2
v4.7.0-rc1
v4.6.2
v4.6.2-rc4
v4.6.2-rc3
v4.6.2-rc2
v4.6.2-rc1
v4.6.1
v4.6.1-rc1
v4.6.0
v4.6.0-rc2
v4.6.0-rc1
v4.5.3
v4.5.3-rc1
v4.5.2
v4.5.2-rc1
v4.5.1
v4.5.1-rc2
v4.5.1-rc1
v4.5.0
v4.5.0-rc12
v4.5.0-rc11
v4.5.0-rc10
v4.5.0-rc9
v4.5.0-rc8
v4.5.0-rc7
v4.5.0-rc6
v4.5.0-rc5
v4.5.0-rc4
v4.5.0-rc3
v4.5.0-rc2
v4.5.0-rc1
v4.4.1
v4.4.0
v4.3.0
v4.2.3
v4.2.2
v4.2.1
v4.2.0
v4.1.2
v4.1.1
v4.1.0
v4.0.1
v4.0.0
v3.11.4
v3.11.3
v3.11.2
v3.11.1
v3.11.0
v3.10.0
v3.9.1
v3.9.0
v3.8.0
v3.7.0
v3.6.1
v3.6.0
v3.5.0
v3.4.1
v3.4.0
v3.3.0
v3.2.0
v3.1.0
v3.0.0
v2.1.0
v2.0.0
v1.1.0
v1.0.0
v0.12.0
v0.11.0
v0.10.0
v0.9.1
v0.3.3
v0.9.0
v0.8.0
v0.3.2
v0.3.1
v0.3.0
v0.7.0
v0.6.0
v0.5.0
v0.4.0
v0.2.1
v0.2.0
v0.1.1
v0.1.0
Labels
Clear labels
backend
Issue related to the backend
bot
Issue related to the bot
bug
Something is not working
duplicate
This issue or pull request already exists
enhancement
New feature
frontend
Issue related to the frontend
help wanted
Need some help
invalid
Something is wrong
question
More information is needed
recording
Issue related to the recording system
security
Security hardening / vulnerability work
wontfix
This won't be fixed
No labels
backend
bot
bug
duplicate
enhancement
frontend
help wanted
invalid
question
recording
security
wontfix
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/Quest-Board#728
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Build lane 2 of the v4.5.0 redesign. The brief is
docs/design/v4.5.0-brief.md(§9, the lanes in order); the build plan isdocs/design/v4.5.0-build-plan.md(the rollout rule, the design-system mapping, the journeys as tests). Umbrella: #366. Goes after lane 1.Scope
Surfaces: PUB-1 to PUB-12: the front door, sign in, an invitation, the shared analytics page, Help, Licences & notices, not found and the crash screens, first-run setup, the Discord link pages, Accessibility, Privacy.
The drawing:
/feedback/prototype/lane1c— the page the build must match, still by still.Decisions: the brief §7, and each surface's header in
redesign-surfaces/sources/headers.md.Server changes it needs (in this lane or an earlier one)
IS-251toIS-258)Acceptance
coverage/lane1c.pyclassifies as drawn or replaced is built as the prototype draws it; the script is the checklist. Rows it marks behaviour are tested, not drawn.vocabulary.js; no page-level error destroys rendered content; every async operation shows progress and a next action on failure; disabled controls say why.redesign-surfaces/sources/headers.md(Decided lines and the owner's review notes) are honoured; a departure is a decision change on #659 first.Notes
🤖 Generated with Claude Code
Picking this up. Lane 1 (#727) merged this morning — PRs #742, #744, #747, #748, #749, #750 — so lane 2 is next in the build plan's order.
Read first: the drawing (
/feedback/prototype/lane1c, the twelve PUB sections and its "Reviewed, settled, and still open" list), the checklist (coverage/lane1c.py— 109 placements: 89 drawn, 4 replaced, 10 behaviour, 6 belonging to another surface), the surfaces' headers insources/headers.md, and the decisions these pages turn on: D4, D13, D15-as-amended-by-D63, D46, D62, D63, D64, D65, D66, D68, D70.The PR series
Working agreements §7: the lane's server change first, as its own PR; then UI only; every PR names the coverage rows it builds.
1 — Server: what the public pages read. Backend only, one migration. The public pages are the only part of the app that reads the server rather than a campaign, and nothing today exposes any of it without a session:
IS-385);IS-388, ADMIN-15's storage; lane 9 draws the Admin form that writes them);IS-387), so the page cannot drift from the settings the day they change;API-016, D64);IS-196), which the invite preview cannot say today.2 — Server: first-run setup. Backend only, one migration: the setup state, the seven steps, and — the point of the decision — which steps were skipped, so Admin can list them afterwards (
IS-251–IS-258, D70: it reminds, never blocks). The step checks are Instance health's, not a second set (#439).3 — UI: the public frame, the front door, sign in. The
pubframe the twelve pages share (wordmark or crumb, the page, and the six-part footer D63 settled), then PUB-11, PUB-1 and PUB-2. Carries the footer's three new doors — Accessibility, Privacy, Licences & notices — into the signed-in shell too, where lane 1 left a comment saying they arrive with this lane.4 — UI: the invitation, the shared analytics page, Help. PUB-3, PUB-4, PUB-5.
5 — UI: the stops, and the four written pages. PUB-7 (a real 404 at last —
SH-009), PUB-6, PUB-10, PUB-12.6 — UI: setting up a new server. PUB-8, the wizard and the list it leaves in Admin, and J1's setup steps in the journeys suite.
J1 and J2 grow with the PRs that build what they walk through, rather than in a PR of their own; the axe gate is on every page they visit.
Departures
None decided in advance. Anything the build finds it cannot draw as the prototype draws it gets recorded here and in the PR body before it is built, per §7 — the build does not redesign.
🤖 Generated with Claude Code
A departure to record before it is built, on
IS-252(the setup wizard's backup step) — per §7, on the issue first.The drawing says "Take one now, and check it restores", and reports back "Took a backup and read it back: 1.1 GB, 4 minutes ago." The owner's review note is explicit about why: "Taking a backup is not enough: the step reads it back."
What exists to build that on:
settings_service.BackupConfig(destination, retention count, rclone remote, include-audio), scheduled and on by default since #414, withPOST /api/admin/backup/run,GET /api/admin/backup/logsand abackup_logtable recording status, size and destination.backup_client_service(#429) already refuses to write a backup this server'spg_restorecould not read — its own docstring says "a backup nobody has restored is not a backup".So the step will read the archive back rather than restore it: after taking the backup it runs
pg_restore --listover the file it just produced and reports what it found — the archive is readable by this server's ownpg_restore, and how big it is and when. That catches the failures that actually happen in the wild (a truncated file, an unreadable archive, a version mismatch, a destination that silently wrote nothing) and it is honest about being a read rather than a restore, so the wording on the step will say "read it back", not "checked it restores".A real restore-into-a-scratch-database check is a worthwhile thing and belongs with the backup feature (#414's line of work), not inside a first-run wizard. If you would rather the step claim less, or rather it wait for the real thing, say so and I will change it — it is the last PR of the lane, so there is time.
Nothing else in the lane is blocked; PRs 1 and 3 are being built now.
🤖 Generated with Claude Code
A second departure to record before building, on
IS-253(the setup wizard's key step) — and some good news about the rest of PUB-8.The good news first
The seven steps are a path through endpoints the product already has, not a new settings system. Having gone through them one by one:
IS-251)IS-252)PUT /api/admin/backup/config,POST /api/admin/backup/run,GET /api/admin/backup/logsIS-253)GET /api/admin/settings/secrets-healthalready answers the questionIS-254)PUT /api/admin/settings/retentionIS-255)PUT /api/admin/settings/bot, thenPOST /api/admin/settings/whisper/testand.../llm/test— which are Instance health's own tests, as the surface header asked for, not a second setIS-256)PUT /api/admin/settings/bot,POST /api/admin/settings/bot/regenerate-key,GET /api/admin/settings/bot/pingregenerate-keyalready returns the key once and its docstring already says so — which is the drawing's "Made for you. Put it in the bot's environment; it is not shown again", word for word. The drawing got that one exactly right.So the only genuinely new server thing is the state: nothing today records that a server has been set up at all. One new instance setting (
setup_state— a key in the existing JSON store, so still no migration) holdingdone,skippedandcompleted_at, withGET /api/setup/state,POST /api/setup/steps/{step}andPOST /api/setup/finish. Re-doing a skipped step clears it from the list, because D70's list has to be able to empty.finishnever refuses over a skipped step — D70: it reminds, never blocks.The departure: the key step will show no key
The drawing shows
QB_SECRET_KEY=2f9c…a41ewith a Copy button. I do not think the build should, and I would rather say so than quietly draw it.GET /api/admin/settings/botstates the rule the whole settings layer follows — "Secrets are never returned — only presence flags" — andSECRET_KEYis the key every other secret is encrypted with, so it is the last one to make an exception for. It also buys the operator nothing: they putSECRET_KEYinto the server's environment themselves, so showing it back teaches them nothing and adds one more place it can leak from — a screenshot of the setup wizard, a support thread, a shoulder.What the step does instead is the thing the step is actually for, which is custody rather than disclosure:
SECRET_KEY, in this server's environment — and that a backup restored without it cannot read the bot token, the AI keys or the mail password, which is the sentence that matters and is the drawing's own;GET /api/admin/settings/secrets-health: how many encrypted settings are readable with it, and names any that are not. #428 and #430 built that endpoint for precisely this question, after a restore onto a host with a differentSECRET_KEYproduced a system that looked restored and was not;The generated
BOT_API_KEYon the Discord step is untouched by this — that one is made by the server, has to be shown once to be usable, and already is.Say the word if you would rather have the fingerprint shown as drawn and I will put it back; it is the last PR of the lane.
🤖 Generated with Claude Code
Departures on PUB-3, PUB-4 and PUB-5, recorded before the PR goes up (§7). Five small ones, and one thing that is not lane 2's but is being fixed here anyway.
The one worth your attention: every eyebrow in the app is the wrong case
Not a lane 2 departure — a lane 0 port error, found while building these pages and verified on both sides.
shared/looks.css:153in the prototype says it outright::root[data-look]is on in every prototype page, so every drawing you reviewed and signed off shows sentence case. Lane 0 portedkit.css's.labeland not the reset, so the app ships the thing that decision retired:AN INVITATIONwhere the drawing readsAn invitation. It is on the front door, sign in, Home, You and all five public pages — everything built so far.Three properties in one file, and restoring a decision rather than making one, so it is fixed in this PR rather than filed. Flagging it against #364 as well, since that is where it came from.
The five departures
SH-124— "13 sessions in six months" is not a number the server has.GET /public/analytics/{token}reportsaverage_gap_daysandsessions_last_30_days; the ledger row forSH-124says "sessions completed in the last 30 days". The drawn figures are also arithmetically impossible together — thirteen sessions at a thirteen-day gap is not six months — so I read "six months" as fiction rather than specification. The page keeps the drawn sentence's shape with the number the server actually reports: Every 13 days on average · 2 sessions in the last 30 days. If you want the drawn words, it needs a new server field — say so and I will add it.SH-088has no way onward. The ledger row says the request-sent state "explains the wait and links to the dashboard"; the drawing's banner has no action, and I built it as drawn. It is a real if small loss for a signed-in reader who has just asked to join and is now looking at a page with nowhere to go. Easy to add if you would rather have the ledger's version.SH-091is on the default state only, as drawn. The ledger says "shown on every state"; the drawing replaces it with "You will come straight back here afterwards" when signed out, and drops it while busy or failed. Drawing wins, difference noted.PUB-5 is not
pub--wide. The drawing passes it, but in a still the box is about 600px so it never shows; in a real windowpub--wideismax-width: noneinside a 1560px page — a guide set to a 1560px measure, which is unreadable prose. It uses the narrow card the other public pages use, which is also almost exactly the still's proportions. PUB-3 and PUB-4 keep their drawn widths.SH-122's wordmark is a link. The decision is that "the header's Quest Board link goes somewhere that exists"; the drawing's PUB-4 head is the shared non-link wordmark, so building it literally would leave the page with no door into Quest Board at all — worse for exactly the stranger the row is about. The wordmark is drawn as the wordmark and carrieshref="/". Not the crumb, which would swallow the "Campaign analytics" eyebrow over the campaign name.Two faults the render check caught, for the record
Tailwind's preflight strips the markers from every list, and the guides are the first pages in the redesign to render a list as prose — so a twenty-section guide drew its bullets with no bullets. And the Help index's guide cards sat an indent in from everything else, because
.pubhelp .glistloses to the frame's.qb .pub uland inherited a bullet list's padding. Neither is visible in the markup; both are obvious in a picture.🤖 Generated with Claude Code
A new catalogue row,
IS-438, and one small question for you at the end of it.The drawing's front door reads "Amberwake is run by Dana, for a few groups of friends." Nothing stored that last clause — the build found it by hard-coding it, which would have had every self-hosted Quest Board telling its visitors that its operator runs it for a few groups of friends. #752 made it a real field (
blurbonGET /public/site), written in About this server.IS-389names the four things About this server holds — the name, who runs it and how to reach them, the privacy policy's own words, and the numbers switch. This is a fifth. Without a row of its own, lane 9 builds that form fromIS-389and no real server ever gets a line on its front door.So, per §7's "the catalogue is kept live":
IS-438added toledger-IS.md, placed on ADMIN-15 (primary) and PUB-11, catalogue rebuilt — 1,707 rows — and every coverage script re-run, which is how the second surface turned up.The question
lane1c.pycounts it drawn on PUB-11: #751 draws that sentence both with the line and without it.lane7.pycounts it deferred on ADMIN-15, and that is the honest answer rather than a comfortable one. Lane 7's About this server form draws Its name, Run by, How to reach them and In your words — and has no field for this, because the row did not exist when that lane was drawn.I have deliberately not added it to the drawing. It would be one input in a form that already has four, and it follows directly from D62, so it is a small change — but lane 7 is a page you have already reviewed and signed off, and quietly editing a reviewed drawing is not a thing I should do on my own initiative.
So: would you rather the drawing gained the field now, or that lane 9 (#735) adds it when it builds that form? Either is fine and neither blocks lane 2; if you say nothing, lane 9 will find it as a deferred row in its own coverage script, which is the mechanism working as designed.
🤖 Generated with Claude Code
Lane 2's build is complete, and all four open questions are answered (owner, 2026-09-22).
The six PRs, all merged
/public/site,/public/policies, the invitation's two new fields,?next=widened, the Discord link pages restyled/, sign in, sign-in failedPlus two fixes this lane found in other people's work: #755 (a Home test asserting a countdown against the wall clock) and #757 (the journeys job's Compose project name, hard-coded, so two overlapping CI runs tore each other's stacks down).
The answers
IS-252— the backup step reads the archive back. Confirmed, and now D87.pg_restore --listover the file just written, reported as "read it back", claiming no more than it does. A real restore-into-a-scratch-database check belongs with the backup feature (#414), not a first-run wizard.IS-253— the key step shows no key material. Confirmed, and now D88.SECRET_KEYis the key the other secrets are encrypted with;secrets-healthanswers "is this the right key" by decrypting rather than by eye.SH-124— twelve months, and now D89. And a correction to what I told you: I said the drawing's figures were "arithmetically impossible together". They are not — thirteen sessions at a thirteen-day average gap spans about 169 days, which is roughly six months, so the drawn sentence is internally consistent. What was impossible was mapping it onto the endpoint'ssessions_last_30_days. That was a missing field, not a broken drawing, and the build took the lesser sentence when the drawing was right. Being corrected to twelve months rather than six: a year tells a reader about a campaign's rhythm and survives a table that plays fortnightly through a quiet summer. In progress onfix/owner-answers-code.IS-438— the drawing gains the field. Done: ADMIN-15's "About this server" now has What it is for, the line that finishes the front door's sentence, with its empty state on a fresh server. Rendered and read in both themes.lane7.pycounts it drawn rather than deferred, the catalogue is rebuilt, and all sixteen coverage scripts pass.Also settled from #759: the first-run redirect keeps both conditions (pristine setup state and nothing on Home), because pristine alone is equally true of every instance that predates the wizard and would have bounced a year-old server's administrator into "Setting up this server" on upgrade day.
SH-088gains the way onward the ledger asked for. And D90 writes down thepub--widerule for every later lane: a still's box is about 600px, a window's is 1560px, and prose at that measure is unreadable — so a page that is mostly words keeps the narrow card whatever the still passed.Against the acceptance list
lane1c.pyclassifies as drawn or replaced is built; the script passes with 110 placements and nothing unclassified./loginhaving been its last entry and this lane having rebuilt that page.vocabulary.js's throughout; no page-level error destroys rendered content; every async call shows progress and a next action; disabled controls say why.Left open only for your review on the dev server, per the rollout rule. Next in order is lane 3 (#729, the campaign core and Settings).
🤖 Generated with Claude Code
The owner's review of lane 2 on dev, 2026-09-25. Looks right: the front door, and the 404 and the waits.
The owner's notes:
Fixes in batch R1 (
fix/review-r1):#nnorDnnin any public page's visible text.Layout: "the pages are too narrow on high-res screens. Let's take advantage of screen space." Help: "The text column is too narrow… we should have a navigation section along the top." Both are part of the wide-screen mock-ups (revising D90). Help's top navigation is built in every option.
Signed off by the owner on the Redesign Review page, 2026-10-01 ("Much better after the pass, thank you."). The R3 re-check for this lane (setup going to Admin once finished) is marked OK. No changes asked for. Closing.