fix(msteams): drop dangling surrogates in message previews#98058
fix(msteams): drop dangling surrogates in message previews#98058wangmiao0668000666 wants to merge 1 commit into
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 30, 2026, 3:12 AM ET / 07:12 UTC. Summary PR surface: Source +4, Tests +38. Total +42 across 2 files. Reproducibility: yes. source-reproducible: current main and Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Next step before merge
Security Review detailsBest possible solution: Land the localized MS Teams preview truncation fix after normal maintainer review; keep broader sibling-channel UTF-16 cleanup in separate channel-specific PRs. Do we have a high-confidence way to reproduce the issue? Yes, source-reproducible: current main and 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 56c2d637d940. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +4, Tests +38. Total +42 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
|
|
Closing this as superseded by the broader UTF-16-safe truncation fix now on main: c16bb87. I kept this as one canonical pass instead of landing the one-off PRs separately so Browser, Discord, Feishu, iMessage, MS Teams, Signal, Twitch, and Voice Call preview/error truncation all use the shared UTF-16 helpers consistently. Thanks for flagging this surface. Proof for the landed commit:
|
What Problem This Solves
extensions/msteams/src/monitor-handler/message-handler.ts:250,:251, and:505use raw.slice(0, N)on the inbound message body for debug log previews and the system event label. When an emoji or other astral character straddles positionN, the slice keeps only the high-surrogate half (0xD83Cfor🎉), producing malformed UTF-16 (?/�) in verbose logs. The:505label flows intocore.system.enqueueSystemEventand then downstream, where the lone surrogate can also break string comparisons.Why This Change Was Made
The plugin SDK provides
sliceUtf16Safe/truncateUtf16Safeinopenclaw/plugin-sdk/text-utility-runtimefor exactly this pattern. Alix-007 landed the same fix for Twitch (#98008) and Signal (#97982); their PR bodies explicitly list "Discord, Feishu, Telegram, Signal, Mattermost, Slack" as already using these helpers. msteams was the remaining gap.The three call sites map to the two helpers:
rawText,text) — bare values into a log field →truncateUtf16Safe(value, 50)preview, with areplace(/\s+/g, " ")upstream) — system event label →sliceUtf16Safe(replaced, 0, 160)so the call site still reads as a slice but the trailing surrogate is dropped wholeEvidence
Boundary probe — input is
🎉(U+1F389, surrogate pair0xD83C 0xDF89) placed immediately afterN-1ASCIIacharacters so it straddles the truncation point:🎉= U+1F389, high surrogate0xD83C, low surrogate0xDF89. The loned83chalf in the BEFORE rows is the malformed UTF-16 the previous code emits; the AFTER rows show a clean ASCII tail with the surrogate pair dropped whole.After-fix Proof
node scripts/run-vitest.mjs extensions/msteams/src/monitor-handler/message-handler.dm-media.test.ts --reporter=verbosenode scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.scripts.json extensions/msteams/src/monitor-handler/message-handler.ts extensions/msteams/src/monitor-handler/message-handler.dm-media.test.ts→ EXIT=0git diff --check openclaw/main...HEAD→ cleangit diff --numstat openclaw/main...HEAD→ 2 files changed (1 source + 1 test)Diff scope
Security & Privacy
No user-facing behavior change for ASCII input. The previews render identically for non-emoji text. For emoji-straddling input, the preview is one or two code units shorter because the surrogate pair is dropped whole instead of leaving a lone high surrogate — this is the intended UTF-16 boundary fix, not a content loss.
Compatibility
Plugin SDK export (
openclaw/plugin-sdk/text-utility-runtime) is already inpackage.jsonexports for@openclaw/plugin-sdk(re-exported fromsrc/plugin-sdk/text-utility-runtime.ts). No new dependency added at the package level. The helpers are dependency-free persrc/shared/utf16-slice.ts:1-5(nonode:imports), so they bundle cleanly into both server and UI builds.What was not tested
Live MS Teams message flow with a real surrogate-pair payload. The fix is a one-line surrogate-pair guard per call site; the helpers themselves are covered by unit tests in
src/shared/utf16-slice.ts. Integration coverage at this layer is intentionally out of scope — Alix-007's PRs #98008 (Twitch) and #97982 (Signal) followed the same boundary and were accepted on the same evidence.Other channel plugins that already use the helper
Discord, Feishu, Telegram, Signal (#97982), Mattermost, Slack, Twitch (#98008). msteams is the new addition.
Related
truncateUtf16Safeon a debug-log preview.truncateUtf16Safeon a verbose-log preview.src/shared/utf16-slice.ts(read-only reference, already merged).