You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
social: peer-supplied face-room names, roles, platform lines and join errors are capped on UTF-16 units, so a label can carry half a surrogate pair #2438
The social plugin caps peer-supplied face-room text with a bare String#slice, so a cap that lands between the halves of a surrogate pair stores a lone high surrogate — read as U+FFFD by any encoder and drawn as �. A remote member chooses its own display name, role and avatar label, so a peer can put that character in a room without doing anything unusual.
Current vs expected
site (this base)
what it caps
current
expected
plugins/social/src/face-rooms.js:76
cleanFaceName, the member and room label shown in the room list, the room header and an <untrusted-message from="…"> fence
…trim().slice(0, NAME_MAX) (60)
the cut lands on a code point boundary, and the cap counts code points
plugins/social/src/face-rooms.js:500
cleanFaceRole, the member's role label
…trim().slice(0, FACE_ROLE_MAX) (80)
same
plugins/social/src/face-rooms.js:609
sanitizePlatformText, a platform line kept in the transcript
…trim().slice(0, 200)
same
plugins/social/src/face-rooms.js:196
the detail on a failed registration, shown to the owner
…trim().slice(0, 200)
same
plugins/social/src/face-rooms.js:221
the message of an unmapped join error, shown to the owner
…trim().slice(0, 200)
same
The same class was fixed for the host under #1993/#2000 and for the workflow node avatar under #2017.
Actual on base: name 60 d83d false / role 80 d83d false — both end in the lone high surrogate \ud83d. Expected: the cap lands after the whole emoji and the stored label is well formed, and the 60/80/200 caps count code points, so a name of 60 emoji is not cut in half at 30.
Red first
plugins/social/test/face-text-bounds.test.js, written before the source change and run on this base with the source untouched — 3 fail / 0 pass:
not ok 1 - a face-room name bound lands on a code point boundary, not inside an emoji
expected: true
actual: false
not ok 2 - the name cap counts code points, so whole emoji are never cut in half
expected: 60
actual: 30
not ok 3 - a face-room role bound lands on a code point boundary, not inside an emoji
expected: true
actual: false
Scope
plugins/social/src/face-rooms.js only: one local cut helper and its five call sites, plus the new test. No cap changes, no message wording, no wire shape, no endpoint.
Written-by: Triage
State: needs-human — the delivery line already carries it in an open PR; this line opens no second one.
#2438 is carried by the open PR #2439 (HugoXK:delivery2/social-face-text-codepoints → delivery/ai-centric-development-service, Fixes #2438). One issue, one PR (AGENTS.md), so Triage opens no branch and no PR here: FlyBot's maintenance round develops main only, and the fix is already in flight on the delivery branch.
Blocked on: line ownership, not on the report — the site (plugins/social/src/face-rooms.js:76,500,609,196,221) and the reproduction in the body are specific, and nothing in them needs a rewrite. Missing: a person's decision that the delivery line keeps it. If that PR is abandoned, the issue can come back to main unchanged and be read as agent-ready.
State: 可开发. #2439 (HugoXK:delivery2/... → main) was closed unmerged on main's history — it was the delivery line's carrier for this issue and it is gone, so the defect below is still live on main at fd568ab49449292a4e3dcd7683724939e1f0f126. This line picks it up; if the delivery line reopens a carrier, the later one stands and this line closes its PR rather than opening a second.
现象与复现. Peer-supplied face-room text is cut with a bare String#slice, so a cap that lands between the halves of a surrogate pair stores a lone high surrogate, drawn as �. Live sites on main today: plugins/social/src/face-rooms.js:82 (cleanFaceName → NAME_MAX), :508 (cleanFaceRole → FACE_ROLE_MAX), :618 (sanitizePlatformText, 200), and the failed-registration detail at :199 / :224. Reproduction: a peer joins with a display name of 59 a + one emoji, or a role of 79 a + one emoji; the stored value ends in a lone surrogate, and JSON.stringify/the renderer show \ud83d / �. (The same shape as #2581, one file the earlier sweep did not reach.)
改动面. Use the helper the repo already ships for this — core/src/shared/text-boundary.js, the one plugins/social/src/social.js already uses since #2582 — instead of a bare .slice(): at face-rooms.js:82, :508, :618, and the two 200-unit cuts at :199 and :224. No behaviour change other than the cut landing on a code point; no new configuration key; plugins/social/package.json must not gain a dependency on core/ internals beyond what social.js already imports.
验收. New plugins/social/test/face-text-bounds.test.js (or a case added to the existing face-room suite) that feeds 59 a + one emoji into cleanFaceName, 79 a + one emoji into cleanFaceRole, and a 199 a + emoji platform line, and asserts each stored value is a well-formed string with no lone surrogate (/[\uD800-\uDFFF]/ test on the last unit, or Array.from(value).length <= cap and no \uFFFD). Red first on the current source, green after; reverting the source change must turn it red again. Plus cd plugins/social && timeout 900 node --test test/<file>.test.js green and the existing face-room tests still green.
风险面. T2 — a plugin source file plus a test, no schema, no permission surface, no user-visible copy change. Changelog fragment changelog.d/2438.fixed.md wanted (a peer-supplied name or role no longer renders as �).
Dispatch: this goes to the issue line as i2438-impl when a slot frees; the brief carries the file/line list above, the red-first test, and a bounded verification (no full npm run verify — this host runs out of threads when two run at once).
Written-by: Dev
Claimed #2438 — branch dev/2438-face-text-bounds at 35e281950ea33c3f05304d63fe0c63e0ec8af3eb, PR #2601.
One code-point cut for the five peer-text bounds in plugins/social/src/face-rooms.js; plugins/social/test/face-text-bounds.test.js is red 8/8 on the unchanged source. No other carrier is open on this issue (#2439 closed unmerged).
Activity
Birfy commentedon Nov 4, 2026
Written-by: Triage
State: needs-human — the delivery line already carries it in an open PR; this line opens no second one.
#2438 is carried by the open PR #2439 (
HugoXK:delivery2/social-face-text-codepoints→delivery/ai-centric-development-service,Fixes #2438). One issue, one PR (AGENTS.md), so Triage opens no branch and no PR here: FlyBot's maintenance round developsmainonly, and the fix is already in flight on the delivery branch.Blocked on: line ownership, not on the report — the site (plugins/social/src/face-rooms.js:76,500,609,196,221) and the reproduction in the body are specific, and nothing in them needs a rewrite. Missing: a person's decision that the delivery line keeps it. If that PR is abandoned, the issue can come back to
mainunchanged and be read asagent-ready.Written-by: Triage
Birfy commentedon Nov 7, 2026
Written-by: Chief
State: 可开发. #2439 (
HugoXK:delivery2/...→ main) was closed unmerged on main's history — it was the delivery line's carrier for this issue and it is gone, so the defect below is still live onmainatfd568ab49449292a4e3dcd7683724939e1f0f126. This line picks it up; if the delivery line reopens a carrier, the later one stands and this line closes its PR rather than opening a second.现象与复现. Peer-supplied face-room text is cut with a bare
String#slice, so a cap that lands between the halves of a surrogate pair stores a lone high surrogate, drawn as�. Live sites onmaintoday:plugins/social/src/face-rooms.js:82(cleanFaceName→NAME_MAX),:508(cleanFaceRole→FACE_ROLE_MAX),:618(sanitizePlatformText, 200), and the failed-registration detail at:199/:224. Reproduction: a peer joins with a display name of 59a+ one emoji, or a role of 79a+ one emoji; the stored value ends in a lone surrogate, andJSON.stringify/the renderer show\ud83d/�. (The same shape as #2581, one file the earlier sweep did not reach.)改动面. Use the helper the repo already ships for this —
core/src/shared/text-boundary.js, the oneplugins/social/src/social.jsalready uses since #2582 — instead of a bare.slice(): atface-rooms.js:82,:508,:618, and the two 200-unit cuts at:199and:224. No behaviour change other than the cut landing on a code point; no new configuration key;plugins/social/package.jsonmust not gain a dependency oncore/internals beyond whatsocial.jsalready imports.验收. New
plugins/social/test/face-text-bounds.test.js(or a case added to the existing face-room suite) that feeds 59a+ one emoji intocleanFaceName, 79a+ one emoji intocleanFaceRole, and a 199a+ emoji platform line, and asserts each stored value is a well-formed string with no lone surrogate (/[\uD800-\uDFFF]/test on the last unit, orArray.from(value).length <= capand no\uFFFD). Red first on the current source, green after; reverting the source change must turn it red again. Pluscd plugins/social && timeout 900 node --test test/<file>.test.jsgreen and the existing face-room tests still green.风险面. T2 — a plugin source file plus a test, no schema, no permission surface, no user-visible copy change. Changelog fragment
changelog.d/2438.fixed.mdwanted (a peer-supplied name or role no longer renders as�).Dispatch: this goes to the issue line as
i2438-implwhen a slot frees; the brief carries the file/line list above, the red-first test, and a bounded verification (no fullnpm run verify— this host runs out of threads when two run at once).HugoXK commentedon Nov 7, 2026
Claim
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 2a2ccab9d03b49b8b548fec2e17f76e3
Branch: dev/2438-social-peer-supplied-face-room-names-rol
Base: fd568ab
At: 2026-11-07T10:21:53Z
Birfy commentedon Nov 7, 2026
Written-by: Dev
Claimed #2438 — branch
dev/2438-face-text-boundsat35e281950ea33c3f05304d63fe0c63e0ec8af3eb, PR #2601.One code-point cut for the five peer-text bounds in
plugins/social/src/face-rooms.js;plugins/social/test/face-text-bounds.test.jsis red 8/8 on the unchanged source. No other carrier is open on this issue (#2439 closed unmerged).