fix(qqbot): use UTF-16-safe truncation for messaging reply and approval previews#101421
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed July 7, 2026, 3:19 AM ET / 07:19 UTC. Summary PR surface: Source +2, Tests +15. Total +17 across 6 files. Reproducibility: yes. at the source-expression level: current main still uses raw 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:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review detailsBest possible solution: Land the focused helper substitution after redacted real QQBot approval/log/terminal proof is added or a maintainer explicitly overrides the proof gate; keep sibling QQBot UTF-16 surfaces in their separate PRs. Do we have a high-confidence way to reproduce the issue? Yes at the source-expression level: current main still uses raw Is this the best way to solve the issue? Yes for the code shape, but not yet for merge readiness. Reusing the existing exported AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against d09469c7a6b4. Label changesLabel justifications:
Evidence reviewedPR surface: Source +2, Tests +15. Total +17 across 6 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 (1 earlier review cycle)
|
|
Merged via squash.
|
…al previews (openclaw#101421) * fix(qqbot): use UTF-16-safe truncation for messaging reply and approval previews * test(qqbot): focus UTF-16 approval regression --------- Co-authored-by: Peter Steinberger <[email protected]>
…al previews (openclaw#101421) * fix(qqbot): use UTF-16-safe truncation for messaging reply and approval previews * test(qqbot): focus UTF-16 approval regression --------- Co-authored-by: Peter Steinberger <[email protected]>
…al previews (openclaw#101421) * fix(qqbot): use UTF-16-safe truncation for messaging reply and approval previews * test(qqbot): focus UTF-16 approval regression --------- Co-authored-by: Peter Steinberger <[email protected]>
Summary
.slice(0, N)so emoji and CJK surrogate pairs in the user-visible approval command preview, TTS preview, payload-text preview, textBefore preview, media-path preview, and ApiError message are not split mid-pair.truncateUtf16Safe(text, N)helper fromopenclaw/plugin-sdk/text-utility-runtime.outbound.ts/outbound-deliver.ts/outbound-media-send.ts(covered by PR fix(qqbot): use UTF-16-safe truncation for messaging outbound previews #101410) and gateway / api surfaces (PR 2 + PR 3).Linked context
engine/tools/remind-logic.ts(llagy009 #96575) all use the sametruncateUtf16Safehelper. QQBot reply dispatcher + streaming + approval command preview is the new addition. Continues PR fix(qqbot): use UTF-16-safe truncation for messaging outbound previews #101410 (messaging outbound-deliver / outbound-media-send).Real behavior proof (required for external PRs)
TTS:preview, streaming-c2c payload-text / textBefore / media-path previews, streaming-media-sendexecuteSendQueue: sendingdebug, sender ApiError end-to-end propagation message, and the user-visible approval command preview (buildExecApprovalText) now truncate on a UTF-16 code-unit boundary instead of splitting emoji/CJK surrogate pairs.buildExecApprovalTextcode-fence).length <= capAND that the output contains no lone high or low surrogate code unit. ThebuildExecApprovalTexttest extracts the user-visible code-fence from the rendered approval text and verifies both the cap and the no-lone-surrogate invariant.packages/normalization-core/src/utf16-slice.test.ts(hasLoneSurrogatewalk). When the source site istruncateUtf16Safeit returns 0 lone surrogates; if the source site is reverted to.slice(0, N)and the input contains a surrogate pair straddling indexN-1orN, the test fails.Tests and validation
node scripts/run-vitest.mjs extensions/qqbot/src/engine/messaging/reply-dispatcher.test.ts extensions/qqbot/src/engine/approval/index.test.ts --runit()blocks across the two existing test files:reply-dispatcher.test.tsandapproval/index.test.ts).node scripts/run-oxlint-shards.mjs --threads=4clean.pnpm tsgo:extensionsclean.Risk checklist
approval/index.ts:buildExecApprovalTextis directly user-visible in QQ approval cards;reply-dispatcher.ts:sanitizeForLogand the streaming / sender debugLog paths are operator-visible in logs..slice(0, N)fortruncateUtf16Safe(text, N); the helper preserves identical behavior for ASCII, CJK (BMP), and all inputs without surrogate pairs, and only ever trims at most 1 code unit when a surrogate pair straddles the cap. Inline tests assert both the cap and the absence of lone surrogates. The SHA-256 hex slice atreply-dispatcher.ts:301and the positional slices atstreaming-media-send.ts:208/:429are intentionally skipped (hex is ASCII; positional slices operate on dynamic indices).Current review state