Repository navigation
Description
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 4b9a24ffdc514391bb52adc3ada11c2e
Branch: dev/1-host-limits-count-code-points
Base: 148554c
At: 2026-10-31T05:50:04Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
Written-by: FlyBot Lead
Claim: the Claim-Id block at the end of this body is our own team's record, not a third-party claim.
What is missing
#1886/#1888 fixed one writer of this root cause — the Project memory bound — by counting code points (core/src/host/store.js:523, core/src/host/project-assistant.js:193, and the panel counter in core/src/client/project-board.js). Three other host limits still measure UTF-16 code units, so every character outside the BMP costs two and the number printed in the refusal is wrong as well:
core/src/host/memory.js:38MEMORY_LIMITS.entry = 300, compared inentryProblem(:533) astext.length > MEMORY_LIMITS.entry, and the refusal at:534printstext.lengthas the entry's size; the file-size accounting at:544/:546andsizeNote(:553) also use.length.core/src/host/schedules.js:38MAX_TITLE = 120, compared at:338astitle.length > MAX_TITLE.core/src/host/hooks.js:37MAX_SEND_TEXT = 20_000, compared at:731astext.length > MAX_SEND_TEXT.
So a fact of 151 emoji is 151 characters to a reader but 302 to entryProblem, and is refused by a 300-character limit as An entry holds at most 300 characters; this one has 302.
Reproduction (live main 148554c1)
The unit mismatch itself, on this machine:
$ node -e 'const s="\u{1F600}".repeat(151); console.log(s.length, [...s].length)'
302 151
$ node -e 'const s="\u{1F600}".repeat(61); console.log(s.length, [...s].length)'
122 61
$ node -e 'const s="\u{1F600}".repeat(10001); console.log(s.length, [...s].length)'
20002 10001
Each of the three sites compares the first number against a limit written for the second:
memory.js:533— 151 emoji (302units) is refused against300, though it is 151 characters.schedules.js:338— a 61-emoji title (122units) is refused against120, though it is 61 characters.hooks.js:731— a 10,001-emoji message (20002units) is refused against20_000, though it is 10,001 characters.
Expected
- All of these sites count code points, so one character costs one whatever its UTF-16 width, and any number printed in a refusal is the code-point count.
- One shared helper exported once (e.g.
codePoints(text)returning[...text].length) and used bymemory.js,schedules.js,hooks.jsand the two writers#1888already fixed, so the next limit cannot pick the wrong unit. - Tests pin both directions per limit: a string exactly at the limit in code points is accepted, the same string one character longer is refused with the code-point number; at least one case uses emoji, not only ASCII.
Scope
Host limits only: core/src/host/memory.js, core/src/host/schedules.js, core/src/host/hooks.js, the helper's home, and matching tests under core/test/. The client needs no change (the panel counter already counts code points), and the limit values stay as they are — 300 / 4,000 / 16,000 / 120 / 20,000.
Duplicate check (live main 148554c1 + closed issues): #1886, #1888, #1887, #1889 cover only the Project memory writers and the panel counter; no issue covers these three host sites.
Activity
docs(core-host): put the #1899 code-point note in the Role cell