fix(qqbot): truncate reminder job name on a code-point boundary#96575
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 26, 2026, 2:07 AM ET / 06:07 UTC. Summary PR surface: Source +1, Tests +34. Total +35 across 2 files. Reproducibility: yes. at source level: current main slices the trimmed reminder content at UTF-16 unit 20, so 19 ASCII units followed by an emoji can leave a lone high surrogate before the ellipsis. The PR body also includes terminal proof from the real Review metrics: 1 noteworthy metric.
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 the helper-based QQBot reminder fix after normal maintainer approval, keeping the shared SDK text helper as the single truncation implementation. Do we have a high-confidence way to reproduce the issue? Yes, at source level: current main slices the trimmed reminder content at UTF-16 unit 20, so 19 ASCII units followed by an emoji can leave a lone high surrogate before the ellipsis. The PR body also includes terminal proof from the real Is this the best way to solve the issue? Yes. Reusing the existing AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 4fc504d321b6. Label changesLabel justifications:
Evidence reviewedPR surface: Source +1, Tests +34. Total +35 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
|
465ec46 to
b57f463
Compare
generateJobName truncated reminder content with String.slice(0, 20) on a UTF-16 code-unit index, so an astral character (e.g. an emoji) landing on the boundary was cut into a lone surrogate, producing a malformed cron job name. Truncate with the shared truncateUtf16Safe helper so a surrogate pair is never split, keeping the existing 20-unit budget and ellipsis suffix. Adds a test asserting the truncated job name contains no lone surrogate.
b57f463 to
b24820b
Compare
…aw#96575) generateJobName truncated reminder content with String.slice(0, 20) on a UTF-16 code-unit index, so an astral character (e.g. an emoji) landing on the boundary was cut into a lone surrogate, producing a malformed cron job name. Truncate with the shared truncateUtf16Safe helper so a surrogate pair is never split, keeping the existing 20-unit budget and ellipsis suffix. Adds a test asserting the truncated job name contains no lone surrogate.
…aw#96575) generateJobName truncated reminder content with String.slice(0, 20) on a UTF-16 code-unit index, so an astral character (e.g. an emoji) landing on the boundary was cut into a lone surrogate, producing a malformed cron job name. Truncate with the shared truncateUtf16Safe helper so a surrogate pair is never split, keeping the existing 20-unit budget and ellipsis suffix. Adds a test asserting the truncated job name contains no lone surrogate.
…aw#96575) generateJobName truncated reminder content with String.slice(0, 20) on a UTF-16 code-unit index, so an astral character (e.g. an emoji) landing on the boundary was cut into a lone surrogate, producing a malformed cron job name. Truncate with the shared truncateUtf16Safe helper so a surrogate pair is never split, keeping the existing 20-unit budget and ellipsis suffix. Adds a test asserting the truncated job name contains no lone surrogate.
…aw#96575) generateJobName truncated reminder content with String.slice(0, 20) on a UTF-16 code-unit index, so an astral character (e.g. an emoji) landing on the boundary was cut into a lone surrogate, producing a malformed cron job name. Truncate with the shared truncateUtf16Safe helper so a surrogate pair is never split, keeping the existing 20-unit budget and ellipsis suffix. Adds a test asserting the truncated job name contains no lone surrogate. (cherry picked from commit d693ed4)
…aw#96575) generateJobName truncated reminder content with String.slice(0, 20) on a UTF-16 code-unit index, so an astral character (e.g. an emoji) landing on the boundary was cut into a lone surrogate, producing a malformed cron job name. Truncate with the shared truncateUtf16Safe helper so a surrogate pair is never split, keeping the existing 20-unit budget and ellipsis suffix. Adds a test asserting the truncated job name contains no lone surrogate.
Summary: The QQBot reminder job name was sliced to 20 UTF-16 units, tearing an emoji at the boundary into a lone surrogate. This truncates on a code-point boundary so multi-unit characters stay intact.
What Problem This Solves
QQBot reminder job names were truncated with a raw UTF-16
.slice()budget. Inputs that place an emoji or other astral character on the truncation boundary can leave a lone surrogate in the generated job name.Trigger example:
The first 20 UTF-16 units contain 19 ASCII characters plus only the emoji high surrogate, producing a malformed string such as:
Fix
extensions/qqbot/src/engine/tools/remind-logic.tsnow builds reminder job names with the sharedtruncateUtf16Safehelper instead of raw.slice()truncation.That keeps the existing 20 UTF-16-unit job-name budget and ellipsis behavior, while relying on the shared helper's range validation to avoid cutting between surrogate pairs. The generated job name remains escaped/serializable as a well-formed JavaScript string even when the input contains emoji at the boundary.
Evidence
Command run from a temporary worktree checked out at
fix/qqbot-jobname-surrogate:The demo imports the real
generateJobNamefunction fromextensions/qqbot/src/engine/tools/remind-logic.ts, reproduces the old raw.slice(0, 20)behavior, then calls the fixed function.The old path leaves a lone high surrogate (
0xd83d). The fixedgenerateJobNameoutput is well-formed and the lone-surrogate check returnsfalse.Tests
Vitest coverage was added for
generateJobNameinextensions/qqbot/src/engine/tools/remind-logic.test.ts.The tests cover: