fix(file-operations): verify write_file persisted content before reporting success - #23142
fix(file-operations): verify write_file persisted content before reporting success#23142Frowtek wants to merge 1 commit into
Conversation
|
+1 — confirming this exact silent-failure repro on WSL2 (Ubuntu 22.04) writing to /mnt/c/... (Windows 9P share). write_file returned success: true with a plausible bytes_written while the file's mtime on the Windows side never updated. Patching the agent prompt layer to "always re-read after write" is fragile; the fix belongs at the tool layer, exactly as this PR does. |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for targeting a real false-success path. Current write_file still returns success after _atomic_write and a wc -c probe without comparing read-back content (tools/file_operations.py:1497-1533), while patch_replace already performs a content comparison (tools/file_operations.py:1604-1638).
Problems
tests/tools/test_file_operations.py:617models a successful write only when the command starts withcat >. Main now writes through_atomic_write, whose generated shell script begins withset -e;(tools/file_operations.py:1482-1497), so this test will leave its fake state unchanged and fail after salvage.- The new write-file verification-read failure branch has no dedicated test.
Suggested changes
- Key the test fake on
stdin_data is not None, as the current atomic-write tests do attests/tools/test_file_operations.py:640-647. - Add a nonzero verify-read test for
write_file.
Automated hermes-sweeper review.
|
|
||
| def test_write_file_succeeds_when_file_persisted(self, mock_env): | ||
| """Normal success path: persisted bytes should still report success.""" | ||
| state = {"content": "old content\n"} |
There was a problem hiding this comment.
Current main no longer invokes a command beginning with cat >: write_file delegates to _atomic_write, whose shell script begins with set -e; before writing stdin to a temporary file. Key this fake on stdin_data is not None instead, as the current atomic-write tests do, so the persisted-write case updates state after salvage.
Summary
ShellFileOperations.write_file()could report success aftercat > filereturned cleanly even if the target file was not actually updated on disk.
This change adds a post-write verification step that re-reads the file and
compares the normalized content against the intended write before returning a
successful
WriteResult.What changed
ShellFileOperations.write_file()Why
patch_replace()already verifies persistence after writing, butwrite_file()did not. That left a false-success path where a backend write could appear to
succeed while the on-disk file remained stale or truncated.
This aligns both write paths around the same invariant: do not report success
until the file content is actually present on disk.
Tests
tests/tools/test_file_operations.py::TestWriteFilePostWriteVerification::test_write_file_fails_when_file_not_persistedtests/tools/test_file_operations.py::TestWriteFilePostWriteVerification::test_write_file_succeeds_when_file_persistedtests/tools/test_file_operations.py::TestPatchReplacePostWriteVerification::test_patch_replace_fails_when_file_not_persistedtests/tools/test_file_operations.py::TestPatchReplacePostWriteVerification::test_patch_replace_succeeds_when_file_persistedtests/tools/test_file_operations.py::TestPatchReplacePostWriteVerification::test_patch_replace_fails_when_verify_read_errorsResult:
5 passed