The updater promises to wait for active work, but only scans set appState.busy. Quarantine, restore, and purge leave it false, so the app can offer an update and restart while one of those actions is still running.
app/src/updater.js relies on this flag:
await update.download();
if (appState.busy) return;
// User confirms, then install() and relaunch().
In app/src/App.jsx, doQuarantine(), restore(), and purge() never update the flag. A mocked run of the actual updater with that idle state reaches download -> confirm -> install -> relaunch.
Expected: updating must wait until all scan and file operations finish, including failures. Prevent new operations once installation/restart starts.
Use a shared operation counter or equivalent ownership mechanism: a boolean set to false by the first finishing action is not enough when two rows are working at once.
Done when: tests keep each action pending and verify that install/relaunch are deferred; overlapping actions stay busy until both finish; rejected actions release their busy state. Test with mocked updater calls, without actually restarting the app.
Confirmed on 8abd5cb. This report establishes the missing coordination; it does not claim observed file loss.
The updater promises to wait for active work, but only scans set
appState.busy. Quarantine, restore, and purge leave it false, so the app can offer an update and restart while one of those actions is still running.app/src/updater.jsrelies on this flag:In
app/src/App.jsx,doQuarantine(),restore(), andpurge()never update the flag. A mocked run of the actual updater with that idle state reachesdownload -> confirm -> install -> relaunch.Expected: updating must wait until all scan and file operations finish, including failures. Prevent new operations once installation/restart starts.
Use a shared operation counter or equivalent ownership mechanism: a boolean set to false by the first finishing action is not enough when two rows are working at once.
Done when: tests keep each action pending and verify that install/relaunch are deferred; overlapping actions stay busy until both finish; rejected actions release their busy state. Test with mocked updater calls, without actually restarting the app.
Confirmed on
8abd5cb. This report establishes the missing coordination; it does not claim observed file loss.