Repository navigation
W4-1: bound speech drafts to the server's 2000 code point limit in the UI - #88
Conversation
All three speech entry points (action-bar Say, Perception talk, NPC inspect talk) now validate the trimmed payload with one shared code-point check, matching Python len on the server. An overlong draft is not sent, not cleared and not closed; the send button is disabled and a localized role=alert message is linked via aria-describedby. Adds boundary and component regression tests covering plain, astral and combining text on both the button and Enter paths.
Independent review: PR #88 — PASSReviewed head: Full diff reviewed: three speech inputs share code-point validation of the actual trimmed payload. Exactly 2000 astral characters pass; 2001 fail. Combining marks count separately. Both Enter and click refuse overlong text without clearing or closing it. RU/EN feedback, role=alert and aria-describedby are wired. No backend or unrelated changes. Independent detached worktree make check exit 0: 3046 pytest, 387 Vitest across 47 files; ruff and mypy pass, tsc clean. One pre-existing EventLog eslint warning (0 errors). GitHub readback: check, frontend, integration, detect-changes all success on the exact reviewed head. No blocking findings. Generated attribution footer removed and read back; commit has none. |
Summary
The server (
service/action_parsing.py) rejects any string param longer than 2000 Unicode code points, measured with Pythonlen. The three frontend speech entry points had no bound, so an overlong draft was sent, cleared and then rejected by the server.components/game/speechLimit.tsholds the shared check.checkSpeech(draft)trims the draft and counts the code points of the trimmed payload withArray.from. It returns thepayload, itslength,tooLongandcanSend. An astral emoji counts as one code point and a combining mark counts as its own code point, the same as Pythonlen. The check does not use JS.lengthor HTMLmaxLength, which both count UTF-16 units.components/game/SpeechLengthError.tsxshows a localized message such as "Too long: 2001 of 2000 characters…" withrole="alert". It renders nothing while the draft is sendable.All three entry points now use the shared check and send only when
canSendis true:action-bar/SayAction.tsxPerception.tsx(talk)NpcInspectModal.tsx(talk)On an overlong draft, both the Enter key and the send button do nothing. The draft is kept, the input stays open and the modal stays open. The send button is disabled. The input gets
aria-invalidandaria-describedby, which points to the alert.New i18n key
game:speech_too_longinenandru.The server is unchanged. Valid speech behaves as before and sends the same trimmed payload.
Tests
components/game/__tests__/speechLimit.test.tsxhas 20 tests:aria-invalidandaria-describedbyare asserted.Against main's components, 10 of these 20 tests fail; with this change all pass.
make checkexits 0:EventLog.tsx)