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: b8a2488115044cdd8d49283bbd413c4f
Branch: dev/2-p294-clean-peer-name
Base: 564a8bc
At: 2026-10-31T14:44:10Z
core/src/shared/remote-label.js:6 cleanPeerName is the twin of cleanName: same sanitise chain (String(...) → strip C0/C1 controls and \u2028\u2029 → strip []"\<>→ collapse whitespace →trim) and the same cut(text, 60), but the chain has **no .toWellFormed()**. #1938added the repair tocleanName and to the share envelope (parseRoomShare→ notice / roster / history). Every peer string that does **not** travel throughparseRoomShare` still reaches a display label with a lone surrogate inside it.
Reproduction (pure function, no fixture)
On live main 12936d207cfb89546d12a68fa9bac71d36d7d82e:
import { cleanPeerName } from './core/src/shared/remote-label.js'
cleanPeerName('Ann\ud83dX') // 'Ann\ud83dX' → isWellFormed() === false
cleanPeerName('a'.repeat(59) + '\ud83d') // 60 units, last one a lone high surrogate → still falsecut(text, 60) does not split a whole pair, but it also does not repair a lone half, so the half travels on. For contrast, cleanName in delivery.js returns 'Ann\uFFFDX' (well formed) after #1938.
Why it matters
cleanPeerName is the display-name normaliser for peer-controlled strings: client/face-seats.js, client/at-menu.js, client/cells.js, client/user-message.js, host/face-lead.js, host/room-membership.js (roster name/lead/owner, inviterName). Ill-formed UTF-16 reaches visible text and, on the roster/inviter path, text that is assembled next to prompt-facing material — the same class of damage #1937 fixed one layer up, minus the envelope.
Fix direction
Insert .toWellFormed() on the String(name ?? '') result, before the replace chain — exactly what #1938 did in cleanName. cut(text, 60) stays as is: one UTF-16 unit becomes one U+FFFD, so the 60-unit bound and the existing "never split a whole pair" behaviour do not move. Well-formed input must come back byte-identical.
Mirrors that regenerate from core/: core/client.js (bundle), patches/ds-bot/0008-client-bundle.patch, patches/ds-bot/files/src/shared/remote-label.js. Test in core/test/group-bot-label.test.js: lone half → U+FFFD; length preserved; 60-unit bound unchanged; whole pair at the boundary still dropped as a pair; well-formed input unchanged.
Dedupe (live main, 2026-10-31)
Searched open and closed issues for cleanPeerName, toWellFormed, remote-label, surrogate: #1927, #1908, #1917, #1930 (closed) are the cut-on-code-point-boundary fixes; #1937/#1938 (open) is the parseRoomShare + cleanName repair. Nothing covers cleanPeerName's missing repair — this is the remaining sibling.
Scope
core/src/shared/remote-label.js (+1), core/client.js mirror (+1), patches/ds-bot/0008-client-bundle.patch (+1/−1), patches/ds-bot/files/src/shared/remote-label.js, core/test/group-bot-label.test.js (~+20), one changelog.d/ fragment. No behaviour change for well-formed input, no constant or bound touched.
Timing
Branch dev/2-p294-clean-peer-name is cut from main at 564a8bcf6025c6aec6051968f061ee04fd80b3c1 — the merge of #1938 (the #1937 envelope + cleanName repair) — so this one rebases on nothing; #1938 did not touch remote-label.js, so the reproduction above is unaffected by it.
Activity
peer labels: make a peer display name well formed before it is cleaned (