Skip to content

fix(twitch): truncate message preview on UTF-16 boundary#98008

Closed
solodmd wants to merge 2 commits into
openclaw:mainfrom
solodmd:fix/twitch-truncate-preview-utf16
Closed

fix(twitch): truncate message preview on UTF-16 boundary#98008
solodmd wants to merge 2 commits into
openclaw:mainfrom
solodmd:fix/twitch-truncate-preview-utf16

Conversation

@solodmd

@solodmd solodmd commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

The Twitch inbound-message debug-log preview truncates the message body
with messageText.slice(0, 100). When an emoji or other astral character
straddles position 100, the raw slice keeps only the high-surrogate half,
producing a lone \uD83D in the debug log — malformed UTF-16.

Why This Change Was Made

The plugin SDK provides sliceUtf16Safe for this exact pattern. Other
channel plugins (Discord, Feishu, Telegram, Signal, Mattermost, Slack)
already use it for the same purpose.

User Impact

No user-facing behavior change. The verbose debug log now emits valid
UTF-16 previews regardless of where emoji fall in the truncated message.

Evidence

  • git diff --check origin/main...HEAD
  • pnpm test extensions/twitch — 5 files, 43 tests passed

After-fix Proof

Boundary probe on this PR branch:

input: "x".repeat(99) + "😀" + "rest"  (emoji at position 99–100)

BEFORE .slice(0, 100):
  preview tail: [78 78 d83d]   ← lone high surrogate, broken

AFTER sliceUtf16Safe(messageText, 0, 100):
  preview tail: [78 78 0020]   ← clean, emoji dropped whole

✅ All paths produce well-formed UTF-16.

Tests

extensions/twitch/src/twitch-client.test.ts — 2 new tests covering
the straddling-emoji boundary (lone-surrogate assertion) and plain ASCII
pass-through.

Replace String.prototype.slice() with sliceUtf16Safe() when truncating
the debug-log message preview so that emoji, CJK, and other surrogate-pair
characters are not split into lone surrogates.

Co-Authored-By: Claude <[email protected]>
@openclaw-barnacle openclaw-barnacle Bot added channel: twitch Channel integration: twitch size: S labels Jun 30, 2026
@clawsweeper

clawsweeper Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 30, 2026, 3:21 AM ET / 07:21 UTC.

Summary
Replaces the Twitch inbound debug-log preview slice with sliceUtf16Safe and adds Twitch client tests for surrogate-boundary and ASCII preview behavior.

PR surface: Source +1, Tests +70. Total +71 across 2 files.

Reproducibility: yes. source inspection gives a high-confidence reproduction path: current main uses messageText.slice(0, 100), so an input like "x".repeat(99) + "😀rest" can leave a lone high surrogate in the preview.

Review metrics: none identified.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Next step before merge

  • No ClawSweeper repair lane is needed because the patch has no actionable findings and should proceed through normal maintainer review.

Security
Cleared: The diff only changes a Twitch debug-log string truncation helper import and colocated tests; it adds no dependency, workflow, secret, package, or code-execution surface.

Review details

Best possible solution:

Land the localized helper reuse with the focused Twitch regression tests after ordinary maintainer review.

Do we have a high-confidence way to reproduce the issue?

Yes, source inspection gives a high-confidence reproduction path: current main uses messageText.slice(0, 100), so an input like "x".repeat(99) + "😀rest" can leave a lone high surrogate in the preview.

Is this the best way to solve the issue?

Yes. Reusing the existing public sliceUtf16Safe helper is the narrow owner-boundary fix; a Twitch-local surrogate guard would duplicate an established SDK helper already used by sibling plugins.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 56c2d637d940.

Label changes

Label justifications:

  • P3: This is a low-blast-radius Twitch debug-log correctness fix with no config, auth, delivery, migration, or user-facing workflow impact.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes copied before/after boundary-probe output for the exact UTF-16 truncation behavior, and the live Real behavior proof check passed for this non-visual debug-log change.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes copied before/after boundary-probe output for the exact UTF-16 truncation behavior, and the live Real behavior proof check passed for this non-visual debug-log change.
Evidence reviewed

PR surface:

Source +1, Tests +70. Total +71 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 2 1 +1
Tests 1 70 0 +70
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 72 1 +71

What I checked:

Likely related people:

  • jaydenfyi: The Twitch Plugin PR introduced the Twitch client and test files, including the debug preview slice pattern now being fixed. (role: introduced feature; confidence: high; commits: f5c90f0e5c7a; files: extensions/twitch/src/twitch-client.ts, extensions/twitch/src/twitch-client.test.ts)
  • Masato Hoshino: Current blame for the raw debug-preview line points to the recent repository update commit that carried the Twitch client into the current main history. (role: recent area contributor; confidence: medium; commits: 888f399499c4; files: extensions/twitch/src/twitch-client.ts, extensions/twitch/src/twitch-client.test.ts)
  • steipete: Recent Twitch client history includes targeted refactoring in the same runtime file. (role: recent adjacent contributor; confidence: medium; commits: 999d88d13d9c; files: extensions/twitch/src/twitch-client.ts)
  • dwc1997: Recent shared UTF-16 helper tests are directly relevant to the helper contract this PR reuses. (role: shared helper contributor; confidence: medium; commits: f92ec2d4e88b; files: src/shared/utf16-slice.ts, src/shared/utf16-slice.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. labels Jun 30, 2026
@solodmd
solodmd force-pushed the fix/twitch-truncate-preview-utf16 branch from fe60ea1 to f0e51da Compare June 30, 2026 04:06
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jun 30, 2026
Add two tests for the debug-log preview truncation:
- Lone-surrogate check: an emoji at position 100 is not split
- Plain ASCII: short messages pass through unchanged

Co-Authored-By: Claude <[email protected]>
@solodmd
solodmd force-pushed the fix/twitch-truncate-preview-utf16 branch from f0e51da to 73eefe2 Compare June 30, 2026 05:03
@solodmd

solodmd commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@vincentkoc

Copy link
Copy Markdown
Member

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:

  • focused Vitest: shared UTF helper plus Browser, Discord, Feishu, iMessage, MS Teams, Signal, Twitch, and Voice Call touched suites
  • autoreview: clean on the UTF commit
  • Crabbox/Azure changed gate: run_33aba0edad9a, lease cbx_09cf3426b424, passed OPENCLAW_TESTBOX=1 node scripts/crabbox-wrapper.mjs run -- env OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1 OPENCLAW_CHANGED_LANES_RAW_SYNC=1 corepack pnpm check:changed

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

Labels

channel: twitch Channel integration: twitch P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants