Skip to content

Draw the site page's notices, update card and setup checklist with the design system - #605

Merged
zaerl merged 3 commits into
redesign/wpdsfrom
update/color-tokens
Oct 3, 2026
Merged

zaerl merged 3 commits into
redesign/wpdsfrom
update/color-tokens

Conversation

@zaerl

@zaerl zaerl commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Why

Part of the redesign in #542, item 9 of #557: replace all hardcoded colours with tokens. What is left is about 190 hardcoded colours and 200 inline style blocks, too much to review in one go, so it comes as a short series. This is the first part.

What the site's page says above its cards was drawn by hand: each box with its own colours, padding and font size written into the markup. None of it could follow a theme, and each box was a little different from the next.

What changes

Everything above the cards is drawn by the design system, so that none of its CSS is written here. Tokens put into the same inline styles would have replaced the colours and kept the rest; components take all of it.

  • The notices are the design system's notice. A site the old engine made, a merge left half done, an update that did not finish, code that is old, an update that is done, a ticket handed over by a link, a folder that would not open. And what the ticket card says back: a refusal, a switch under way, edits carried or saved, the question about loose edits. Each keeps its words, its role, its buttons and what they do.
  • An update of trunk under way is a card with the list of steps the apply card has. That list is one component for both now, StepList.
  • The setup checklist is a card with a list of steps, each with a badge for how it stands and the button that does it. The prototype has no checklist; it is kept and redrawn.

In index.jsx this takes the hardcoded colours from 100 to 23 and the inline style blocks from 106 to 34. The 23 are the terminal, the logs and the mail.

What looks different:

  • A notice's title and what follows it are two lines, with the design system's icon. They were one run of text.
  • The checklist's rows are not tinted by state. A badge and a mark say it.
  • "Retry install & build" and the question's "Discard…" are not red. The design system's button has no destructive tone, and the other redrawn cards draw theirs the same way.

Not in this pull request:

  • The words. They are as they were, and still not translatable where they were not.
  • The rest of the series: the terminal, logs and mail panels and the page's leftover styles; the review dialog and its destinations, and the discard and email dialogs; and a lint rule that keeps hardcoded colours out of the renderer.

How to test this

Platforms: any. The change is in the renderer only.

The journeys walk these on both platforms. From the repository's root:

npm run build:once && npx playwright test --project=journeys site-page.spec legacy-site.spec merge-in-progress.spec trunk-update.spec trunk-update-watch.spec

site-page.spec.js is new: the checklist's steps, how each stands, its button and the way out; and the notice for old code, with its button and the next-action cue on it. The update journeys now read the update card as a region with a list and a current step, and dismiss the summary. Each claim was checked by breaking it: 21 breaks, all red.

What a journey cannot judge is how it looks. By hand, on the current head, on either platform:

Starting state: the app with no site.

  1. Create a site and leave it alone.
    • The page shows a card headed Initial setup checklist. A blue notice at its top says "Setting this site up for you — step N of 3" and has a Stop setup button.
    • Each step is a row: a mark, its name, a badge (Completed, In progress, Locked), a line about it, and its button. The step under way has a spinner, and its button can be read and cannot be pressed.
  2. When the setup has ended, click Start dev server and finish the wizard.
    • The checklist goes and the site's cards appear.
  3. Open the site's menu (⋮) and choose Update to latest trunk.
    • A card headed Updating to latest trunk says "step N of 3" and lists the steps, the current one with a spinner.
    • When it ends, a green notice says "Up to date with trunk as of today." Its ✕ sends it away.
  4. Edit a file of the site by hand, then link a ticket in Trac ticket.
    • A yellow notice under the field asks what should happen to the edit, with three buttons and Cancel.

What must not have happened:

  • Step 1's buttons were never pressable while their step ran, and the setup went on to the build by itself.
  • Step 4 moved nothing before a button was pressed: the edit is still in the file, and no branch was made.
  • No notice's buttons sit off to one side or leave a gap at its end.

Risks and limitations

  • Review: two passes by a separate context. 5 to fix here on the first, all fixed; 1 on the second, fixed. No behaviour was found lost. Details below.
  • Checked on macOS only, at the default size, in a 1024×728 window, and with the site's status read slowed by a second. Windows is CI's.
  • The manual steps above were not run by a person. I looked at screenshots of the checklist, the question about loose edits, and the old-engine notice.
  • A real setup was not run. The checklist under way (the blue notice, a step in progress, a failed step) is drawn from the same states as before and has no journey; tests/e2e/real-setup/create-site.spec.js runs one by hand and was not run.
  • Nothing is announced that was not before, and nothing less. Every notice is told to say nothing of its own: the ones that were alerts or status regions still are, by their role, and the static ones were silent.
  • The focus is lost when a notice with a focused button goes (Dismiss, Hide, Not now, Retry, Update), as it was before.
  • The next-action ring has a corner a little rounder than the notice or card it is on. Its rule is in the page's own stylesheet, which is the next part of this series.
  • The guide calls "Skip initialization wizard" a link; it is a button now. That is Retake all screenshots and update guide text #561.

Related

Part of #557. Part of #542. Follows #602.


Design decisions and alternatives considered
  • Components, not tokens in the old styles. The request was for as little hard-coded CSS as possible. A notice of the design system needs no CSS here at all; a box with token values would still carry its padding, radius, font size and layout in the markup.
  • The checklist loses its tints. Five states each had a background, a border, a text colour and an indicator colour: twenty values. A badge has the state's colour by its intent, and the mark is an icon. What is left in CSS is the row and the mark's size.
  • The checklist's buttons are not given the design system's loading state. It hides a button's words behind a spinner and says "Loading" to a screen reader. An install takes minutes, and the site it belongs to may not be the one on screen. The buttons are held while their step runs, as before; the step's mark spins and its badge says "In progress".
  • One step list. The update card and the apply card show the same thing, a plan with a current step, and were drawn twice.
  • A class on the page's notices, for now. The page's stylesheet gives every button a right margin, which the redrawn areas are each cleared of. That rule goes with the next part, and the list of exceptions with it.
  • A failed discard's reason is a line of text, not a notice. It follows a sentence inside the ticket card, where a notice inside a sentence would be too much.
Review outcome (required — see AGENTS.md)

