A /rules page says, in one place, what nothing in the app said before:
the chain rule, the clock, what a dead end costs, elimination and the last
player standing, how a word is scored and the reconnect window. Linked
from the landing page and from the board and lobby headers.
The chat control moves above the chain as a pill with the unread count,
where it can be reached on a phone mid-game, and the lobby's folded chat
now carries an unread badge too.
ESLint with the Svelte and JSDoc plugins, run in CI; the real findings
it turned up (missing each keys, untyped timer handles) are fixed.
reader for both wikitext dialects; `meanings(word, ord, pos, gloss)` table; `meaning_count`/`words_with_meaning`/`source_pages` in meta, `source_rows` gone, builder_version 5; `--dump`/`--min-pages` replace `--kaikki`; attribution names the dump and the definition excerpts; 36,200 words, 96.9% with a meaning, every kaikki word kept.
Drop what nothing uses any more: the --max-syllables flag with its
sourceSpec field, meta row and reject reason; the store's clearRejection;
the --gap CSS token; three orphaned i18n strings; two exports with no
importer; the preview npm script; the proto.yml "baseline exists" step
that has been unconditionally true since the schema landed on main; and
two root-level .gitignore entries for paths Playwright never writes.
Correct text that outlived its subject: NOTICE named a tools/ directory
that never existed, the README still pointed at the first plan and
carried a migration note for retired sources, and a few comments still
said "release" for an upstream that is a weekly export. The pin test
header now says three copies and also holds README and ATTRIBUTION to
the same URL; the Make-targets table lists clean and help.
Wire fixtures regenerated so client_hello uses the ProtocolVersion
constant and server_game_started carries the 30s turn limit.
builder_version becomes 4 for the dropped meta row.
Twenty-one Playwright specs against the real binary serving the real bundle: a
bot game with its rejections, an online game across two browser contexts, and
the reconnect path. The server plays against the fixture dictionary, so nothing
here downloads the upstream release.
Every wait is on a state the server produced — the turn indicator, the required
syllable, a word appearing in the chain — never a sleep. Moves are chosen by
reading the same wordlist the server has rather than scripting a fixed
sequence, because the bot is entitled to pick a different reply.
Two things that do not work are recorded where the next person will look.
Offline emulation does not cut a loopback socket, so a test that went offline
kept playing happily. Routing the socket cuts it for real, but the close does
not reliably reach the server, so the grace window never starts: those tests
take the page away instead.