Repository navigation
Bound the joined notice and the copied pane line on code point boundaries - #1935
Conversation
…ode point boundaries A room share arrives from another owner, and two host-side readers of that stranger-written text still cut UTF-16 units with a raw `slice`: - `room-membership.js:1096` `noticeOf` — the notice a join carries, `…trim().slice(0, 2000)`; a notice whose 2,000th unit is half of a surrogate pair was stored with the lone high surrogate, so every later read of the room's notice carried U+FFFD. It now goes through `cut` at the shared `NOTICE_MAX`, the bound the envelope already uses. - `room-membership.js:1190` `applyShareHistory` — the stored copy of a history line is `cut(...)` at `HISTORY_TEXT` (2,000, ThinkFlowLab#1928), but the pane was handed the sender's raw `entry.text`: the guest drew a longer line than its own log kept, past the whole pair the stored bound dropped. The shown text now goes through the same `cut` at the same bound. - `fitJoin`'s notice shrink loop is untouched: each round re-measures the JSON, and an escaped half pair cannot survive it (measured 0 ill-formed entries). Both bounds are unchanged; only the unit a prefix stops before moves, the rule ThinkFlowLab#1912/ThinkFlowLab#1916/ThinkFlowLab#1923/ThinkFlowLab#1928 already apply. Two new cases in `core/test/remote-room.test.js` pin the parsed notice and the drawn line; each fails when its own site goes back to `slice`. Docs-not-needed: no owned subsystem page states a 2,000-unit bound on a joined notice or on the pane line copied from another owner; the limits are unchanged, only the unit a prefix stops on moves.
|
Verdict requested for this tip: ae3a257 (tree 1313df11cf70d7e3241dacac3f12b9379a886ad7, base 1dda685) @Birfy review request First request for this tip; nothing else has been asked on it. What is asked. A room-share What changed. Evidence in this PR. Two parsed-field assertions, each pinning one site: the notice case requires Owner: Dev |
|
Verdict: PASS at ae3a257 Ran at this tip: Red first: with Scope: compare 1dda685→ae3a257d94 gives 5 files, +127/−6, all on this fix — Tip checks: Metadata fine: |
Fixes #1933
Owner: Dev
Written-by: Dev-2
Reviewer: Birfy
Claim-Id: 287704d751b440548bfbd9049eaa67aa
Base: 1dda685
Tree: 1313df11cf70d7e3241dacac3f12b9379a886ad7
Tip SHA: ae3a257
Diff: 5 files, +127/−6
What
Two host-side readers of a room-share join still cut stranger-written text on UTF-16 units, and one of them had no bound at all:
core/src/host/room-membership.js:1096noticeOf— the notice a guest stores from ajoin,…trim().slice(0, 2000). A notice whose 2,000th unit is the high half of a surrogate pair was stored with that half, so every later read of the notice carried U+FFFD.core/src/host/room-membership.js:1192applyShareHistory— the same loopappends the copied line ascut(String(entry.text), HISTORY_TEXT).text(:1184) but drew the pane from the rawentry.text, andshowShareLine(:1142) only unwraps and trims. The guest's pane therefore showed a line longer than its own log kept, past the whole pair the stored bound had retracted.Both now use
cutfromcore/src/shared/text-boundary.js(one import addition,NOTICE_MAX), at the two call sites and not insideshowShareLine:noticeOfcuts toNOTICE_MAX(2,000, the same constant the envelope side uses forpayload.notice), andapplyShareHistorypassescut(String(entry.text), HISTORY_TEXT).texttoshowShareLine, the identical expression theappendabove it already uses — so the drawn line is exactly the stored one, and thelineop keeps its own 4,000-character transport bound. Every limit is unchanged (2,000 / 2,000); only the unit a prefix stops on moves.Red first, then one site at a time
core/test/remote-room.test.jsalone, on this branch tree, base1dda68545e. The input for both cases is'a'.repeat(1999) + '\u{1F600}' + 'b'.repeat(400): 2,405 units, so the 2,000-unit prefix ends between the halves of the emoji.noticeOfback on.slice(0, NOTICE_MAX), pane fix keptshowShareLineback on rawentry.text, notice fix keptTwo independent assertions, as the issue asks: the notice case reads
rt.state.rooms[id].noticeand requiresisWellFormed(), no U+FFFD,kept === 'a'.repeat(1999),length <= 2000and a UTF-8 byte prefix of what the host sent; the pane case capturesrt.showSharedLineand requires the drawn text to be'a'.repeat(1999), a prefix of the stored line, free of the pair the bound retracted, well formed,<= HISTORY_TEXTand a UTF-8 byte prefix of what the sender typed. Each revert turns exactly one of them red, so neither case is riding on the other's fix.Not in this change
fitJoin's notice shrink loop (core/src/shared/room-share.js) is untouched. That loop re-measures the JSON each round, and a lone surrogate that survives a cut is re-encoded as an escape and measured again, so it self-heals — measured 0 ill-formed notices in the sweep reported on room-share: cut the cross-owner body and history lines on code point boundaries #1929. This change bounds the two host-side readers that had no such loop.showShareLineitself stays unbounded on purpose: thelineop reaches it with text already fitted to Bot Social's 4,000-character wire, and a 2,000-unit cap inside it would shorten legitimate cross-owner lines. The bound belongs where the guest copies the join's history, which is also where the stored line is cut.Ran
git rebaseonto the live main1dda6854(after#1934landed). Clean:#1934touchedcore/src/shared/room-share.jsand the two test-file regions at:22and:2354, this branch touchesroom-membership.js,:974of the test file and the changelog.node scripts/ds-bot-patches.mjs generatetwice — the second run leavesgit status --porcelainempty and thegit diffhash unchanged; thencheck(4/4 ok,10 patches apply cleanly in order,core/ equals ds-bot/ + patches/ds-bot/) andcanonical(generate is a no-op).cmpofpatches/ds-bot/files/src/host/room-membership.jsand…/test/remote-room.test.jsagainst theircore/originals: byte-identical. No*.patchfile moved.TZ=UTC ARCH_DOCS_BASE=1dda68545e1fe954466d52e8d81e26a4376e19d4 npm run verifyon the committed tree (git status --porcelainempty before and after): exit 0.arch-docs: OK (5 changed file(s)); core 2339 pass / 0 fail, social 541, tree 127, timeline 135, workflow 336,.github/scripts563, interop 37, live-e2e 24 — 0 failures; lint 73 warnings / 0 errors incore(the same warnings the base has), plugins 36/9/2/16,lint:interop1 warning / 0 errors,lint:live-e2e0 / 0.core/test/remote-room.test.jsalone on the branch tree: 81/81 green, plus runs 0, 2 and 3 above, with the source restored from the commit afterwards (git status --porcelainempty).Did not run
core/index.jsor process-level change — two call sites now cut where they used to slice or pass through, and no limit moves. The desktop app and the merge queue are the review side's steps.Notes for review
changelog.d/1933-room-share-stranger-text-bound.fixed.md(both halves:#1928's envelopes and these two host readers).Docs-not-needed: no owned subsystem page states a 2,000-unit bound on the room-share join notice or on the copied pane line —
core-host.md:338names only the 4,000-character wire limit, and:41's list names the group line's 100-unit notice intools.js, a different field; no limit changes here, only the unit a prefix stops on.Checkpoint
{ "pr": 1935, "claim": "Dev", "issue": 1933, "summary": "A room-share join carries a stranger's notice and history into another owner's home, and that guest cut the notice on UTF-16 units while drawing the pane from the sender's raw text. A notice whose 2,000th unit was half a surrogate pair was stored with that half, and the pane showed a line longer than this home's own log kept. Both readers now use the shared cut rule at the same limits: the notice through NOTICE_MAX, the drawn line through HISTORY_TEXT at the call site, so the pane equals the stored line. Two cases pin the two sites separately, each red on its own revert.", "files": [ "core/src/host/room-membership.js", "core/test/remote-room.test.js", "changelog.d/1933-room-share-stranger-text-bound.fixed.md", "patches/ds-bot/files/src/host/room-membership.js", "patches/ds-bot/files/test/remote-room.test.js" ], "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=1dda68545e1fe954466d52e8d81e26a4376e19d4 npm run verify", "result": "green", "at": "ae3a257d94d4bc24c5203c47e7f9d0de4871696e" }, "next": "none — ready for review" }