Repository navigation
Conversation
The chip label of a preview annotation cuts a long comment at 47 UTF-16 code units. When an emoji straddles that cut, the label keeps half of it and shows a replacement character before the ellipsis, and this test fails here.
…aracter A preview annotation's context chip takes its label from the comment, cut at 47 UTF-16 code units before the shared label sanitizer runs. An emoji straddling that cut left a lone high surrogate before the ellipsis, so the chip, the record sent with the message and a thread title seeded from the annotation all showed a replacement character. The cut now steps back one unit when it would split a surrogate pair, the check pingdotgg#29158 added to the shared context chip label cap. The 48-character limit and labels without a split emoji are unchanged. Bug: a preview annotation chip label ends in a broken character when an emoji sits at the cut
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Preview annotation labels now avoid cutting a Unicode surrogate pair at the truncation boundary. The change is limited to label presentation and leaves annotation content and existing defaults unchanged. You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
|
Note Written by Verified in a real dev environmentverified as-is at
before, main: after, pr head: real provider response: 12-second recording of annotation attach, details, and removal: Not verifiednative ios/android, macos/windows desktop, other providers, remote/relay/tunnel connections, and annotation-only thread title seeding were not exercised. the web server browser has no annotation creation control, so the changed creation flow was verified through desktop. this change protects surrogate pairs; complete grapheme-cluster truncation remains outside its scope. |




Problem
A preview annotation's context chip takes its label from the annotation's comment through
previewAnnotationContextLabelinapps/web/src/lib/composerContextRecords.ts. That function cuts a comment longer than 48 UTF-16 code units at 47 units and appends…, before the sharedsanitizeComposerContextLabelruns. When an emoji straddles that cut, the label keeps only its high surrogate:The broken label shows in the composer chip. It is also stored in the context record and the chip reference sent with the message, and it seeds the thread title when the message has no text of its own.
Expected: the cut never splits a character, as #29158 made the shared chip label cap do.
Change
When the cut would land between a high and a low surrogate, it steps back one unit. That is the check #29158 added to
sanitizeComposerContextLabel. The 48-unit limit, the…suffix, the page-title fallback and every label without a split emoji are unchanged.Scope and approval
This is a very small, focused fix for an obvious bug. It is the defect #29158 ("context chip labels no longer split an emoji at the 200-character cap") fixed in the shared chip label cap, still present in the preview annotation's own, shorter cut that runs before it. It applies the same check and changes no other behaviour, setting or contract.
Two open PRs change the same file. #29804 makes
clampContextTextsurrogate-safe for terminal and review text and does not touch this label. #29834 changespreviewAnnotationContextRecordand adds a test in the same test file; this PR's test sits at a different spot. A trial merge of this branch with the current heads of both is clean.Verification
apps/web/src/lib/composerContextRecords.test.tsgets one case beside the other annotation record tests. It builds the record for an annotation whose comment is 46as followed by😀, so the emoji sits on the cut.On
mainwith only the test commit (941f304), fromapps/web,vp test run src/lib/composerContextRecords.test.ts:With the fix, from
apps/web:vp test run src/lib/composerContextRecords.test.ts src/components/ChatView.logic.test.ts: 2 files, 62 tests passed.vp run check:changedfrom the repo root: format, lint, knip, typecheck (2 packages), tests beside the change and the React Compiler check all pass.To see it in the app: open a page in the preview, add an annotation, and type a comment of 46 ASCII characters followed by an emoji and more text. The chip that lands in the composer reads
…a�…onmainand…a…with the fix.What I could not check: the chip in a running client. The test covers the label function that the chip, the record and the title fallback all read. Like #29158, the cut works per code point, so it can still split a grapheme cluster such as a flag or a ZWJ sequence; it never leaves a lone surrogate.
Bug: a preview annotation chip label ends in a broken character when an emoji sits at the cut
This was written with Claude Opus 5.5 in Claude Code, driven from T3 Code.