Skip to content

fix(shared): long assistant quote chips no longer end in a broken character - #30367

Open
spoukyii wants to merge 2 commits into
pingdotgg:mainfrom
spoukyii:users/spoukyii/citation-label-emoji
Open

spoukyii wants to merge 2 commits into
pingdotgg:mainfrom
spoukyii:users/spoukyii/citation-label-emoji

Conversation

@spoukyii

@spoukyii spoukyii commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Problem

When an assistant quote is 64 UTF-16 code units or longer and an emoji straddles that point, the quote chip's label keeps only the emoji's high surrogate, so it ends in a replacement character (�) right before the …. It should end on the last whole character before the emoji, as #29158 made context chip labels do.

Change

The label comes from assistantCitationLabel in packages/shared/src/assistantCitations.ts, which cuts the quoted text, or the comment bound to it, at 64 UTF-16 code units and adds …. When the cut would land between a high and a low surrogate, it now steps back one unit. That is the check #29158 added to sanitizeComposerContextLabel, and #29163 and #29563 use it for thread titles. The 64-unit limit, the … suffix and every label without a split emoji are unchanged.

Where the broken end showed, on web and desktop:

  • The quote chip in the sent user message, on a desktop-width window. That chip has no width cap of its own, so the whole label fits in the message bubble.
  • The chip's screen-reader labels, View cited assistant text: <label> and Quoted assistant text: <label>.
  • The text find-in-thread searches, which uses the label for each citation.

The chip in the composer uses the same label but clips it to one line of 16em, so the broken end never shows there. Mobile is not affected: it renders a citation as the full quote, not as this label. The citation the message stores is unchanged; the label is computed when the chip renders, so messages already sent show the fixed label too.

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 label of the other chip the composer makes, the assistant quote chip. It applies the same check and changes no other behaviour, setting or contract.

Overlap check, by assistantCitationLabel and by file. #28084, #28088 and #23473 change assistantCitations.ts and its test, but none touches assistantCitationLabel. #23473's test hunk sits near this PR's new case, a few lines apart. #22148 adds a new assistantCitationLabel caller in the collapsed composer preview and would show the fixed label. #29386 (mobile citing) does not touch these files. #24611 changes the shared truncate, which this function does not call.

Verification

packages/shared/src/assistantCitations.test.ts gets one case in its existing assistant citation references block. No case covered assistantCitationLabel before. It labels a quote of 63 as followed by 😀, so the emoji sits on the cut.

On main with only the test commit (3f9a882), from packages/shared, vp test run src/assistantCitations.test.ts:

 FAIL  src/assistantCitations.test.ts > assistant citation references > shortens a long quote label without splitting an emoji
Expected: 63 "a"s, then "…"
Received: 63 "a"s, the lone high surrogate U+D83D (shown as �), then "…"
      Tests  1 failed | 20 passed (21)

With the fix:

  • vp test run src/assistantCitations.test.ts src/threadFindText.test.ts in packages/shared: 2 files, 30 tests passed.
  • vp run check:changed from the repo root: format, lint, knip, typecheck (34 packages) and tests (3 files) all pass.

In a running dev build (web, Windows): the free Replay provider replied with the line "Rename the config loader so it reads from the new paths first, 🚀 then ship the change.", whose first 63 UTF-16 code units come before the emoji. I selected that line, clicked "Cite selection in composer" and sent the message with main's assistantCitations.ts, then reloaded with this branch's. The same sent message:

Before (main) After (this branch)
Before: the sent quote chip ends in a replacement character before the ellipsis After: the sent quote chip ends on the comma before the ellipsis

The Replay reply text was edited locally for this run only. The captures are the preview panel's visible area (951 by 701), not the full window.

What I could not check: desktop and the screen-reader labels with an actual screen reader. Like #29158, the cut works per code point, so it can still split a grapheme cluster such as a flag, a skin-tone modifier or a ZWJ sequence; it never leaves a lone surrogate.

Bug: a long assistant quote chip 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.

@github-actions github-actions Bot added the vouch:unvouched PR author is not yet trusted in the VOUCHED list. label Nov 3, 2026
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Walkthrough

assistantCitationLabel now avoids cutting between the two UTF-16 code units of a surrogate pair. A test checks that a long label with an emoji at the cutoff ends with an ellipsis instead of a split emoji.

Changes: Citation label truncation

