de0d2c80cd
Audit findings M-3 and M-4. The 24h auto-sweep launched from Plugin's constructor and the manual button in the Privacy tab were both starting a background thread that called DeleteByRetentionPolicy on the shared MessageStore connection without coordinating. With unfortunate timing — manual click moments after a fresh plugin load — two sweeps would race for the same connection and the second would just re-do work the first one already did, while still overwriting RetentionLastRunAt. Move the running flag and a lock object to Plugin so both paths see the same gate. Each entry point takes the lock long enough to check and set the flag, then runs the actual delete on its background thread without holding the lock (other DB operations already happen without locking; spreading the lock further would suggest a guarantee we do not actually provide). The Privacy tab keeps a read-only property that surfaces the shared flag for its UI disable state — ImGui is single-threaded and bool reads are atomic, so the lock-free read is fine.