Quick statuses in General Settings not auto clearing after set interval #227

Closed
opened 2026-09-21 18:54:22 -04:00 by jared · 1 comment
Owner

Have claude deep dive this

Have claude deep dive this
jared added the bugarea: settingspriority: medium labels 2026-09-21 18:54:43 -04:00
Author
Owner

Deep dive done — reproduced and fixed in e393c45f.

Root cause. The auto-clear (StatusExpiryMonitor, ClientNonUIFeatures.tsx:375) did this, in this order:

localStorage.removeItem(msgKey);
localStorage.removeItem(expiryKey);
mx.setPresence({ …, status_msg: '' }).catch(() => undefined);   // ← swallowed

It threw away the record before the write and swallowed any error. Synapse rate-limits presence to ~1 write per 10 s per user (rc_presence, the same limit behind #226) and our own presence heartbeat spends that budget, so a 429 here is routine — especially at startup, where the monitor's first check() fires right next to the initial heartbeat. One 429 and the clear was gone forever: the server kept the status and nothing local remembered it was supposed to expire.

Reproduced headlessly by injecting three 429s on the presence PUT: the status stayed 🎮 Gaming on the server indefinitely while lotus-status-* in localStorage was already empty — no retry, no second chance, exactly the symptom.

Fix. The clear now goes through setPresenceWithRetry (the #226 helper — honours retry_after_ms, bounded wait) and only removes the localStorage keys after the server has taken the write; a re-entry guard prevents overlapping attempts, and the poll interval is 15 s (was 30 s) so a retry lands promptly. Re-ran the same 429 injection: the status clears.

Two things that remain by design, worth knowing:

  • The expiry is device-local. If you set a status and never open Lotus again, nothing clears it — the next launch does (the monitor checks once on mount).
  • A status set on device A expires on device A's timer; device B has no record of it. Making that server-side would need a custom account-data event; say the word if you want it.
Deep dive done — reproduced and fixed in e393c45f. **Root cause.** The auto-clear (`StatusExpiryMonitor`, `ClientNonUIFeatures.tsx:375`) did this, in this order: ```ts localStorage.removeItem(msgKey); localStorage.removeItem(expiryKey); mx.setPresence({ …, status_msg: '' }).catch(() => undefined); // ← swallowed ``` It threw away the record **before** the write and swallowed any error. Synapse rate-limits presence to ~1 write per 10 s per user (`rc_presence`, the same limit behind #226) and our own presence heartbeat spends that budget, so a 429 here is routine — especially at startup, where the monitor's first `check()` fires right next to the initial heartbeat. One 429 and the clear was gone forever: the server kept the status and nothing local remembered it was supposed to expire. **Reproduced** headlessly by injecting three 429s on the presence PUT: the status stayed `🎮 Gaming` on the server indefinitely while `lotus-status-*` in localStorage was already empty — no retry, no second chance, exactly the symptom. **Fix.** The clear now goes through `setPresenceWithRetry` (the #226 helper — honours `retry_after_ms`, bounded wait) and only removes the localStorage keys **after the server has taken the write**; a re-entry guard prevents overlapping attempts, and the poll interval is 15 s (was 30 s) so a retry lands promptly. Re-ran the same 429 injection: the status clears. **Two things that remain by design**, worth knowing: - The expiry is device-local. If you set a status and never open Lotus again, nothing clears it — the next launch does (the monitor checks once on mount). - A status set on device A expires on device A's timer; device B has no record of it. Making that server-side would need a custom account-data event; say the word if you want it.
jared closed this issue 2026-09-23 15:42:00 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#227