Repository navigation
Conversation
…n character Fixing pull request findings in a thread caps each piece of review text at 1,000 UTF-16 code units, cutting at 997 and adding "...". When an emoji straddled the cut, the text kept only its high surrogate and showed a replacement character before the "...", in the review comment card on the composer and in the handoff prompt. The cut now steps back one unit when it would land between a high and a low surrogate, the same check pingdotgg#29158 added to context chip labels and pingdotgg#29563 added to thread titles. Bug: a review finding handed to a thread ends in a broken character when an emoji sits at the 997-unit cut
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — The change prevents truncated review handoff text from ending with half of a Unicode character. Existing length limits and handoff behavior remain intact, with no material operational exposure. 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 unchanged head reproduced the shared sent the pr handoff through the actual codex existing focused checks ran through blacksmith: ci also reports 30 successful contexts, zero failing or pending. no source changes, commits, or pushes were needed. main, matching request: pr, matching request: Not verified
|



Problem
When you fix pull request findings in a thread,
boundedinapps/web/src/components/pullRequest/pullRequestDetail.logic.tscaps each piece of review text it hands over. It cuts anything longer than 1,000 UTF-16 code units at 997 code units and adds.... When an emoji straddles that cut, the slice keeps only the emoji's high surrogate (U+D83D for 😀). The handed-over text then ends in a replacement character (�) right before the..., where it should end on the last whole character before the emoji. Review bots often put emoji in long comments, so this cut can land on one.Where the broken end shows:
contextChipParts.tsx,UserMessageContextChips.tsx). The popover scrolls rather than clipping, so the � shows once you scroll to the end.boundedFieldit caps the quoted conversation comments, check names and descriptions, the pull request title and URL, and the branch names.These come from Fix in a thread on a finding, and from fixing all findings, in the pull request panel (
PullRequestDetailPanel.tsx) and in the thread details pull request row (ThreadDetailsPrRow.tsx).boundedalso caps text in two other handoffs in the same file: the request typed when adding a selection to an agent (buildAddSelectionToAgentHandoff), and the question, the stop summary and the attention line when asking about a review-guide stop (buildAskAboutGuideStopHandoff). This fix covers them the same way.Expected: the cut never splits a surrogate pair, as in the context chip labels #29158 fixed.
Change
When the 997-code-unit cut would land between a high and a low surrogate,
boundedsteps back one code unit, so the emoji is dropped whole. This is the same check #29158 added to context chip labels and #29563 added tot3 thread starttitles. The 1,000-code-unit limit, the...suffix and every text that does not split a pair are unchanged.The cut still works per code point, not per grapheme cluster. A multi-code-point emoji, such as a flag, a skin-tone modifier or a ZWJ family, can still be split between its code points. It never leaves a lone surrogate. That matches the precedents.
The shared
truncateinpackages/sharedis not used here. #24611 (open) fixes the same split in it, butboundeddoes not call it, and its arithmetic differs: it cuts at the limit and then adds..., so switching to it would make capped text 1,003 code units long instead of 1,000.Scope and approval
This is a very small, focused fix for an obvious bug, so there is no prior issue. It is the defect #29158 ("context chip labels no longer split an emoji at the 200-character cap") and #29563 ("t3 thread start titles no longer end in a broken character") fixed elsewhere, still present in the pull request findings handoff. It applies their check and changes no other behaviour, setting or contract.
Overlap check, by
bounded,buildFixFindingsHandoff,FINDING_BODY_MAX_LENGTHand by file. Open PRs #19955, #24990, #25803, #28841, #28884, #29011, #29400, #29412 and #29960 touchpullRequestDetail.logic.ts, but none changesbounded. #24990 rewrites parts ofbuildFixFindingsHandoffand its test file, but notboundedor the case this PR extends. #24611 changes the sharedtruncate, whichboundeddoes not call.Verification
apps/web/src/components/pullRequest/pullRequestDetail.logic.test.tsgets one assertion in its existingbounds a hostile review body instead of attaching it wholecase. It hands over a review thread whose comment, byreviewer, is 986 ASCII characters, then😀, then more text. The text being cut isreviewer:followed by the body, so the emoji's high surrogate is the 997th code unit, the last one the cut keeps.On
mainwith only the test commit (a6c9a49), fromapps/web,vp test run src/components/pullRequest/pullRequestDetail.logic.test.ts:In words: on
mainthe attached review text isreviewer:, the 986 ASCII characters, the lone high surrogate U+D83D, then.... With the fix it isreviewer:, the 986 ASCII characters, then....With the fix:
vp test run src/components/pullRequest/pullRequestDetail.logic.test.tsinapps/web: 73 passed.vp run check:changedfrom the repo root: format, lint, knip, typecheck (2 packages), tests (2 files) and the React Compiler check all pass.To see it on web: the cut runs over the thread's comments as
<login>: <body>lines joined by newlines. For a thread with one comment, the emoji must start at code unit994 − <login length>of the body, counted from 0 after leading whitespace is trimmed. That is 986 for the 8-characterreviewerthe test uses. Open a pull request with such an unresolved review comment, longer than 1,000 code units in all. In the pull request panel, choose Fix in a thread on that finding. Click the review comment chip on the composer to open the full card, then scroll to its end. Onmainit ends in � before the.... With the fix it ends in....What I could not check: the composer card in a running app. The test covers the handoff builder those buttons call.
Bug: a review finding handed to a thread ends in a broken character when an emoji sits at the 997-unit cut
This was written with Claude Opus 5.5 in Claude Code, driven from T3 Code.