fix: preserve unrelated files during Windows update cleanup

Merged
SH
21d ago
+586-38

Running wally --version on Windows deletes every adjacent .old file, including unrelated backups. The installer also retires unrelated directory contents.

Replace only verified-release filenames and publish exact-name/SHA-256 backup receipts after successful replacement. Preserve legacy, unrecorded, changed, locked and interrupted-update files. Serialize transactions and retain recovery files when rollback cannot restore everything.

Review hardening keeps regular non-reparse backup/receipt handles locked through verification and deletes through those handles, rather than reopening paths. The next update warns about uncommitted recovery artifacts without reclaiming them. Both original findings are marked addressed; follow-up review reported no new issues. No dependencies, SDK pins, or non-Windows update behavior change.

A separate test-only follow-up preserves app-local Windows DLLs when relocating the child fixture and explicitly supplies nonterminal stdin for CLI assertions. Both corrected fixtures pass against freshly rebuilt main binaries and through this branch's normal test entry points. This changes test setup, not application routing, assertions, or timeout limits.

Validation

Integrated with main 3819f463498f3aed2e119df69ff0ffc1edbc9652, current locked dependencies, SDK kit 0.20.39 and IDL 1.5.0. Main was rechecked before publication and is unchanged.

  • Paired production-binary reproduction: main deletes three synthetic unrelated/legacy .old files; the fix preserves their exact bytes.
  • cargo test --release --locked --lib commands::update_backups::tests: all six ownership regressions pass in the local full Rust run. The preceding published revision also passed these regressions in native Windows x64 and ARM64 CI.
  • scripts/test/test-update-in-place.ps1 -Binary ./build/wally.exe: passes in Windows PowerShell 5.1 and PowerShell 7 locally. Covers running/locked executables, rollback/restoration failure, concurrent-update refusal, directory collision, recovery warning/preservation, and receipt consumption by the rebuilt binary.
  • cmake --build build -j 2, CLI/backend smoke, fresh ZIP packaging and clean-room ZIP launch: pass. Formatting, version consistency, test ledger and whitespace checks pass.
  • Fresh ctest --test-dir build --output-on-failure: 5/6 pass, Rust 628 passed, 2 failed, 8 ignored, exit 8. Unmodified main: 3/6 CTest pass, Rust 622 passed, the same 2 failed, 8 ignored. Both Rust failures occur while creating symlinks and report Windows error 1314, required privilege not held. No security settings were changed.
  • Corrected decisions and local-harness CLI fixtures pass against main and this branch. The original-main decisions fixture fails its signed-out assertion; its original local-harness CTest entry times out at 120 seconds. Earlier direct loader probes establish missing/mismatched app-local runtime problems, but do not retroactively prove the cause of that timeout.
  • Five rounds of all 26 streaming and 10 network tests pass on each revision, with ordinary thread defaults and stable executable hashes: 180 executions per revision, 36 distinct tests. Earlier full-run streaming failures did not recur; their precise cause remains unestablished.
  • Earlier optional-console full runs had main 605 passed, 19 failed, 8 ignored and the fix 608 passed, 22 failed, 8 ignored. Seventeen account/cloud/local-tool failures came from empty baked console defaults. Valid reserved test-only defaults resolve those failures on both builds. The older failures remain recorded; passing repeats are not a claim that their original cause was fixed.
  • cargo clippy --all-targets --release --locked -- -D warnings: still fails with the same six diagnostics on main and this branch: unused MARK, probe_script, and parse_probe in src/harness/path_reload.rs; three drop_non_drop findings in src/commands/cmd_decisions.rs (lines 1016, 1028, 1036). These unrelated source files are unchanged. Local tracked-symlink consistency is limited by the checkout settings; the preceding published consistency check passes.
  • Preceding CI run: all matrix checks and review statuses passed at 2fab166. The fixture follow-up requires its own fresh CI checks/review; prior green CI does not cover that commit. General CTest/smoke steps are skipped for optional-console fork builds; transaction and focused ownership regressions run unconditionally. Green CI is not full-suite coverage.

Local builds use reserved validation-api.example.test and validation-web.example.test baked origins, mocked account requests and no real keys. Those binaries/ZIPs are validation-only artifacts, not publishable releases. Local VS2019 execution also requires existing SDK/CRT library paths, app-local runtime DLLs and a linker supplement; these setup adjustments are not committed.

No live installation, user PATH/registry change, real user-backup deletion, model inference, or physical power-loss testing is claimed. The full suite is not entirely green. Human review and acceptance of the documented baseline limitations remain outstanding. Cleanup and installer functions have explanatory documentation; the preceding documentation-coverage check passed at 100% against the 80% threshold. A maintainer has been asked to apply bug; labels are not assigned by this update.

Reviewer focus

Receipt publication is the commit point. Review handle-based deletion, Windows sharing behavior, rollback recovery, and preservation of uncommitted recovery files. The two fixture corrections are isolated in their own test-only commit.