docs: record the score breakdown, dead-end claim and word report

README's frontend and rules paragraphs mention the visible score breakdown
and the dead-end claim button. deployment.md documents word_reported next to
word_rejected, and the new dead-end-claim and words-reported counters.
This commit is contained in:
tiennm99 committed 2026-09-21 01:55:10 +07:00
1 parent 0003a4510b
commit e52b0ef2c3
2 files changed
+27 -8

No files matched your search

+12 -5
View File
@@ -144,17 +144,24 @@ once per turn and never over text the player has already typed, so no compositio
progress when it happens.
The chain is listed newest first, and a finished game can be downloaded as a plain-text
transcript — the chain in playing order, who played what, and the final score.
transcript — the chain in playing order, who played what, and the final score. Each word in
the chain shows the named terms its points came from, since the client has no wordlist of its
own to re-derive that from a single number.
A player handed a syllable nothing answers is not left to wait out the clock: a "Bí từ" button
next to the input claims the dead end, and the server settles it immediately — correctly if the
position really is one, refused with the clock still running if it is not.
Every Vietnamese string lives in `web/src/lib/i18n/vi.js`, including the map from
`RejectReason` to a message. That is why `ServerError.code` is a UI key such as
`room_not_found` and never prose. A test walks the generated enums and fails when a value has
no message, so a schema change cannot quietly ship an untranslated screen.
The rules — the chain, the clock, a dead end, elimination, scoring, room codes and reconnect
grace — are written out once on `/rules`, a single anchored page linked from the landing
screen and from a small "Luật chơi" link beside the connection badge in the game header and
the lobby. It is not a button: reading the rules is not a way to start playing.
The rules — the chain, the clock, a dead end and the claim button for it, elimination, scoring
and its visible breakdown, room codes and reconnect grace — are written out once on `/rules`, a
single anchored page linked from the landing screen and from a small "Luật chơi" link beside
the connection badge in the game header and the lobby. It is not a button: reading the rules is
not a way to start playing.
The countdown is drawn against the server's clock, estimated from the `Ping`/`Pong` round
trip, and settles 300ms early so the ring never claims more time than the server allows.
+15 -3
View File
@@ -174,9 +174,11 @@ as not having it. The counters, all prefixed `noitu_`: connections open and
total; rooms live and total, each split `bot`/`pvp`; games started and
finished the same way; words submitted, accepted, and rejected by reason;
eliminations by reason; chat lines; join attempts refused, by whether it was
the rate limit, an unknown code, or a full room; bot moves by difficulty; and
resumes attempted versus succeeded. None of it is read by the game itself —
it is a second write next to a decision already made, not an input to one.
the rate limit, an unknown code, or a full room; bot moves by difficulty; dead-
end claims by whether the position actually had no legal move; words reported
as real by `ReportWord`; and resumes attempted versus succeeded. None of it is
read by the game itself — it is a second write next to a decision already
made, not an input to one.
Every rejected word also gets one structured log line at `Info`,
`word_rejected`, carrying `reason`, `word`, `link` (the syllable it had to
@@ -187,6 +189,16 @@ collect and is exactly the corpus-review question this project has open:
which words players type that the dictionary does not have. Nothing else a
player types is logged: not chat, not a nickname, not an accepted word.
A player who disputes a rejection this way — `ReportWord` — gets the same
treatment: one `Info` line, `word_reported`, carrying `word` (normalized the
same way), `link` (the syllable in play, empty when the report was not filed
mid-game), `mode` (`bot`/`pvp`/`none`) and `room`. Only words of at least two
syllables are recorded, and a session may file at most 20 distinct ones — never
the player's nickname, on both counts for the same reason `word_rejected`
never carries one. Between the two, this is the whole of the corpus dispute
loop: triaged by hand today, into whatever curated word list eventually
applies the fix.
## Health and readiness
`GET /healthz` returns 200 once the dictionary has loaded, for the rest of the