From 06e6be60e3bce8b784c4c13fd20c0f003c35daee Mon Sep 17 00:00:00 2001 From: Harshit Sharma <66710144+harshitethic@users.noreply.github.com> Date: Tue, 22 Sep 2026 03:20:58 +0530 Subject: [PATCH 1/2] fix: preserve sequential edits to the same file --- backend/app/main.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/backend/app/main.py b/backend/app/main.py index 359c165..af970f2 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -214,7 +214,7 @@ def apply_edits(repo: Path, payload: dict[str, Any]) -> tuple[bool, str]: edits = payload.get("edits") if not isinstance(edits, list): return False, "Model response missing edits array" - staged: list[tuple[Path, str]] = [] + staged: dict[Path, str] = {} for i, edit in enumerate(edits): if not isinstance(edit, dict): return False, f"Edit {i+1} is not an object" @@ -234,17 +234,20 @@ def apply_edits(repo: Path, payload: dict[str, Any]) -> tuple[bool, str]: return False, f"Edit {i+1} requires string old/new values" if not path.exists() or not path.is_file(): return False, f"File not found: {rel}" - try: - current = path.read_text(encoding="utf-8") - except UnicodeDecodeError: - return False, f"Binary/non-text file is not editable: {rel}" + if path in staged: + current = staged[path] + else: + try: + current = path.read_text(encoding="utf-8") + except UnicodeDecodeError: + return False, f"Binary/non-text file is not editable: {rel}" if current.count(old) != 1: return False, f"Expected exactly one match for old text in {rel}, found {current.count(old)}" - staged.append((path, current.replace(old, new, 1))) + staged[path] = current.replace(old, new, 1) - for path, content in staged: + for path, content in staged.items(): path.write_text(content, encoding="utf-8") - return True, f"Applied {len(staged)} edit(s)" + return True, f"Applied {len(edits)} edit(s)" def build_patch(repo: Path) -> str: From c3b8fe0df37e6a4c96ceca74c481aea93783333d Mon Sep 17 00:00:00 2001 From: Harshit Sharma <66710144+harshitethic@users.noreply.github.com> Date: Tue, 22 Sep 2026 03:21:02 +0530 Subject: [PATCH 2/2] test: cover multiple edits targeting one file --- backend/tests/test_main.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/backend/tests/test_main.py b/backend/tests/test_main.py index c20cdb5..9621589 100644 --- a/backend/tests/test_main.py +++ b/backend/tests/test_main.py @@ -60,6 +60,26 @@ def test_apply_edits_updates_exact_match(self) -> None: self.assertTrue(ok, message) self.assertEqual(target.read_text(encoding="utf-8"), "after\n") + def test_apply_edits_preserves_multiple_edits_to_same_file(self) -> None: + with tempfile.TemporaryDirectory() as temp_dir: + repo = Path(temp_dir) + target = repo / "example.txt" + target.write_text("alpha beta gamma", encoding="utf-8") + + ok, message = apply_edits( + repo, + { + "edits": [ + {"path": "example.txt", "old": "alpha", "new": "one"}, + {"path": "example.txt", "old": "gamma", "new": "three"}, + ] + }, + ) + + self.assertTrue(ok, message) + self.assertEqual(target.read_text(encoding="utf-8"), "one beta three") + self.assertEqual(message, "Applied 2 edit(s)") + def test_apply_edits_rejects_path_escape(self) -> None: with tempfile.TemporaryDirectory() as temp_dir: repo = Path(temp_dir)