fix(matrix): truncate thread starter body on code-point boundaries#97121
Conversation
Matrix thread-starter previews truncated long bodies by raw UTF-16 slice, which could cut an astral character (e.g. emoji) and leave a lone surrogate, rendering mojibake in the agent's thread context. Reuse the existing sliceUtf16Safe helper so the cut backs up to a valid surrogate boundary, preserving the 500-code-unit limit and '...' suffix. Adds a regression test that fails against the raw-slice implementation. Salvages the original fix from openclaw#96407 (auto-closed by the active-PR queue cap). Preserves @ly-wang19's authorship; rebased clean onto main by @Bartok9.
|
Codex review: needs maintainer review before merge. Reviewed June 26, 2026, 7:20 PM ET / 23:20 UTC. Summary PR surface: Source +1, Tests +17. Total +18 across 2 files. Reproducibility: yes. Current main's exact raw slice can be exercised with a 496- 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. Rank-up moves:
Next step before merge
Security Review detailsBest possible solution: Land this Matrix-only fix after required CI is green, keeping the existing SDK helper as the canonical UTF-16 boundary primitive. Do we have a high-confidence way to reproduce the issue? Yes. Current main's exact raw slice can be exercised with a 496- Is this the best way to solve the issue? Yes. The changed function is the single producer of the bounded Matrix thread-starter body, and using the already exported SDK helper matches existing channel truncation patterns without adding a new API. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against bdd365a34882. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +1, Tests +17. Total +18 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
|
|
Merged via squash.
|
…penclaw#97121) Matrix thread-starter previews truncated long bodies by raw UTF-16 slice, which could cut an astral character (e.g. emoji) and leave a lone surrogate, rendering mojibake in the agent's thread context. Reuse the existing sliceUtf16Safe helper so the cut backs up to a valid surrogate boundary, preserving the 500-code-unit limit and '...' suffix. Adds a regression test that fails against the raw-slice implementation. Salvages the original fix from openclaw#96407 (auto-closed by the active-PR queue cap). Preserves @ly-wang19's authorship; rebased clean onto main by @Bartok9. Co-authored-by: ly-wang19 <[email protected]>
…penclaw#97121) Matrix thread-starter previews truncated long bodies by raw UTF-16 slice, which could cut an astral character (e.g. emoji) and leave a lone surrogate, rendering mojibake in the agent's thread context. Reuse the existing sliceUtf16Safe helper so the cut backs up to a valid surrogate boundary, preserving the 500-code-unit limit and '...' suffix. Adds a regression test that fails against the raw-slice implementation. Salvages the original fix from openclaw#96407 (auto-closed by the active-PR queue cap). Preserves @ly-wang19's authorship; rebased clean onto main by @Bartok9. Co-authored-by: ly-wang19 <[email protected]>
…penclaw#97121) Matrix thread-starter previews truncated long bodies by raw UTF-16 slice, which could cut an astral character (e.g. emoji) and leave a lone surrogate, rendering mojibake in the agent's thread context. Reuse the existing sliceUtf16Safe helper so the cut backs up to a valid surrogate boundary, preserving the 500-code-unit limit and '...' suffix. Adds a regression test that fails against the raw-slice implementation. Salvages the original fix from openclaw#96407 (auto-closed by the active-PR queue cap). Preserves @ly-wang19's authorship; rebased clean onto main by @Bartok9. Co-authored-by: ly-wang19 <[email protected]>
…penclaw#97121) Matrix thread-starter previews truncated long bodies by raw UTF-16 slice, which could cut an astral character (e.g. emoji) and leave a lone surrogate, rendering mojibake in the agent's thread context. Reuse the existing sliceUtf16Safe helper so the cut backs up to a valid surrogate boundary, preserving the 500-code-unit limit and '...' suffix. Adds a regression test that fails against the raw-slice implementation. Salvages the original fix from openclaw#96407 (auto-closed by the active-PR queue cap). Preserves @ly-wang19's authorship; rebased clean onto main by @Bartok9. Co-authored-by: ly-wang19 <[email protected]>
What Problem This Solves
Matrix thread-starter previews truncate long bodies by raw UTF-16 code-unit slice. If the boundary lands inside an astral character such as an emoji, the preview keeps a lone surrogate and renders mojibake in the agent's thread context.
Why This Change Was Made
truncateThreadStarterBodyis the canonical producer of the bounded thread-starter body. This reuses the existing publicsliceUtf16Safehelper (viaopenclaw/plugin-sdk/text-utility-runtime, the same path Discord/Slack/iMessage already use) so the cut backs up to a valid surrogate boundary while preserving the 500-code-unit limit and...suffix.User Impact
Long Matrix thread starters no longer split emoji or other astral characters at the truncation boundary. Short bodies and BMP-only text retain their existing output.
Evidence
mainreproduces the defect: body"a"×496 + 😀 (U+1F600) + "bcd",MAX_THREAD_STARTER_BODY_LENGTH=500, so the cut at497lands mid-pair and leaves a lone high surrogate (U+D83D) before the ellipsis.× truncates long thread starter bodies on code-point boundaries), then green once the fix is restored.6/6passed (node scripts/run-vitest.mjs extensions/matrix/src/matrix/monitor/thread-context.test.ts).git diff --checkclean.Scope
Exactly 2 files, +19/-1 —
thread-context.tsand its regression test. No unrelated changes.Provenance and Credit
Clean re-creation of #96407 / #96961 (both auto-closed — #96961 by the dirty-branch guard after an unrelated commit contaminated the branch). This branch is rebased fresh onto current
mainwith only the Matrix two-file fix. Preserves @ly-wang19's original authorship; rebased by @Bartok9.