From 8d0d908bef14cb9c716b65bfe2b49a8cd4e8ee90 Mon Sep 17 00:00:00 2001 From: kshitij <82637225+kshitijk4poor@users.noreply.github.com> Date: Wed, 12 Aug 2026 15:17:49 +0530 Subject: [PATCH] fix(tools): skip degenerate identical hunks in V4A validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The apply phase already skips a hunk whose -/+ lines are identical (patch_parser.py '(search_lines == replace_lines): continue'), but the validation phase lacked the guard: such a hunk reached fuzzy_find_and_replace, whose identical-strings error names old_string/new_string — parameters that don't exist in patch mode — and failed the whole atomic patch that apply would have accepted. Mirror the apply-phase skip in validation; regression test drives a mixed degenerate+live patch end-to-end (short text dodges the is_already_applied >=8-char rescue). --- tests/tools/test_patch_already_applied.py | 24 +++++++++++++++++++++++ tools/patch_parser.py | 8 ++++++++ 2 files changed, 32 insertions(+) diff --git a/tests/tools/test_patch_already_applied.py b/tests/tools/test_patch_already_applied.py index 16588d0f2d..298c568b30 100644 --- a/tests/tools/test_patch_already_applied.py +++ b/tests/tools/test_patch_already_applied.py @@ -140,3 +140,27 @@ class TestV4AAlreadyApplied: r = _patch_tool(mode="patch", patch=patch_content, task_id="t-v4a") assert r["success"] is True, r assert f.read_text() == "STATUS = 'migrated_to_v2_schema'\n" + + def test_degenerate_identical_hunk_skipped_in_validation(self, workdir): + """A hunk whose -/+ lines are identical is a no-op: the apply phase + skips it, so validation must not fail the patch (previously it + reached fuzzy_find_and_replace, whose identical-strings error names + old_string/new_string — parameters that don't exist in patch mode). + The short text also dodges is_already_applied's >=8-char rescue.""" + f = workdir / "degen.py" + f.write_text("A = 1\nB = 2\n") + patch_content = ( + "*** Begin Patch\n" + f"*** Update File: {f}\n" + "-A = 1\n" + "+A = 1\n" + "@@ B @@\n" + "-B = 2\n" + "+B = 3\n" + "*** End Patch\n" + ) + r = _patch_tool(mode="patch", patch=patch_content, task_id="t-v4a") + assert r["success"] is True, r + text = f.read_text() + assert "A = 1" in text # degenerate hunk left intact + assert "B = 3" in text # live hunk applied diff --git a/tools/patch_parser.py b/tools/patch_parser.py index 37412336ee..a95859d5e4 100644 --- a/tools/patch_parser.py +++ b/tools/patch_parser.py @@ -323,6 +323,14 @@ def _validate_operations( replace_lines = [l.content for l in hunk.lines if l.prefix in {' ', '+'}] replacement = '\n'.join(replace_lines) + if search_lines == replace_lines: + # Degenerate hunk whose -/+ lines are identical: the apply + # phase skips it as a no-op, so validation must not fail it + # — fuzzy_find_and_replace would reject the identical + # search/replacement with old_string/new_string guidance + # that has no meaning in V4A patch mode. + continue + new_simulated, count, _strategy, match_error = fuzzy_find_and_replace( simulated, search_pattern, replacement, replace_all=False )