fix(edit): keep mismatch hint truncation unicode-safe#99527
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 4, 2026, 5:16 AM ET / 09:16 UTC. Summary PR surface: Source +1, Tests +17. Total +18 across 2 files. Reproducibility: yes. from source inspection. Current main and 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. Next step before merge
Security Review detailsBest possible solution: Merge the focused helper reuse and regression test after maintainer review and normal exact-head required checks complete. Do we have a high-confidence way to reproduce the issue? Yes from source inspection. Current main and Is this the best way to solve the issue? Yes. Reusing the dependency-free AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against be95bb72d459. Label changesLabel 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
Review history (4 earlier review cycles)
|
b6a8fa9 to
0495dcb
Compare
|
Land-ready maintainer proof for final rebased head
Proof gap: no external channel, Gateway, or UI run; those surfaces are untouched. The live invocation exercises the actual edit-tool mismatch path, not a standalone helper. |
81e2d37 to
99c03e1
Compare
99c03e1 to
b41df44
Compare
|
Merged via squash.
|
* fix(edit): keep mismatch hint truncation unicode-safe * fix(edit): preserve mismatch hint size bound --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary
This PR fixes the edit-tool mismatch diagnostic truncation path so the
Current file contents:hint cannot split an emoji or other astral Unicode character at the 800-character cutoff.oldText, the diagnostic should show trustworthy current-file context. A broken replacement character at the truncation boundary makes the hint harder to use when the file contains non-BMP Unicode near the cutoff.Real behavior proof
Current file contents:to the thrown mismatch error. Before this change, long current-file snippets were truncated with rawString.prototype.slice(0, 800), which can split a UTF-16 surrogate pair when the cutoff lands inside an emoji or other astral Unicode character.node --import tsx. The script importedsrc/agents/sessions/tools/edit.ts, created a temporary file containing 799 ASCII characters, one🙂emoji, and trailing text, then calledcreateEditTool(...).execute(...)with a missingoldTextto trigger the real mismatch diagnostic path. I also ran the focused regression test and changed-file checks:The focused edit-tool test suite exited 0.
git diff --checkexited 0. The local changed-file check exited 0 and selected the core/core-test lanes forsrc/agents/sessions/tools/edit.tsandsrc/agents/sessions/tools/edit.test.ts.... (truncated), and does not contain the Unicode replacement character. The regression test verifies the same boundary case throughcreateEditTool(...).execute(...), so the hint no longer relies on raw.slice()truncation at the UTF-16 boundary.pnpm check:changedinvocation attempted to delegate to Blacksmith Testbox throughcrabbox, but this host'scrabboxbinary failed its basic sanity check before running repo checks. The local child-mode command above was used for the actual changed-file verification.What Problem This Solves
When an edit replacement cannot find its exact
oldText, the edit tool appendsCurrent file contents:to help the model/user see what actually exists in the file. For long files this diagnostic is capped atEDIT_MISMATCH_HINT_LIMITcharacters.Before this change, the cap used raw JavaScript string slicing. JavaScript
slice()counts UTF-16 code units, not displayed Unicode characters/code points. If an emoji or other astral character straddled the 800-code-unit boundary, the hint could include only half of the surrogate pair. That produces a malformed diagnostic snippet at the exact point where the tool is trying to provide useful mismatch context.Root Cause
appendMismatchHint(), and that formatter truncatedcurrentContentwithcurrentContent.slice(0, EDIT_MISMATCH_HINT_LIMIT). That operation counts UTF-16 code units instead of whole Unicode code points, so the diagnostic owner could create an invalid snippet by cutting between the high and low surrogate of a non-BMP character.for...ofmakes the formatter count whole Unicode code points, so the invariant becomes: the edit mismatch hint may be shortened, but it never creates a malformed half-character at the truncation boundary. This fixes the source formatter rather than masking replacement characters after the fact.src/agents/sessions/tools/edit.ts. No public contract, schema, protocol, config, generated model, or API surface is changed; compatibility and default behavior for edit execution are unchanged. A related open PR / same-contract scan is not relevant because this patch does not define or expand a public contract surface. Out of scope: changing edit matching, replacement, persistence, preview rendering, gateway behavior, approval UI, or any protocol field.Changes
currentContentwithfor...of, so the cutoff is counted by Unicode code point instead of raw UTF-16 code unit.... (truncated)suffix behavior.Review findings addressed from the previous PR content
This PR previously carried a different approval-prompt/protocol/UI change. That old diff has been removed from the branch and replaced with the focused edit-tool fix above.
Evidence
The live proof and regression test both covered the real edit-tool mismatch error path through
createEditTool(...).execute(...), not only a standalone helper. The boundary file contains 799 ASCII characters followed by an emoji and trailing text, then triggers an exact-match miss. The observed diagnostic includes the intact emoji and the existing truncation marker.Changed-file verification also covered:
All selected local changed-file lanes exited 0.
Regression Test Plan
src/agents/sessions/tools/edit.test.ts.... (truncated), not a sliced surrogate half or replacement character.Merge risk
merge-risk:*label should be required for the current diff. The old approval-protocol/UI compatibility risk no longer applies because that diff was removed.