fix(profile): retry a failed read; require reversibility for unattended writes
Testing the round trip turned up a defect the unit tests could not: a single transient failure of `read_current` silently converts a reversible write into a one-way one. The write still succeeds, `previous` is None, and nothing says so until someone tries to undo it. Seen for real -- `PowerGetActiveScheme` failed once while several compiles were running, then read normally on the next attempt, which is also why the fix is a retry rather than a redesign. `read_current_with_retry` gives a flaky source three chances. `apply_setting_reversible` refuses outright when the prior value still cannot be read, and `tuning::serve` uses it for every unattended write: a loop with nobody watching must not make a change it cannot take back. `apply_setting` keeps the old behaviour for attended callers, who can be told the write is one-way and decide for themselves. Tests added while hunting this: - read -> parse -> format round-trips for the Windows GUID, including the all-zero and all-ones edges. This is the seam a revert crosses and it is invisible if only one side is tested: `read_current` formats with Debug, `apply` parses with `parse_guid`, and nothing forces them to agree. - malformed GUIDs are rejected rather than truncated into a valid-looking different one. - 2000 concurrent reads across 8 threads, because `read_current` allocates and frees Win32 memory on every call and the tuning loop calls it every cycle; a mistake there is heap corruption showing up somewhere else. - the retry itself, with a handler that fails once and one that always fails. - an ignored end-to-end test that applies, verifies, reverts and verifies again against the real machine. Ignored because it writes; run with `cargo test --all-features --lib -- --ignored round_trip`. Verified by hand beyond the suite: the round trip moved this machine Balanced -> High performance -> Balanced, `powercfg /getactivescheme` independently confirmed it was returned to where it started, and the audit log carries `previous` on both entries, so a revert is reconstructible after a restart rather than only in-process. 860 tests, 6 consecutive clean runs of the lib suite (4,404 executions, no flake), clippy -D warnings clean, release build and docs checked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A
Adam Erickson committed
0d7057a1e41b6559375613d9aca3b7a80bd342bb
Parent: 833df1e