fix(ui): keep agent avatar initials on grapheme clusters#110837
fix(ui): keep agent avatar initials on grapheme clusters#110837nocodet888-arch wants to merge 1 commit into
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed July 19, 2026, 11:15 AM ET / 15:15 UTC. Summary PR surface: Source +105, Tests +150. Total +255 across 7 files. Reproducibility: no. independent high-confidence current-main reproduction was available in this review. The changed fallback call sites provide a clear source-level path for emoji-leading labels to be truncated by UTF-16 slicing. Review metrics: none identified. Stored data model Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Retain the shared fallback approach if it still matches current Do we have a high-confidence way to reproduce the issue? No independent high-confidence current-main reproduction was available in this review. The changed fallback call sites provide a clear source-level path for emoji-leading labels to be truncated by UTF-16 slicing. Is this the best way to solve the issue? Yes, conditionally: one shared fallback helper is the maintainable way to keep the three UI paths consistent, but it needs current-main comparison and real behavior proof before it is accepted as the best landed fix. AGENTS.md: unclear because the file could not be read completely. Codex review notes: model internal, reasoning high; reviewed against 223235044a29. Label changesLabel justifications:
Evidence reviewedPR surface: Source +105, Tests +150. Total +255 across 7 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
Review history (8 earlier review cycles)
|
|
@clawsweeper re-review Switched the helper to |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
501983c to
dc6fc3f
Compare
|
@clawsweeper re-review Rebased onto latest
Updated PR body Evidence + Real behavior proof with verbatim vitest output. |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
dc6fc3f to
adf983f
Compare
|
@clawsweeper re-review Addressed P1s:
Screenshots are local/gitignored (not committed; Head: |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
What Problem This Solves
Control UI agent avatar fallbacks used
.slice(0, 1)on the agent name/id.Names starting with a flag emoji (
🇺🇸Team) or ZWJ sequence (👨💻Dev) werecut mid-cluster and rendered as replacement characters / incomplete glyphs.
Engines without
Intl.Segmenteralso dropped safe non-ASCII BMP letters(e.g.
東京,Émile) to?when only ASCII[A-Za-z0-9]was accepted.Why This Change Was Made
Add
resolveFallbackAvatarInitialusingIntl.Segmentergrapheme granularityand use it in the three agent avatar fallback call sites. Keep the prior
locale-independent
toUpperCase()casing contract (nottoLocaleUpperCase()).When
Intl.Segmenteris unavailable, take the first code point only when itis a single BMP Unicode letter (
\p{L}) or decimal digit (\p{Nd}). Do notuse UTF-16
.sliceor non-BMP first-code-point emoji (flags / ZWJ) — those stay?so incomplete glyphs are never shown.User Impact
Before: Agent names beginning with multi-code-point emoji produced broken
avatar initials; non-ASCII letter names became
?without Segmenter.After: Fallback avatars keep a complete grapheme (flag / ZWJ emoji / letter)
with Segmenter. Without Segmenter, safe BMP letters/digits still render
(
東京→東,Émile→É) while flag/ZWJ-leading names show?.Evidence
ui/src/lib/agents/display.ts,ui/src/lib/agents/display.test.ts,ui/src/components/app-sidebar.ts,ui/src/components/app-sidebar-agent-menu.ts,ui/src/pages/agents/panels-overview.ts,ui/src/test-helpers/app-sidebar-cases/agent-menu.ts,ui/src/e2e/avatar-initials.e2e.test.tseditor →
resolveFallbackAvatarInitial(label)when no text avatar is configuredtoUpperCase(); emptylabels become
?; Segmenter-missing path keeps BMP\p{L}/\p{Nd}andrefuses flag/ZWJ clusters (
?) rather than splitting them.artifacts/control-ui-e2e/avatar-initials/(not committed):flag-avatar.png,zwj-avatar.png,tokyo-avatar.pngReal behavior proof
Behavior or issue addressed
Mounted Control UI sidebar renders
🇺🇸/👨💻/東in the agent-chip avatarslot for flag-, ZWJ-, and Japanese-leading agent names. Without Segmenter,
flag/ZWJ labels become
?while BMP letters (東京,Émile) still resolve.Canonical reachability path
Control UI agent chip / menu / overview →
resolveAgentTextAvatar(...) ?? resolveFallbackAvatarInitial(label)→.sidebar-agent-card__avatar-text/.sidebar-agent-section__avatarShared helper / provider constraint check
Same Segmenter primary path as
ui/src/pages/plugins/presentation.tstakeGraphemes, but avatar fallback refuses non-BMP / non-letter first codepoints without Segmenter (no
Array.fromemoji halves); no new config.Real environment tested
Local trusted source checkout at PR head; jsdom Control UI component mount via
mountSidebar; Playwright Chromium mocked Control UI e2e viastartControlUiE2eServer+installMockGateway; Node viascripts/run-vitest.mjs.Exact steps or command run after this patch
Evidence after fix
Helper + Segmenter-missing BMP-safe fallback:
Rendered Control UI avatar slots (production Lit templates via
mountSidebar):Playwright Control UI e2e (DOM initials + screenshots, not committed):
Local screenshot paths (gitignored, not committed):
.artifacts/control-ui-e2e/avatar-initials/flag-avatar.png— chip shows🇺🇸for🇺🇸Team.artifacts/control-ui-e2e/avatar-initials/zwj-avatar.png— chip shows👨💻for👨💻Dev.artifacts/control-ui-e2e/avatar-initials/tokyo-avatar.png— chip shows東for東京Observed result after fix
The live sidebar agent-chip avatar slots render complete flag and ZWJ graphemes
and ordinary Unicode letter initials instead of UTF-16-sliced fragments, without
changing the prior
toUpperCase()casing contract. The Segmenter-unavailablepath keeps safe BMP letters/digits and still refuses flag/ZWJ halves.
AI-assisted: yes. I reviewed and understand the change.