Description
StateManager.load() (app/state.py) handles a corrupt or version-mismatched state file by logging a warning and returning empty state. There is no .bak, no recovery attempt, and no migration path for STATE_VERSION changes - a bump wipes everyone's state on upgrade.
Losing state resets every pending leaving-soon timer (items get their full duration again) and re-sends already-sent leaving-soon notifications. Not an over-deletion risk (the duration filter fails safe), but real user surprise and notification spam.
Proposed Fix
- Keep a
.bak copy on every successful save; on corrupt read, attempt recovery from it before falling back to empty
- Add a version migration path so a
STATE_VERSION bump migrates instead of wiping
- Log loudly (and notify) when state is actually reset, since timers restarted
Description
StateManager.load()(app/state.py) handles a corrupt or version-mismatched state file by logging a warning and returning empty state. There is no.bak, no recovery attempt, and no migration path forSTATE_VERSIONchanges - a bump wipes everyone's state on upgrade.Losing state resets every pending leaving-soon timer (items get their full duration again) and re-sends already-sent leaving-soon notifications. Not an over-deletion risk (the duration filter fails safe), but real user surprise and notification spam.
Proposed Fix
.bakcopy on every successful save; on corrupt read, attempt recovery from it before falling back to emptySTATE_VERSIONbump migrates instead of wiping