2 months ago
cd520d8* fix(config): atomic write + corruption recovery to end the boot brick (#208) `save_config` truncated-then-wrote config.json in place with a plain `fs::write` — no temp file, no fsync, no atomic rename. A kill, OS sleep, or power loss mid-write (or a concurrent settings save) left config.json 0-length or partial. `load_config` then returned `Err` on any parse failure and `setup_app` propagated it with `?`, aborting Tauri startup. The result was an unrecoverable boot brick from a single interrupted save: all settings lost AND the app refused to launch on every run. - save_config now writes to a unique sibling temp, fsyncs it, atomically renames over config.json, then fsyncs the parent dir — reusing the write-temp + fsync + rename pattern from remote::atomic_download. A crash at any point leaves the previous config fully intact or the new one fully written, never a truncated file. Unique temp names also make two racing saves unable to interleave bytes into one renamed file. - load_config now quarantines an unparseable config.json to config.json.corrupt-<unix-millis>, logs a warning, and returns Ok(None) so callers fall back to defaults instead of erroring. This covers 0-length, truncated, and garbage files. - setup_app treats any config load error as recoverable (defaults + warning) rather than `?`-aborting startup. Tests: corrupt/empty config recovers to Ok(None) and is quarantined; post-recovery save round-trips; an interrupted save (bytes only in the temp) leaves the committed config byte-for-byte intact; successful saves leave no temp residue and overwrite cleanly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(settings): inject persistence failure at the config directory (#208) The two EQ persistence-failure tests made config.json itself read-only to force save_config to fail. The atomic write introduced in this branch replaces config.json via a temp-file + rename, and on Unix rename is governed by the directory's write bit, not the target file's — so a read-only file no longer fails the save. The tests saw an unexpected success and panicked (settings.rs:955/:1013), and the coordinator revert command was never sent, panicking the responder task (settings.rs:677/:696). Switch the injection to a read-only config directory (0o555), which fails the atomic save's temp-file create and genuinely drives the persist-fail -> coordinator-revert path. Directory permissions are restored afterward so TempDir cleanup succeeds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Parentf1afa6e