fix(ui): keep event payload previews UTF-16 safe#102625
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 9, 2026, 9:36 AM ET / 13:36 UTC. Summary PR surface: Source 0, Tests +39. Total +39 across 2 files. Reproducibility: yes. at source level. Current main uses Review metrics: none identified. Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Next step before merge
Security Review detailsBest possible solution: Land this focused PR after maintainer review and exact-head or merge-commit checks, keeping full Debug payload rendering unchanged and using the shared safe truncation helper for the Overview preview. Do we have a high-confidence way to reproduce the issue? Yes, at source level. Current main uses Is this the best way to solve the issue? Yes. Reusing AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 474d660137d0. Label changesLabel justifications:
Evidence reviewedPR surface: Source 0, Tests +39. Total +39 across 2 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 (7 earlier review cycles)
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
5b5ebe9 to
25a9f11
Compare
5accd09 to
042de6a
Compare
ce845c1 to
0aa1634
Compare
0aa1634 to
9bcdd65
Compare
|
Land-ready proof for
No provider/OAI-key lane is relevant to this deterministic presentation-only invariant. |
|
Merged via squash.
|
* fix(ui): keep event payload previews UTF-16 safe * chore: use shared utf16 truncator in presenter * fix(ui): use canonical utf16 truncator import * refactor(ui): reuse canonical text truncation --------- Co-authored-by: Peter Steinberger <[email protected]>
What Problem This Solves
The Control UI Overview event log created its 120-code-unit payload preview with raw UTF-16 slicing. If the boundary landed between the halves of an emoji or another supplementary character, the rendered preview could contain a lone surrogate.
Why This Change Was Made
truncateTexthelper.truncateTextdelegates to the canonical@openclaw/normalization-core/utf16-slicetruncator, so the UI keeps one UTF-16-safe truncation path instead of a presenter-specific adapter.User Impact
Long Overview event payload previews remain bounded and no longer display malformed emoji or replacement characters when payload text contains astral Unicode characters near the preview boundary.
Evidence
origin/mainat8d6c54f513136ff204c5e254c2b33872cd4ea0d9still rendersformatEventPayload(entry.payload).slice(0, 120)inui/src/pages/overview/event-log.ts.5accd09a8e5d7c09a45a893954c7b325bcdca77d.proof: sufficient,rating: 🦞 diamond lobster, andstatus: 👀 ready for maintainer lookwere applied byclawsweeper[bot].Real behavior proof
5accd09a8e5d7c09a45a893954c7b325bcdca77d./overviewin Chromium, emitted anagent.messageGateway event whose legacy 120-code-unit preview ends on a high surrogate, then read.ov-event-log-payloadfrom the DOM.{ "browserPath": "/overview", "legacySliceLastCodeUnit": 55357, "legacyEndsWithHighSurrogate": true, "previewLength": 119, "previewLastCodeUnit": 97, "previewEndsWithHighSurrogate": false, "previewTail": "aaaaaaaaaaaaaaaaaaaaaaaa" }The legacy raw slice still demonstrates the bad boundary, while the rendered Overview DOM preview backs off to 119 code units and ends on ordinary
a(97), not a dangling surrogate.Focused checks
Regression Test Plan
ui/src/pages/overview/event-log.test.ts.Root Cause
formatEventPayload(entry.payload).slice(0, 120), which truncates by raw UTF-16 code units and can leave a dangling surrogate when the boundary falls inside an emoji.