5 [fix here] · 1 [follow-up] on the first pass, all 5 fixed. 1 [fix here] · 2 [follow-up] on the second, fixed, with one follow-up taken.

  • Review: completed — a separate agent context, against .github/instructions/code-review.instructions.md; head 495db32, base 4bee60f003b363548d4a3a697c33d6d120a6145e; it compared each removed block with what replaced it (conditions, handlers, refs, cue props, roles, text) and found none lost; it ran lint and the unit tests, not the journeys. Fixed:
    1. A journey looked for "Dependencies unchanged" on the whole page, which the terminal says too.
    2. A failed discard's reason ran on from the sentence before it.
    3. The checklist's buttons said a bare "Loading" and hid their words while a step ran.
    4. The page's notices' buttons had the page's older margin.
    5. The screenshots' crop of "Update incomplete" took the column.
    • Follow-up left: the guide's word for the skip button.
  • Second pass: completed — a separate agent context; head 3be3413, same base. No defect in the fix-up. Fixed: the question about loose edits is also drawn in the review dialog, where its buttons still had the margin. Taken: the update journey's look for the summary is by the summary's own sentence. Left as it is: the legacy journey's count of alerts can be answered as the page settles and would not catch one that came later; its comment says so now.
  • Since review: 3be3413 → 8c1512be3d5d2374b600a0549271fdf0b202d2d2: that class on one notice, one redundant prop removed, and two lines of journeys. Not reviewed again; every suite was run on it.

Checks on 8c1512be3d5d2374b600a0549271fdf0b202d2d2, macOS:

Check Result
npx eslint . --max-warnings=0 clean
npm test 1847 pass, 2 skipped
npm run test:electron 1848 pass, 1 skipped
npm run test:e2e 97 of 97
npm run test:e2e:packaged 15 of 15, on an unsigned build
Ten journey files in a 1024×728 window 31 of 31
Nine journey files with the status read slowed 28 of 28
Implementation notes
  • src/renderer/index.jsx: the boxes are Notice, Stack and Text; UPDATE_STEP_MARKS and checklistVisuals are gone; pageNotice(id) gives a page-level notice its class and, where it has one, its cue.
  • src/renderer/components/step-list.jsx (new): StepList, from the apply card's Progress.
  • src/renderer/components/trunk-update-card.jsx, setup-checklist.jsx (new).
  • src/renderer/setup-steps.cjs: setupStepBadge, with a unit test.
  • src/renderer/shell.css: .apply-step* is .step-list*; .setup-step*; .error-text. Every value is a token with its fallback.
  • scripts/screenshots/shots.cjs: two crops follow the new markup.
Screenshots or recording

Not attached: I have no way to upload an image from here. What the screenshots I took show:

  • The checklist: a card headed "Initial setup checklist"; each step a bordered row with a green tick, the step's name in bold with a green "Completed" badge beside it, a grey line under it, and an outlined button at the right ("Dependencies installed", "Build complete"); the last step ringed as the next thing to do, with a blue "Ready" badge and a solid blue button.
  • The question about loose edits: a yellow notice with an icon under the ticket field, the question, then three outlined buttons and a plain "Cancel".
  • A site the old engine made: a red notice with an icon at the top of the page, a bold first line, three lines under it and a blue "Create site" button; under the ticket field, a second red notice with the refusal.

🤖 Generated with Claude Code

zaerl and others added 3 commits October 3, 2026 16:39
…e design system