Layer / File(s) Summary
Preserve surrogate pairs at the cutoff
packages/shared/src/assistantCitations.ts, packages/shared/src/assistantCitations.test.ts
assistantCitationLabel adjusts the cutoff when it would split a surrogate pair. The test checks that the resulting label contains 63 leading a characters followed by an ellipsis.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Possibly related issues

  • pingdotgg/t3code#27842: The issue reports surrogate pairs split by truncation. This PR addresses the same issue in assistantCitationLabel, but does not change the generic truncation path named in the issue.

Possibly related PRs

  • pingdotgg/t3code#26610: This PR changes the helper used for composer and link labels in the mobile citation workflow.
  • pingdotgg/t3code#29386: This PR changes the helper used for citation chips in the mobile citation workflow.
  • pingdotgg/t3code#30345: Both PRs adjust truncation to avoid splitting a surrogate pair, in different label paths.

Suggested labels: bugfix, size:S

Suggested reviewers: flamboh, macroscopeapp

Merge Risk: Minimal · up to beaea

The PR addresses the reported broken-character regression with no outstanding merge-blocking risk identified.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main fix: preventing broken characters in long assistant quote chips.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The description includes all required sections: Problem, Change, Scope and approval, and Verification. It explains the bug, implementation, scope rationale, regression test, validation results, UI evi…
Full details: Description check

Explanation

The description includes all required sections: Problem, Change, Scope and approval, and Verification. It explains the bug, implementation, scope rationale, regression test, validation results, UI evidence, and remaining verification limits. It also identifies the model and harness used.

Finishing Touches
Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.
Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between d1ec71e and beaea4d.

Files selected for processing: 2
  • packages/shared/src/assistantCitations.test.ts
  • packages/shared/src/assistantCitations.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.

@github-actions github-actions Bot added the size:XS 0-9 changed lines (additions + deletions). label Nov 3, 2026
…racter

assistantCitationLabel cut a quote or its comment at 64 UTF-16 code
units. When an emoji straddled the cut, the label kept only its high
surrogate, so it ended in a replacement character before the ellipsis.
That shows in the quote chip of a sent message on a desktop-width window,
in the chip's screen-reader labels and in the text find-in-thread
searches. The composer chip clips its label to one 16em line, so the
broken end never shows there.

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.

Bug: a long assistant quote chip ends in a broken character when an emoji sits at the cut
@spoukyii
spoukyii force-pushed the users/spoukyii/citation-label-emoji branch from beaea4d to 4a68ff9 Compare November 3, 2026 21:08
@maria-rcks

maria-rcks commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

verified unchanged head 4a68ff97d43be1ff37f5d43b9d8b1e9bed03f981 on a linux boat vm using repository playwright and /usr/bin/google-chrome, with real codex gpt-6.1-sol turns through the web composer. no mocks, replay provider, fixtures, or source edits.

  • reproduced on github/main (7c22e24e3f): selected a real assistant reply with the rocket emoji beginning at UTF-16 index 63, clicked cite, saved and sent. the sent chip and accessible label retained a lone U+D83D before the ellipsis.
  • stopped main, started the exact pr head against a copy of that isolated app-created state, and inspected the same sent message. the chip and accessible label now end cleanly at the comma and ellipsis.
  • created and sent fresh long and short citations on the pr. the short label stays Short quote works.. the popover retains the complete quote and go to source navigates back to the assistant reply.
  • codex correctly answered then for the word following the rocket and reproduced the complete short quote. a separate citation with a long attached comment also had a clean label; codex reproduced both its full quote and full comment, including the emoji.

blacksmith checks passed: 30 focused citation/search tests, plus vp run check:changed a10490937dbd8a9e441b0518a77a60117f3ecf5a (format, lint, knip, 34-package typecheck, 22 selected tests). the explicit base is needed because the remote worker initially receives shallow history. existing ci reports 28 successful checks. no code changes were necessary.

before, main:

main: sent citation ends with a broken character

after, same saved message on the pr:

pr: sent citation ends with a clean ellipsis

selection, citation creation, popover, source navigation and sending:

real web citation interaction

real provider response to the two citations:

codex reads the full long and short citations

Not verified

native electron, ios/android, macos/windows, an actual screen reader, and remote/relay connections were not exercised on this linux web run. accessible DOM labels were inspected directly. this vm lacks a rocket emoji font, so the full emoji appears as a missing glyph in the captures; its unicode and delivery to codex were verified. find-in-thread was covered by the existing focused tests, not a browser interaction.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XS 0-9 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants