fix(articles): actually enforce the limits the editor declares - #135
Merged
Conversation
`ARTICLE_LIMITS.requestBytesMax` was declared and never read. The 256 KB cap is on the whole request body and is independent of the character count, so a body inside the 100.000 character limit still breaches it once it carries emoji or Turkish letters — and the server answers 413, not a validation error, so nothing downstream could explain it. Turkish writers are the likely first to hit it, which makes it a poor thing to leave unchecked. The character limit was checked in the wrong place. `bodyTooLong` disabled publish but `canSave` only looked for emptiness, so autosave kept sending an over-length body on every pause. Each attempt was rejected with a bare 400, spending the sixty-a-minute update budget and telling the writer nothing. Both checks now live in one place the hook and the page share, and `save` re-runs it rather than trusting its caller — it is also reached from the retry button and from publish. The indicator names the limit that is breached instead of saying only that something is unsaved. The draft was being re-serialised on every render for the dirty check, over a body that runs to a hundred thousand characters. It is serialised once per change now and both the dirty check and the byte count read that. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hu1QuLxS84vdf1gmzoGtWP
Contributor
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
tdn-client | 9876914 | Commit Preview URL Branch Preview URL |
Aug 26 2026, 03:24 AM |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two more from continuing the review, and they share a root: the editor knows the server's limits and was not using them.
A constant declared and never read
ARTICLE_LIMITS.requestBytesMax— the 256 KB cap on the whole request body — was defined when the editor was written and never referenced anywhere.It matters because it is independent of the character count. A body comfortably inside the 100.000 character limit still breaches it once it carries emoji or Turkish letters, and the server answers 413, not a validation error, so nothing downstream could explain what happened. Turkish writers reach it first, which makes it a poor thing to leave unchecked in a Turkish-language product.
The character limit was checked in the wrong place
bodyTooLongdisabled the publish button.canSave— which gates autosave — only looked for emptiness. So an over-length body kept being sent on every typing pause, each attempt rejected with a bare 400, spending the sixty-a-minute update budget and telling the writer nothing.Both checks now live in one function the hook and the page share, and
savere-runs it rather than trusting its caller — it is also reached from the retry button and from publish. The indicator names the limit that is breached instead of saying only that something is unsaved.While in there
The draft was re-serialised on every render for the dirty check, over a body that can run to a hundred thousand characters — so every keystroke in a long article stringified the whole thing. It is serialised once per change now, and both the dirty check and the byte count read that.
Reviewing
The three tests that matter fail on
main: an over-length body is sent, a 90.000-emoji body (well under the character limit, well over 256 KB) is sent, and neither is reported to the writer.The page test's mock now keeps
problemin step withcanSave, since the two always agree in the real hook —canSaveisproblem === null.Verification
pnpm build,tsc -b,pnpm lintclean. 479 unit tests across 66 files and 29 Playwright tests pass.🤖 Generated with Claude Code
https://claude.ai/code/session_01Hu1QuLxS84vdf1gmzoGtWP