First part of replacing hardcoded colours with tokens (#557). What the
site's page says above its cards was drawn by hand, each box with its own
colours, padding and font size written into the markup. It is the design
system's now, so that none of it is written here:

- The notices are the design system's notice: a site the old engine made,
  a merge left half done, an update that did not finish, code that is old,
  an update that is done, a ticket handed over by a link, a folder that
  would not open, and what the ticket card says back (a refusal, a switch
  under way, edits carried or saved, the question about loose edits).
  Each keeps its role, its words and its buttons.
- An update of trunk under way is a card with the list of steps the apply
  card has, now one component for both.
- The setup checklist is a card with a list of steps, each with a badge
  for how it stands and the button that does it.

What is left in the page's own markup is the terminal, the logs and the
mail, which move to the tray (#558), and the dialogs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…lear of the old button rule

The checklist's buttons were given the design system's loading state, which
hides a button's words behind a spinner and says a bare "Loading" to a
screen reader, for an install that takes minutes and for a site that may
not be on screen. They are held while their step runs, as before, and say
what they did; the step's own mark and badge say it is under way.

The notices above the cards sit where the page's older rule gives every
button a margin, which moved their buttons and their close button. They
are clear of it. A failed discard's reason is on a line of its own again,
under the sentence it follows.

The update journey read "Dependencies unchanged" off the whole page, which
the terminal says too. The screenshots' crop of "Update incomplete" took
the column and not the notice.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he review dialog too

The question is drawn in the ticket card and also in the review dialog,
which the card's own rule does not reach: its buttons had the page's older
margin there. It carries the page's notices' class.

The update journey's look for the summary is by the summary's own
sentence, as its look for the summary being gone already was.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: WordPress/contributor-toolkit/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2b9441a1-f142-4b53-88d3-330c3750660d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@zaerl
zaerl merged commit daefeb3 into redesign/wpds Oct 3, 2026
11 of 12 checks passed
@zaerl
zaerl deleted the update/color-tokens branch October 3, 2026 15:30
zaerl added a commit that referenced this pull request Oct 3, 2026
…d empty the page's own stylesheet (#606)

## Why

Part of the redesign in #542, item 9 of #557: replace all hardcoded
colours with tokens. This is the second part of the series; #605 was the
first.

The terminal, the logs and the mail under a site's cards were black
panes and grey text written into the markup, and the page still had a
stylesheet of its own in `index.html`, with a rule that gave every
button in the window a margin, which each redrawn area then had to be
cleared of.

## What changes

**The terminal and the log panes are light**, as the prototype's tray
has them: the design system's weak surface with dark monospace text.
That was decided before building. The design system has no token for a
dark surface in a light theme, so staying dark would have meant keeping
colours of our own.

- **The terminal draws itself and takes its colours and font as
values**, so they are read off the tokens where it stands when it is
made. Which token each colour is, is `terminal-theme.cjs`'s, with unit
tests.
- The sixteen colours a command can ask for by number are the design
system's nearest: red is what an error is said in, green a success,
yellow a warning.
- The bright eight are the plain eight. The design system's stronger
colours are for text on a tinted notice and are all but black here.
- A selection is the strong brand surface, with the text colour the
design system has for it.
- Text a command prints on a background of its own is moved until it can
be read (the terminal's minimum-contrast option, at 4.5).
- **A log line is coloured by its kind** in the stylesheet: an error, a
warning, a deprecation or notice, each in the design system's colour for
it.
- **The three panels are regions named by their headings.** Their
buttons are the design system's; a command named under the terminal is
its link, made of a button.
- **The window's own cards** (the Playground web server, a setup in
flight) are the design system's card.

**The page's own stylesheet is gone from `index.html`.**

- What was still used moved to `shell.css`, with tokens: the next-action
ring and the review dialog's two columns.
- What was not used is deleted: five rules for markup that no longer
exists.
- **The margin it gave every button** is the older library's dialogs'
alone now. The list of redrawn areas cleared of it, sixteen selectors
long, is gone with it.

`index.jsx` has no colour and no inline style left. It began this item
with 100 and 106.

Not in this pull request:

- **The words**, which are as they were.
- **The panels' layout.** They move to the tray in #558; here they keep
their place and their shape.
- **The rest of the series:** the review dialog and its destinations,
the diff panes, the discard and email dialogs; and a lint rule that
keeps hardcoded colours out.

## How to test this

Platforms: any. The change is in the renderer only.

The journeys walk the three panels on both platforms. From the
repository's root:

```bash
npm run build:once && npx playwright test --project=journeys terminal.spec logs.spec mail.spec
```

They now also say: each panel is a region named by its heading, in their
order; the terminal's surface and text are the tokens' colours, read
where the terminal paints them; red printed in bold and in plain is the
error colour; text on a background of its own can be read; a log pane is
the same surface; a warning and a notice in `debug.log` have their
colours; a command link is in the terminal's type. Each claim was
checked by breaking it: 29 breaks, all red.

What a journey cannot judge is how it looks. By hand, on the current
head, on either platform:

**Starting state:** a site that is set up, with the dev server running.

1. Scroll to **Terminal**.
- A pale grey pane with dark monospace text, and no dark surface
anywhere on the page.
2. Type `npm run build` and press Enter.
- The build's output is readable throughout. Anything it prints in
colour (warnings in yellow, errors in red) can be told from the text
around it.
3. Drag across a few lines of the output.
   - The selection is a solid blue with light text on it.
4. Under the terminal, with nothing running, click **npm install** in
the hint.
- It is in monospace, and it types `npm install` at the prompt without
running it.
5. Scroll to **Logs** and open **debug.log** after loading a page of the
site that logs a PHP warning.
- The pane is the same pale surface; the warning's line is in the
warning colour, a stack trace under it in grey.
6. Send a mail from the site (a password reset) and look at **Mail**.
- A framed list with one row: when, from whom, and the subject in bold.
The row highlights under the pointer and opens the mail.
7. Open **Review & submit changes**.
   - The dialog looks as it did: its buttons are spaced as before.

**What must not have happened:**

- No text in the terminal is unreadable: nothing white on the pale
surface, nothing dark on a dark background.
- The terminal's columns line up: the help's two columns are straight,
and no line is cut in half.
- Buttons elsewhere on the page have not moved together or apart: the
log tabs, the feedback popover, the header.

## Risks and limitations

- **Review:** two passes by a separate context. 5 to fix here on the
first, 3 on the second, all fixed. Two of the first pass's were real
readability problems of the light terminal; details below.
- **Checked on macOS only**, at the default size, in a 1024×728 window,
and with the site's status read slowed by a second. Windows is CI's. The
terminal's font is the tokens' list (Menlo, Consolas, monaco), which on
Windows is Consolas, as before.
- **The manual steps above were not run by a person.** I looked at
screenshots of the three panels, of coloured output with a selection,
and of the review dialog. Real `npm` output was not looked at: the
journeys print stand-in lines.
- **The terminal reads its colours once, when it is made.** It will not
follow a change of theme until it is made again. That matters with dark
mode, #560.
- **Two things a command can ask for are less readable than on the dark
terminal**, both from how the terminal itself works:
- Reversed text with no colours given (`ESC[7m`) is mid-grey on dark,
about 4.8:1 where it was 15:1. The contrast option stops raising it once
it reaches its ratio.
- Dim text is drawn at half strength after the contrast check, so dim
grey is about 2:1.
- Both are rare here: a command's output is piped and nothing forces
colour.
- **Removing the page's button margin moved old-library buttons outside
dialogs 8px closer**: the log tabs, the feedback popover's, the links in
the changes note. I looked at the log tabs and the note; they read
better for it.
- **The next-action ring is the design system's warning stroke**, a
paler amber than the one it had, at the cards' radius.
- **A dark-on-light terminal is a change of habit** for anyone used to
the black one. It is the prototype's, and it follows the theme.

## Related

Part of #557. Part of #542. Follows #605.

---

<details>
<summary>Design decisions and alternatives considered</summary>

- **Light, not dark with a few colours of our own.** Asked and decided
before building. Dark panes would have kept a set of hardcoded values
and would not follow a theme.
- **The terminal's colours are resolved, not passed as `var(…)`.** The
terminal parses colours itself and paints them into its own stylesheet
and cells. Each token is given to a hidden element and read back, and
written through a canvas as `#rrggbb`, which is the one form every part
of the terminal takes.
- **Tokens are written as `var(--wpds-…)` in the module**, which is how
the repository's lint rule finds a token, and how the build can give one
its fallback.
- **Bright is plain.** The alternative, the design system's stronger
colours, made a bold red error indistinguishable from the text around
it.
- **The selection has its own text colour.** Without it the text on a
selection is readable only because of the contrast option, which is a
dependence nobody would see.
- **Regions with headings**, like the cards above them. It also makes
the journeys' way to a panel the same for all of them, where the old
markup was found by its shape.
- **The margin stays for `.components-modal__frame
.components-button`.** The older library's dialogs are redrawn in the
next part; until then their buttons are spaced as they were. The design
system's buttons inside them are not touched by it.
- **`hidden` in place of an inline `display`** on a site's view that is
not on screen. Nothing sets a `display` on that element that would undo
it.

</details>

<details>
<summary>Review outcome (required — see AGENTS.md)</summary>

5 [fix here] · 2 [follow-up] on the first pass, all 5 fixed and both
follow-ups taken. 3 [fix here] · 2 [follow-up] on the second, all 3
fixed.

- **Review:** completed — a separate agent context, against
`.github/instructions/code-review.instructions.md`; on the change before
it was committed (staged over
`daefeb35a613478f38452221c0b197983cf044c7`; it became `3eaa3d3`); it
read the diff, the terminal library's source and the removed stylesheet
rule by rule, and ran lint and the unit tests, not the journeys. Fixed:
  1. A selection in the terminal could not be seen.
2. Bold coloured output was all but black, and text on a coloured
background could vanish.
  3. The window's own cards had lost the room under them.
  4. A command link under the terminal had lost its monospace.
5. A new journey file cost an app launch on every pull request for what
three existing journeys could say.
- Follow-ups taken: a rule for the review dialog's title that had never
matched; a check in a hook the unit tests cannot reach, moved to the
module.
- **Second pass:** completed — a separate agent context; head `30779e9`,
same base. Fixed:
1. My reason for the selection's colour was wrong (this terminal paints
it solid), and its text was readable only through the contrast option.
It has its own text colour.
2. The mail journey says the panels' order, which the folded journey had
said.
  3. A margin doubled under the last of the window's notices.
  - Left, and in Risks: reversed text and dim text.
- **Since review:** `30779e9` →
`2df2d559812fb776d7ee569a1d49a864df524325`: those three. Not reviewed
again; every suite was run on it.

Checks on `2df2d559812fb776d7ee569a1d49a864df524325`, macOS:

| Check | Result |
|---|---|
| `npx eslint . --max-warnings=0` | clean |
| `npm test` | 1861 pass, 2 skipped |
| `npm run test:electron` | 1862 pass, 1 skipped |
| `npm run test:e2e` | 97 of 97 |
| `npm run test:e2e:packaged` | 15 of 15, on an unsigned build |
| Nine journey files in a 1024×728 window | 24 of 24 |
| Nine journey files with the status read slowed | 24 of 24 |

</details>

<details>
<summary>Implementation notes</summary>

- `src/renderer/terminal-theme.cjs` (new): `TERMINAL_COLOR_TOKENS`,
`terminalTheme`, `terminalFont`, `tokenName`, `TERMINAL_READABILITY`.
- `src/renderer/hooks/use-site-terminal.jsx`: `readTerminalLook`;
`TERMINAL_FONT` is gone.
- `src/renderer/index.jsx`: the three panels and the window's cards;
`LOG_PANE_STYLE` and `pageNotice` are gone.
- `src/renderer/components/log-text.jsx`, `terminal-command-link.jsx`:
classes and the design system's link.
- `src/renderer/index.html`: no `<style>`. `src/renderer/shell.css`: the
panes, the log lines, the mail list, the ring, the review dialog's
columns.
- `src/renderer/components/review-dialog.jsx`: a prop the older
library's modal ignores is removed.
- The terminal draws a row again as more is printed, so the journey's
reads of a printed word are asked until they are so, both colours off
the same row.

</details>

<details>
<summary>Screenshots or recording</summary>

Not attached: I have no way to upload an image from here. What the
screenshots I took show:

- **The terminal:** a pale grey pane with dark monospace text, the
help's two columns aligned, three grey lines of hints under it with the
two commands as blue links.
- **Coloured output:** red, green, yellow, blue, magenta and cyan words,
each readable, bold ones in the same colours; words on red, green,
yellow, blue and dark backgrounds in light text; a selection across one
line in solid blue with light text.
- **Logs and mail:** three tabs over a pale pane; a framed mail list
saying "No emails yet." with an outlined **Clear emails** button above
it.
- **The review dialog:** as before.

</details>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
zaerl added a commit that referenced this pull request Oct 4, 2026
… no window (#607)

## Why

On the macOS runner a journey's launch sometimes gives the test no
window: `electronApplication.firstWindow: Timeout 30000ms exceeded while
waiting for event "window"`. The test passes on Playwright's retry and
is reported as flaky, but the job still fails a minute later on `Worker
teardown timeout of 60000ms exceeded` and "1 error was not a part of any
test". It happened on two pull requests in a row on 3 October (runs
[37132158563](https://github.com/WordPress/contributor-toolkit/actions/runs/37132158563)
and
[37148706799](https://github.com/WordPress/contributor-toolkit/actions/runs/37148706799)),
in a different test each time, and both went green on a re-run.

## What changes

**Root cause of the failed run:** the app from the launch that gave no
window was still running when the worker stopped. `Session.close()` gave
it five seconds and then called `proc.kill()`. On macOS that is SIGTERM,
which a main process that has stopped answering survives. When the
worker stops, Playwright asks every process it launched to close and
waits for its exit with no limit of its own, so the runner's 60-second
teardown limit is what ended it, as a failure.

- `close()` now ends the app by force once it has had its five seconds:
the process group on macOS and Linux, the process tree on Windows (where
the launched process is a shell and the app is its child). It then waits
for the exit, with a limit.
- A launch that gives no window now puts what the main process said of
itself in the error: whether Electron became ready, and each window with
its address and whether its page was loading or had crashed. An app that
could not be reached, and one that gave no answer in five seconds, each
say so in their own words.

**Not in this change:** why the launch gives no window. That is not
established. The trace shows the app started in 0.6 s, its main process
answered once, no window event arrived in 30 s, and the app then would
not quit. The new error text is there so the next occurrence says which
state the app was in. There is also no retry of the launch inside the
helper: with the teardown fixed, Playwright's own retry in CI is enough,
and a retry in the helper would hide the thing still to be found.

## How to test this

Platforms: any. No user-visible surface; this is the journeys' engine
(`tests/e2e/helpers/app.cjs`), and nothing under `src/` changes.

From the repository root, after `npm ci` and `npm run build:once`:

```
npx playwright test --project=journeys engine.spec
```

- `closing ends an app that has stopped answering` makes the main
process busy for good and asserts the app is gone after `close()`. **It
is red without the change**: with `proc.kill()` put back in `close()`
the app survives, the assertion fails, and the run ends on "1 error was
not a part of any test" about a minute later, which is the failure the
macOS runner showed. I checked that on macOS.
- `the main process says what a launch came to` reads the state the
launch error reports, on a launch that worked.

**What must not have happened:** no `Electron --inspect=0` process left
behind after the run (`pgrep -fl "Electron --inspect=0"` prints nothing
on macOS), and no journey slower or failing because its app was killed
while quitting normally. All 59 journeys pass locally on macOS.

**What cannot be tested by hand:** a launch that gives no window cannot
be staged without a hook in the app. I checked the error text once by
hand for each of its three outcomes (state read, app gone, app not
answering), with the helper edited for the run and restored. The Windows
branch of the forced kill (`taskkill /T /F`) is exercised only by CI,
through the first test above.

## Risks and limitations

- Review: 2 passes, 8 findings fixed here, 1 not applied, 1 follow-up.
Details below.
- An app that is quitting normally but takes more than five seconds is
now ended mid-quit, where SIGTERM used to let it finish; a child it
started in a process group of its own would then be left behind. No
journey quits that slowly today.
- Not applied: if the main process exits and one of Chromium's helpers
keeps its output pipe open, `close()` returns without killing anything
and Playwright could still wait at teardown. Nothing has shown this
happening, so there is no branch for it.
- The second new test pins the state reader, not the error path it
exists for.
- The packaged smoke was not run: it does not use this helper.

## Related

Seen on #605 and
#606. Once merged,
this goes into `redesign/wpds` with a merge commit; the launch code
differs there, so the merge needs a hand.

---

<details>
<summary>Design decisions and alternatives considered</summary>

- **Force after the limit, not SIGTERM first.** By the limit the app has
already been asked to quit through `app.quit()`. A second polite request
is what did not work.
- **Process group and process tree.** Playwright starts the app detached
on macOS and Linux, so the group is the app and its helpers. On Windows
it launches through a shell, so the pid is `cmd.exe`'s and `/T` is what
reaches the app. `proc.kill()` is avoided on purpose: it marks the
process as killed whether or not it went, and Playwright skips its own
last forced kill, at worker exit, for a process marked that way.
- **Evidence in the error, not as an attachment.** The CI log is where a
flaky test is read; the error is in it, an attachment is in an artifact.
- **No shorter wait for the window.** 30 s for the window, 5 s for the
state and up to 10 s in `close()` fit the 60 s test timeout, and
teardown after a failure has a budget of its own.

</details>

<details>
<summary>Review outcome (required — see AGENTS.md)</summary>

**Pass 1: 5 [fix here] · 1 [follow-up]. Pass 2 (on the fix-up): 4 [fix
here]. 8 fixed, 1 not applied, 1 follow-up.**

- **Review:** completed — a separate agent context, read-only; head
`c70587d` / base `522b6ea`; read the diff against Playwright 1.63's
launcher and worker teardown; 5 [fix here], 1 [follow-up].
- Fixed: the comment gave the wrong reason for the hang (it is
Playwright waiting for the exit; the killed mark only matters at its
last forced kill); "did not answer" covered an app that had died as well
as one that was stuck; the comment did not say a slow normal quit is now
cut off; the test polled where its invariant said "by the time `close()`
returns".
- Not applied: the pipe-held-open path in Risks, which nothing has
demonstrated.
  - Follow-up: the second test does not reach the error path.
- **Review:** completed — a second separate agent context, read-only;
head `bc15afb` / base `522b6ea`; 4 [fix here], all fixed.
- The direct assertion from pass 1 could be red on Windows with nothing
wrong, because `close()` waits there for the shell and the app can be a
moment behind it: the poll is back and the comment says why.
- The launch error could lose the original error on a rejection that is
not an `Error`, and one of its three sentences had no full stop.
- `TESTING.md` said "did not answer" means stuck; it now says most
likely.
- The forced kill's comment said SIGTERM for both platforms and
understated what a kill at the limit leaves behind.
- **Since review:** `bc15afb → a450f63` is the second pass's fixes only;
engine spec and all 59 journeys re-run on `a450f63`, lint clean.

</details>

<details>
<summary>Implementation notes</summary>

- Timeline of the failed launch in run 37148706799, from its trace:
launch 637 ms, a main-process `evaluate` answered in 4 ms, `firstWindow`
timed out at 30 s, "Close context" never returned, the fixture gave up
after 5 s, and the worker teardown then waited 60 s.
- Playwright 1.63: worker teardown calls `gracefullyCloseAll()`, which
calls the app's `close()`, which awaits the browser context's close
promise; that resolves only when the process exits.
- Local checks on macOS: lint clean, `npm test` 1733 pass, `npm run
test:e2e` 59 pass.

</details>

Nothing on screen changes, so there are no screenshots.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
zaerl added a commit that referenced this pull request Oct 4, 2026
…kens (#608)

## Why

Item 9 of #557 is to replace every hardcoded colour with the design
system's tokens, with as little hand-written CSS as possible. Parts 1
and 2 did the site page and its panels. What was left was inside the
three dialogs still built on the older library: "Review & submit
changes" with its diff and its three destinations, the "Update to latest
trunk?" question, and the mail dialog. Between them they held 95 inline
`style` attributes and 87 colour values, including a dark diff pane and
a dark raw-mail pane that no longer matched the light terminal and logs.

## What changes

The three dialogs keep their frames, buttons and inputs from
`@wordpress/components`. Everything drawn by hand inside them is now the
design system's.

- **The diff** is on the strong surface inside a hairline, and each kind
of line (added, removed, hunk, file name, the app's own header) is a
class painted with tokens, as the prototype has them. **The raw mail**
is on the surface the logs and terminal are on.
- **Boxes that warned, failed or informed** are `Notice`s: the old-trunk
warning, the unreadable diff, nothing to send, someone else's work in
the checkout, the branch based on today's trunk, the update question's
failure, and test mode.
- **Lines that say how something went** are `Text` in one of three
shared classes, `success-text`, `warning-text` and `problem-text`. These
also replace the apply card's and the details sidebar's own copies, and
`.error-text` from part 1 now uses the same red (its token gave a
near-black `#470000`).
- **Destinations** are stacks and text inside a card per group. The
update question's two answers, its file list and the mail's panes are
classes in `shell.css`.
- The rule that gave every button in an older dialog a right margin is
gone; the layouts use gaps.

After this, no inline `style` and no colour value is left in any
component under `src/renderer`.

**Deliberately not in this PR:**

- Turning these dialogs into the design system's `Dialog`, or the review
into the prototype's three-column drawer with a file list. That is a
redesign of the screen, not colour work, and is not listed in #557.
- The three discards that still ask through `window.confirm`.
- The lint rule that forbids a hardcoded colour in the renderer. That is
part 4.
- Mail HTML rendering is unchanged and tracked separately.

## How to test this

Platforms: any. The journeys below drive each dialog on macOS and
Windows and assert the colours against the tokens, read from the window
itself. From the repository root, after `npm ci` and `npm run
build:once`:

```
npx playwright test --project=journeys review-changes.spec trunk-update.spec mail.spec open-pull-request.spec
```

Each new assertion is red without the style it claims; I broke the rules
one at a time to check (10 mutations, 10 red):

- `review-changes.spec.js`: an added and a removed line are in the
success and error colours on their washes; a failed save is in the error
colour and a saved file's line in the success colour.
- `trunk-update.spec.js`: the chosen answer is ringed in the brand
colour and the other is not, the ring moves with the choice, the chosen
answer's detail is in the full text colour, and the answer that loses
work stays red, chosen or not.
- `mail.spec.js`: the raw mail is on the weak surface.

**Worth a look by hand, since no journey judges taste** (any platform,
the current head):

1. On a site with an edit, press **Review & submit changes**. The diff
is light, with green added and red removed lines on a tint; the
destinations are two cards.
2. From the site's menu choose **Update to latest trunk** with an edit
in the tree. The chosen answer is ringed in blue; choosing **Discard
them** moves the ring and keeps that answer red.
3. Start the dev server on a site that has sent mail, open a mail, and
press **Raw**. The pane is light.

**What must not have happened:** no wording, role or accessible name
changed (the existing journeys find everything by role and text and pass
unchanged, all 99), and nothing outside these dialogs moved except the
two colour classes named above.

**What cannot be tested by hand here:** the GitHub device code and a
real pull request result need a GitHub sign-in; the journeys stand in
for GitHub and cover both states.

## Risks and limitations

- Review: 2 passes, 6 findings fixed here, 2 accepted as they are.
Details below.
- **Contrast is lower than the dark pane's, though every pair passes
4.5:1.** Added lines are 4.86:1 and hunk lines 4.50:1, where the dark
pane had about 9.7:1. These are the prototype's tokens for a diff.
- **Visible changes beyond colour:** destination cards have the design
system's 24px padding (was 14/16px); titles are the design system's
medium heading; the GitHub device code is 20px (was 24px); test mode is
a neutral notice and not a dashed box; the mail dialog's two tabs sit
flush, which is the library's default; a stand-alone link in a
destination is clickable on its words only, not across the column.
- The error under the site page's changes note turns from near-black to
red, with `.error-text`.
- Accepted, not fixed: no journey checks the 12px size of the four
stand-alone links.
- The strings in these components are still not translatable. That was
so before, and is not changed here.

## Related

Part of #557, after
#605 and
#606.

---

<details>
<summary>Design decisions and alternatives considered</summary>

- **Frames and controls stay the older library's.** A dialog half in
each library's buttons would look worse than either, and the frame is
what a later redesign of the review replaces.
- **`Notice` with nothing spoken.** The design system's notice speaks
its text when it mounts. Each one here either carries `role="alert"`, as
the box it replaces did, or was silent before and stays so; none is
announced twice.
- **`Text` renders a span.** Every one is a flex or grid item, or is
given a block element, so no line runs into the next.
- **Shared classes for text colour** and not one per card: three classes
replace six rules that said the same thing.
- **The pressed answer's ring is drawn inside its border**, so choosing
does not move the other answer by a pixel, as the old 2px border did.

</details>

<details>
<summary>Review outcome (required — see AGENTS.md)</summary>

**Pass 1: 4 [fix here] · 2 [follow-up]. Pass 2 (on the fix-up): 2 [fix
here], both low. 6 fixed, 2 accepted.**

- **Review:** completed — a separate agent context, read-only; head
`50129cd` (rebased since, as `369cf6e`) / base `9570450`; compared each
component with its old version, read `Notice`'s implementation, computed
contrast for every new pair; 4 [fix here], 2 [follow-up].
- Fixed: the chosen answer's detail text was 4.34:1 on its tint (now the
full text colour, 14.6:1); four stand-alone links had grown from 12px to
13px; the mail journey's text-colour check passed without the rule it
was for.
- Fixed though marked follow-up: the test helper `tokenColour` could not
notice a misspelled token (it now refuses one the window does not have);
`.error-text` painted the same error in a different red.
- Accepted: the mail dialog's tabs sitting flush, the library's default.
- **Review:** completed — a second separate agent context, read-only;
head `86555dd` / base `23d46e7`; 2 [fix here], both low.
- Fixed: nothing pinned the losing answer's detail staying red once
chosen, which holds on source order alone; a journey now asserts it.
  - Accepted: no journey checks the links' size.
- **Since review:** `86555dd → 1460d81` adds that one assertion;
`trunk-update.spec` re-run, and red with the two rules swapped.

</details>

<details>
<summary>Implementation notes</summary>

- The branch was rebased once, before it was pushed, onto
`redesign/wpds` after trunk's journey-engine fix
(#607) was merged
into it.
- `ui.tokenColour` and `ui.paintOf` are new shared helpers in
`tests/e2e/helpers/ui.cjs`; `logs.spec.js` and `terminal.spec.js` use
the first in place of their own copies.
- Local checks on macOS: lint clean, `npm test` and `npm run
test:electron` pass (1863 tests), `npm run test:e2e` 99 pass, the
affected journeys pass in a 1024×728 window and with the status read
slowed by a second, `npm run test:e2e:packaged` 15 pass.

</details>

<details>
<summary>Screenshots or recording</summary>

Not attached: I have no way to upload images from the command line. The
three steps under "Worth a look by hand" show every changed surface, and
Buildkite's build for this branch can be used for them.

</details>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
zaerl added a commit that referenced this pull request Oct 4, 2026
…r's components (#609)

## Why

Parts 1 to 3 of item 9 in #557 left no colour value and no inline
`style` in any component under `src/renderer`: the window is painted
from classes in `src/renderer/shell.css` with the design system's
tokens. Nothing stopped one coming back. A colour typed into a component
is one the theme cannot reach, and `TESTING.md` rules out the only other
check, a test that reads a component's source.

## What changes

Two lint rules of this repository's own, switched on for
`src/renderer/**/*.{js,jsx,cjs}`:

- **`toolkit/no-hardcoded-colors`** reports a colour written out in a
string or in the fixed part of a template: a hex value of 3, 4, 6 or 8
digits, or a function that takes a colour's channels (`rgb()`, `hsl()`,
`oklch()`, `color()` and the like). A token wrapped in `var()` passes,
and so does `color-mix()` of tokens.
- **`toolkit/no-inline-styles`** reports a `style` attribute on a JSX
element.

They live in `eslint-rules/`, registered as a local plugin in
`eslint.config.mjs`. No new dependency: the rules are plain modules,
tested with ESLint's own `RuleTester`.

**Not in this PR:**

- **The stylesheet.** `shell.css` is not checked by these rules, and it
is where all the styling now is. That is the next pull request:
Stylelint with the design system's own rules.
- A colour's name (`red`, `white`), a colour put together from pieces, a
`style` passed in a spread or set from an effect. Each rule's header
says what it does not read. None of these exists in the renderer today.
- `src/main.js`, whose patch window still carries a few inline colours.
It is not the renderer.

## How to test this

Platforms: any. No user-visible surface; this is lint and its tests.
From the repository root, after `npm ci`:

```
npm run lint
node --test tests/unit/eslint-rules.test.cjs
```

Both pass. To see the rules bite, add `style={{ borderColor: "#dcdcde"
}}` to any element in `src/renderer/components/destination.jsx` and run
`npx eslint src/renderer`: it reports the inline style and the colour. I
did that, and the same with an `rgb()` in
`src/renderer/terminal-theme.cjs`.

`tests/unit/eslint-rules.test.cjs` runs each rule over code that must
pass and code that must not. I removed each guard in the two patterns in
turn (the lookbehinds, the lookahead, the case flag, the string-only
check, reading a template as the program gets it, `color()` in the list)
and the suite went red every time.

**What must not have happened:** the rules must not fire on anything in
the tree as it is (`npm run lint` is clean with no disable comment
added), and `eslint-rules/` must not be packaged into the app
(`build.files` in `package.json` does not include it).

## Risks and limitations

- Review: 2 passes, 9 findings fixed here, 1 kept as it is. Details
below.
- **A reference of three or four digits written out in a string reads as
a colour**: `'Fixed in #607'` is reported, because `#607` is a grey and
`#000` must not pass. Nothing in the tree does this; the renderer builds
such strings from the number (`#%d`, `#${ n }`), and the message says
so. A fragment made only of hex letters, `'#add'`, is reported too
unless it follows a word or a slash.
- Kept: these could have been three selectors given to the core rule
`no-restricted-syntax`, with no rule files. They are rules of their own
because the colour rule's message names what it found and the patterns
are tested by themselves.

## Related

Part of #557, after
#605,
#606 and
#608.

---

<details>
<summary>Review outcome (required — see AGENTS.md)</summary>

**Pass 1: 5 [fix here] · 1 [follow-up]. Pass 2 (on the fix-up): 4 [fix
here]. 9 fixed, 1 kept.**

- **Review:** completed — a separate agent context, read-only; head
`e8903a2` / base `5b7e1fb`; ran the test file on Node and on Electron's
Node, eslint over the renderer, and probed both rules with throwaway
code; 5 [fix here], 1 [follow-up].
- Fixed: a test that passed without the guard it named; the header
claiming a written-out reference could not be flagged; a fragment after
a slash being flagged; four wordings that claimed more than the code
does (the `TESTING.md` sentence, both messages, the rule's description).
- Fixed though marked follow-up: tests for uppercase hex, hex after `:`
and `(`, a template that cannot be read, a namespaced attribute.
- Kept: custom rules over `no-restricted-syntax`, with the reason now in
each header.
- **Review:** completed — a second separate agent context, read-only;
head `022aebf` / base `5b7e1fb`; removed each guard in memory and re-ran
the suite; 4 [fix here], all fixed.
- Three guards could be removed with the suite still green; two now have
a test, and the third decided nothing and is gone.
  - Two comments named the wrong case as pinning the string-only check.
- `color()` and `device-cmyk()` were missing from the functions the rule
reads.
  - One of the two reasons given for a custom style rule did not hold.
- **Since review:** `022aebf → b9bc2e2` is those four fixes only; the
test file, `npm test`, `npm run test:electron` and `npm run lint` re-run
on it.

</details>

<details>
<summary>Implementation notes</summary>

- The preset from `@wordpress/eslint-plugin` does not configure
`no-restricted-syntax`, so nothing is overridden either way.
- `RuleTester` is given `node:test`'s `describe` and `it`, so a failing
case fails `npm test`; checked with a deliberately wrong case.
- The journeys and the packaged smoke were not run: nothing under `src/`
or `tests/e2e/` changes.

</details>

Nothing on screen changes, so there are no screenshots.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
zaerl added a commit that referenced this pull request Oct 5, 2026
## Why

#542 replaces the app's interface with the one in the
[prototype](https://github.com/jameskoster/wordpress-contributor-toolkit-prototype),
drawn with the WordPress Design System. It was built in slices on
`redesign/wpds`, so that trunk, which releases are cut from, never held
a half-redesigned window. The window is whole now: the shell, the page
header and details, every card and dialog, and the tray. This pull
request is how the branch reaches trunk.

It lands before the last three sub-issues, on purpose. The settings
dialog (#559) and dark mode (#560) add to a finished window and do not
need a branch to hide in, and the guide (#561) is easier to rewrite
against what is on trunk. They follow as pull requests against trunk.

## What changes

Everything `redesign/wpds` holds; this pull request adds nothing of its
own. Each slice was reviewed in its own pull request against that
branch, and says there how to test it and what it leaves out.

- **The shell** (#555): a sites list, the page area and a footer, in a
larger window. #590
- **The page header and the details** (#556): the site's menu in the
header, and what the checkout is in a sidebar that can be put away.
#594
- **The site's page** (#557): the server and the build watch in the
header and the details
(#595); the ticket
card, the apply card with a preview dialog, and the list of a site's
tickets (#596,
#597,
#599); the
create-site, rename and delete dialogs
(#600,
#601);
confirmations as notices in the window's corner
(#602); the page's
notices, update card and setup checklist
(#605); the
terminal, logs, mail and the review dialogs painted with the design
system's tokens
(#606,
#608); and lint
rules that keep it so
(#609,
#610).
- **The tray** (#558): along the bottom of the window, holding the
terminal, the logs or the mail, with a count of unseen debug.log lines
on the footer
(#612,
#613,
#614,
#615).
- Along the way:
#611 (the site
menu's update item says why it is held), and three that tidy up before
landing: #616 (a
journey's race with the page's clock),
#617 (comments the
finished redesign made untrue) and
#618 (the server's
button by its present name in `AGENTS.md`).

**What a contributor will notice first:** the terminal, the logs and the
mail are no longer on the page but behind three buttons at the foot of
the window; the terminal is dark text on light; the server and the build
watch are started from the header; a patch is previewed in a dialog
before it is applied; and what worked is said in the window's corner.

**Not in this pull request:**

- The settings dialog (#559). Until it, nothing about how the window is
arranged is remembered across restarts: the details, the tray's height,
the apply card's fold.
- Dark mode (#560). The terminal reads its colours once, when it is
made, and will need to follow the theme.
- The user guide and its screenshots (#561), which describe the old
interface. They are published from release tags, so they are not wrong
until a release ships this; #561 is next, ahead of #559 and #560, for
that reason.
- How a mail is drawn, and how the window handles a link. Both are
unchanged and tracked separately.

## How to test this

Platforms: macOS and Windows, both. Buildkite builds signed artifacts
for this pull request; use the build for its current head, and check
that it is: a push to the branch makes earlier builds stale.

The suite, from the repository root, after `npm ci`:

```
npm run lint
npm test
npm run test:e2e
```

113 journeys walk every slice on macOS and Windows on each push. What
they do not do is run a real site: a clone of `wordpress-develop`, an
install, a build and a server are stood in for. The one test that does,
`real-setup.yml`, is run by hand and was run on this branch at `548c020`
(https://github.com/WordPress/contributor-toolkit/actions/runs/37298667056):
a Core site on macOS and on Windows and a Gutenberg site on macOS were
created, installed, built and served, and passed. **The Gutenberg site
on Windows did not finish.** Its first attempt was cancelled after 74
minutes inside the journey, a minute short of the limit that would have
failed it with evidence, so it says nothing about where it was; a second
attempt was still running when this was written and its result is not in
this description. The commits since `548c020` change a journey, comments
and prose.

**A pass by hand, on a real machine** (any platform; Apple Silicon for
the server, which no test on a pull request starts for real). It follows
the order a contributor meets things in:

1. Open the app with no sites. **Create new site**, a Core site, in a
folder with a space in its path. The setup checklist runs its steps; the
terminal's button at the foot of the window shows what each is doing.
2. Let the checklist's last step start the server, and finish
WordPress's own setup in the browser. Back in the app the header says
"Server running" and "Build watching". Stop the server and start it
again: from **Server running** in the header, or with **Stop** and
**Start** beside "Server" in the details.
3. Press the three buttons at the left of the footer in turn. Terminal:
type `help`. Logs: the server's lines, the build watch's, and Debug.log.
Email: where SMTP is listening. Drag the tray's top edge.
4. Link a ticket by its number. The card shows the ticket and its pull
requests and patches.
5. Apply one of them. The preview dialog names the files; **Apply and
rebuild** runs the steps on the card.
6. Edit a file under `src/`, then **Review & submit changes**. The diff
is the edit and nothing else.
7. Create a second site, or open one from before, and move between the
two from the sites list. Each has its own terminal, logs and mail.
8. **Update to latest trunk** from the site's menu.

**What must not have happened:** work lost in a link, an apply, a switch
or an update that did not say so; `node_modules` rebuilt where nothing
changed; a failure said only in a tray that stayed closed; one site's
output in another's tray; anything on the page under the tray.

**What cannot be tested by hand, and what was not:** none of the slices'
manual steps were run by a person. I looked at screenshots and drove the
app through the journeys; everything local was on macOS, with Windows
left to CI. This pass is the first one by hand.

## Risks and limitations

- **It is one commit on trunk**, since the repository allows only squash
merges. The slices' pull requests are its record. `redesign/wpds` should
not be branched from after this: it will have diverged from trunk.
- **Reviewed in slices, not as a whole.** Twenty-two pull requests, all
but a two-word change to `AGENTS.md` reviewed by a separate reviewer
context before they were opened, most in two passes; see below. The
branch was then swept once for what falls between slices, which found
comments and one unread field
(#617) and the
three points that follow.
- **Three questions and two failures still use the system's own
dialogs**: the discards ask through its confirm box, and a path that
could not be copied and a server started before there is a build are
said in its alert. #557 meant to replace them and did so for deletions
only.
- **Some dialogs are repainted, not rebuilt.** The review dialog and its
destinations, the mail dialog and the question an update asks about
loose edits have the design system's colours and type on the old
component library's parts.
- **A real Gutenberg setup on Windows is not shown to pass on this
branch.** See "How to test this". It passed on trunk before the
redesign, in 35 minutes; here it was past 46 on its second attempt.
Whether that is the runner or the branch is not known.
- **The guide describes the old interface** until #561. Do not cut a
release before it.
- **The bundle roughly doubled**
(#590): the sites
list brings `DataViews` and what it needs. Launch time was not measured.
- **Less is always in view.** A build's output, a new line in debug.log
and a caught mail are in a tray that may be closed. A failure opens the
terminal, or the logs if nothing else is open; unseen debug.log lines
are counted on the footer; a mail that arrives shows nowhere until its
tray is opened, which was decided and is not an oversight.
- **Translation is about half done.** The shell, the cards, the tray and
most dialogs go through the translator. Roughly 200 strings in
components and hooks do not yet (the review dialog and its destinations,
the setup checklist, the logs, most of what the hooks say), nor about
150 in the modules they take sentences from. Strings that are new are in
English in the shipped translations until they are translated.
- **Focus is lost in a few places**: when the app swaps what the tray
holds from under it, when a notice with a focused button goes, when a
row's own action removes the row.
- **Some failures are still worded by the main process** ("Error
invoking remote method…"): a failed rename, a failed setup.
- **Things carried over, not made by this:** a start that throws leaves
the server's button dead until a restart; erasing typed input in the
terminal breaks once the line wraps; a line written to debug.log while
it is being attached to can be shown twice.
- **#571 and
#603 will conflict
with trunk after this**, in the mail's journey and helpers and in the
dev server's hook.
- Each slice's own list has more, and says which of its limits were
chosen.

## Related

Closes #557. Closes #558. Part of #542, which stays open for #559, #560
and #561. #555 and #556 are closed already.

---

<details>
<summary>Design decisions and alternatives considered</summary>

- **An integration branch, and one landing.** A window drawn half by the
old view and half by the new one could not be released, and the slices
were too many to hold back one by one behind a flag. Fixes and changes
with no visible effect went to trunk first and were merged across, so
this diff is the redesign and little else.
- **Landing before #559 to #561.** The plan was to land when all seven
sub-issues were in the branch. The remaining three do not change what is
there: two add to it and one documents it. Holding a finished window on
a branch for them only lengthens the time trunk and the branch can drift
apart.
- **What the prototype lacks is kept and redrawn**, and what it has
somewhere else moves to where it puts it. Its labels are adopted. Where
a slice departs from it, the slice says so.

</details>

<details>
<summary>Review outcome (required — see AGENTS.md)</summary>

**No review of the whole diff was run. The record is the slices':
twenty-two pull requests into `redesign/wpds`, each but one reviewed
before it was opened by a separate, read-only reviewer context following
`.github/instructions/code-review.instructions.md`, most in two passes
(the change, then its fix-up), with the counts and the findings in each
pull request's own review outcome. The one is
#618, two words in
a line of prose.**

- **Review:** completed, per slice —
#590,
#594 to
#602,
#605,
#606,
#608 to
#617 (no review was
run for #618);
everything marked to fix in a slice was fixed in that slice, and what
was left is in its Risks.
- **Review:** completed, for leftovers only — a separate agent context,
read-only; `redesign/wpds` at `548c020` against trunk; not a review of
correctness, which the slices had: a search for dead CSS and code,
comments that waited for a slice that has landed, what is left of the
old component library and of the system's dialogs, strings not yet
translatable, and repository docs that name the branch. Nothing found in
the stylesheet, the dependencies or the docs; thirteen comments and one
unread field, fixed in
#617; the rest is
in Risks above.
- **CodeRabbit:** not run. Its check reads "Review skipped: automatic
reviews are disabled" on this pull request and on the slices, so the
slices' pre-PR reviews are the reviews of record, each for the head it
names.
- **Since review:** nothing was added to the branch outside a reviewed
slice, apart from three merges of trunk (`da19ac6`, `3344172`,
`23d46e7`).

</details>

<details>
<summary>Implementation notes</summary>

- `git diff origin/trunk...origin/redesign/wpds`: 148 files, about
14,800 lines added and 3,000 removed; about 6,300 of the added lines are
tests.
- The site's view, which was one component of five thousand lines, is
spread over the four regions the layout has: the header, the cards, the
details and the tray. Decisions are in `src/renderer/*.cjs` with unit
tests; components draw them.
- New for the suite: journeys per region under `tests/e2e/journeys/`,
lint rules of the repository's own (`eslint-rules/`), and Stylelint over
the window's stylesheet.
- The main process changed in one place for the redesign's sake: the
debug.log tail says which lines the file already held
(#614).

</details>

<details>
<summary>Screenshots or recording</summary>

Not attached: I have no way to upload images from the command line. The
prototype shows the design; the signed build shows the app.

</details>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@zaerl zaerl added this to the v2.0.0 milestone Oct 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant