fix(agents): keep steering metadata truncation UTF-16 safe#101736
Conversation
Replace raw string slicing with truncateUtf16Safe in promptLiteral so emoji and CJK surrogate pairs in steering queue metadata are not split mid-pair at the 500-char MAX_METADATA_CHARS cap. Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Codex review: needs maintainer review before merge. Reviewed July 8, 2026, 2:10 AM ET / 06:10 UTC. Summary PR surface: Source +3, Tests +24. Total +27 across 2 files. Reproducibility: yes. Source inspection shows current main raw-slices sanitized metadata at 500 UTF-16 code units, so 499 BMP characters followed by an emoji can leave a dangling surrogate; the PR body also includes after-fix live output for that boundary. Review metrics: none identified. Stored data model Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land this narrow helper-based fix with the in-suite regression after exact-head required checks and maintainer review pass. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows current main raw-slices sanitized metadata at 500 UTF-16 code units, so 499 BMP characters followed by an emoji can leave a dangling surrogate; the PR body also includes after-fix live output for that boundary. 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 8cb92636920b. Label changesLabel justifications:
Evidence reviewedPR surface: Source +3, Tests +24. Total +27 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
Review history (5 earlier review cycles)
|
…tadata Drive buildMergedAgentSteeringPrompt with a task label placing an emoji at the 500-char MAX_METADATA_CHARS boundary to prove truncateUtf16Safe preserves the surrogate pair instead of splitting it. Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Maintainer verification complete on exact head
This is the best bounded fix: sanitization still happens first, and the existing canonical UTF-16 helper now owns only the 500-code-unit metadata boundary. |
|
Merged via squash.
|
…101736) * fix(agents): keep steering metadata truncation UTF-16 safe Replace raw string slicing with truncateUtf16Safe in promptLiteral so emoji and CJK surrogate pairs in steering queue metadata are not split mid-pair at the 500-char MAX_METADATA_CHARS cap. Co-Authored-By: Claude Opus 4.8 <[email protected]> * test(agents): add emoji surrogate boundary regression for steering metadata Drive buildMergedAgentSteeringPrompt with a task label placing an emoji at the 500-char MAX_METADATA_CHARS boundary to prove truncateUtf16Safe preserves the surrogate pair instead of splitting it. Co-Authored-By: Claude Opus 4.8 <[email protected]> * test(agents): assert steering truncation output * test(agents): remove useless string concat in emoji boundary test --------- Co-authored-by: Alix-007 <[email protected]> Co-authored-by: Claude Opus 4.8 <[email protected]> Co-authored-by: Peter Steinberger <[email protected]> Co-authored-by: chengzhichao-xydt <[email protected]>
What Problem This Solves
Steering queue metadata is capped at 500 UTF-16 code units. A raw string slice could stop between an emoji's surrogate halves, leaving malformed text in the merged parent prompt.
Why This Change Was Made
Route that boundary through the repository's canonical
truncateUtf16Safehelper. The behavior remains unchanged for ordinary text and only backs up by one code unit when the cap would split a surrogate pair.User Impact
Long subagent labels, tasks, session keys, and outcome text no longer inject a dangling surrogate into the parent agent prompt.
Scope
Two files; no config, protocol, dependency, or compatibility change. AI-assisted; maintainer-reviewed and tightened.
Real behavior proof
Behavior addressed: Steering queue metadata is capped at 500 UTF-16 code units; raw
.slice(0, 500)could split an emoji surrogate pair, leaving malformed text in the merged parent prompt.Real environment tested: Local Linux checkout at head
98d3416d49(after mergingupstream/mainand fixing the lint nit), Nodev22.22.0, repositorytsx.Exact steps or command run after this patch: A temporary harness imports
buildMergedAgentSteeringPromptfrom./src/agents/agent-steering-queue.js, builds a pending subagent run whose label is 499xcharacters followed by 🧠 + extra, calls the production function, and prints the resulting title line:Evidence after fix:
Observed result after fix: The title line is
1.plus exactly 499xcharacters (502 UTF-16 code units total). The lone-surrogate regex checks both high and low halves and reporthasLoneSurrogate: false. The emoji is safely backed off before the 500-code-unit cap.What was not tested: Real agent runtime round-trip; provider/channel delivery; other truncation sites outside the steering-queue prompt builder.
Maintainer verification
98d3416d49f680c44c7368e7f7f09b8820cc939e28920948579attempt 2: success28920948642: success28920948584: success