fix(agents): edit rejects a unique match as ambiguous - #115738
Conversation
995dc10 to
b2ee025
Compare
The match is found exact-first, but the uniqueness count always ran in the fuzzy-normalized space. Normalization folds away trailing whitespace, smart quotes, dashes and NBSP, so lines the exact match had told apart could be counted as duplicates and a genuinely unique edit was refused. Count in whichever space the match was actually found in. Fuzzy matches keep counting fuzzily, so ambiguous fuzzy edits are still refused.
b2ee025 to
424b876
Compare
|
Codex review: needs real behavior proof before merge. Reviewed July 29, 2026, 9:00 AM ET / 13:00 UTC. ClawSweeper reviewWhat this changesThe PR changes the agent edit tool so a uniquely exact Merge readiness⛔ Blocked until real behavior proof from a real setup is added - 4 items remain Keep this PR open for normal review. The patch is a focused, plausible repair: it makes the uniqueness check use the same exact-or-fuzzy comparison space that selected the edit, while retaining normalized ambiguity rejection for fuzzy matches. It still needs a rebase against current Priority: P2 Review scores
Verification
How this fits togetherThe agent edit tool receives a requested text replacement, locates the requested text through exact-first fuzzy matching, then either applies the replacement or reports an ambiguity error. This change sits between match selection and the safety gate that prevents an edit from targeting multiple locations. flowchart LR
A[Agent edit request] --> B[Exact-first text matcher]
B --> C{Exact or fuzzy match?}
C -->|Exact| D[Exact occurrence safety check]
C -->|Fuzzy| E[Normalized occurrence safety check]
D --> F[Apply edit or report ambiguity]
E --> F
F --> G[Updated file content or actionable error]
Before merge
Agent review detailsSecurityNone. PR surfaceSource +9, Tests +28. Total +37 across 2 files. View PR surface stats
Review metricsNone. Stored data modelPersistent data-model change detected: Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Rebase onto current Do we have a high-confidence way to reproduce the issue? No high-confidence live reproduction was independently established in this read-only review. The branch supplies a focused source-level reproduction and a control case that clearly describe the exact-versus-fuzzy mismatch. Is this the best way to solve the issue? Yes, provisionally: using the same comparison space for match selection and duplicate counting is the narrowest maintainable repair, provided it remains correct after rebasing onto the current fuzzy-edit implementation. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 4624f681add5. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
|
|
Merged via squash.
|
The match is found exact-first, but the uniqueness count always ran in the fuzzy-normalized space. Normalization folds away trailing whitespace, smart quotes, dashes and NBSP, so lines the exact match had told apart could be counted as duplicates and a genuinely unique edit was refused. Count in whichever space the match was actually found in. Fuzzy matches keep counting fuzzily, so ambiguous fuzzy edits are still refused.
What Problem This Solves
Fixes an issue where an agent using the
edittool would have a perfectly unambiguous edit refused with:even though the text it asked to replace occurs exactly once in the file.
The trigger is ordinary: another line in the file is identical to the target except for characters that only matter to fuzzy matching, such as trailing whitespace, a smart quote, an en-dash, or a non-breaking space. Files that mix straight and curly quotes, or that have stray trailing spaces, hit this routinely.
The practical cost falls on the model. It is told to "provide more context", so it retries with a larger
oldText, which frequently spans another near-duplicate line and is refused again.Why This Change Was Made
applyEditsToNormalizedContentlocates the edit withfuzzyFindText, which is documented to try an exact match first and only fall back to fuzzy matching. The uniqueness gate immediately below it calledcountOccurrences, which unconditionally normalizes both sides before counting.So the match and the safety check ran in two different string spaces. On the exact path the match was found in raw content, while the count was taken after normalization had folded away exactly the distinctions the match had relied on. Any sibling line that is only fuzzily identical inflated the count, and the edit was rejected as ambiguous.
The fix counts in whichever space the match was actually found in, using
matchResult.usedFuzzyMatch, which the function already computes and returns. Fuzzy matches keep counting fuzzily, so an edit that really is ambiguous under normalization is still refused. Nothing about matching, normalization, or the error text changes.User Impact
Agents can now apply an edit whose target text is genuinely unique, even when the file contains near-duplicate lines differing only in trailing whitespace or Unicode punctuation. Ambiguity protection is unchanged for fuzzy matches, so edits that could land in the wrong place are still refused.
Evidence
Two tests were added to
src/agents/sessions/tools/edit-diff.test.ts.The first pins the fix and is load-bearing. Against the unfixed source it fails with the exact defect:
The second is the control case: content where the target is ambiguous only under normalization, and where no exact match exists at all. It asserts the duplicate error is still raised, so the change cannot be read as simply weakening the uniqueness gate.
After the fix, both pass along with the existing suite:
oxfmt --checkis clean on both touched files.One note on scope:
src/agents/sessions/tools/edit.test.tshas two pre-existing failures inrenders previews through custom edit operations. They reproduce identically with this change stashed, so they are unrelated to it and are left alone.AI-assisted: written and verified with an AI coding agent; the failing-test-first measurement, the control case, and the stashed comparison above were reviewed by me.