Scope
Follow-up from the S4b review finding on #1408 (epic #1375, file-safety series): when focus-disruption prevention is disabled, the diff-view approval path saves via DiffViewProvider.saveChanges() without an observation/version check. A file that changes after the diff preview was rendered can be silently overwritten on user accept.
The guarded-write wiring in this series covers the tool-driven write paths (write_to_file / edit via guardedWrite() with the observation registry + version tokens). The user-accept path in the diff view is the remaining save path that bypasses the guard.
Proposed behavior
- When a diff preview is rendered, register an observation for the target (read bytes → version token), reusing the existing observation-registry semantics from S4a/S4b.
- On user accept,
saveChanges() must verify the recorded version against the current file state before writing:
- match → proceed with the (guarded) save;
- mismatch or target deleted → reject with a
GuardRejectedError-class outcome and surface a re-review prompt in the diff view (stale content highlighted), instead of overwriting.
- Behavior when focus-disruption prevention is enabled stays as-is (that path already refuses to save across a focus change).
Acceptance criteria
- Regression test: file modified after preview render, user accepts → no overwrite, re-review prompt shown.
- Regression test: unmodified file → accept saves as before.
- No behavior change for tool-driven writes (covered by the S4a/S4b suites).
References
Scope
Follow-up from the S4b review finding on #1408 (epic #1375, file-safety series): when focus-disruption prevention is disabled, the diff-view approval path saves via
DiffViewProvider.saveChanges()without an observation/version check. A file that changes after the diff preview was rendered can be silently overwritten on user accept.The guarded-write wiring in this series covers the tool-driven write paths (
write_to_file/editviaguardedWrite()with the observation registry + version tokens). The user-accept path in the diff view is the remaining save path that bypasses the guard.Proposed behavior
saveChanges()must verify the recorded version against the current file state before writing:GuardRejectedError-class outcome and surface a re-review prompt in the diff view (stale content highlighted), instead of overwriting.Acceptance criteria
References
7a25fc076—replaceIfVersionENOENT →GuardRejectedErrornormalization (the error-shaping precedent for the mismatch case above).