Rate limiter fix (limiter.lisp):
- Override simple-rate::tax-rate with fixed-window implementation
The upstream version updates the timestamp on every request, which
prevents the window from ever resetting while polling is active.
This override only updates the timestamp when the window expires and
the counter resets.
- Override rate:left to correctly report expired windows as full budget,
so with-limitation does not block on stale tracking entries.
- These are monkey-patches on r-simple-rate; the upstream library is
not modified.
Polling normalization:
- front-page.lisp: channel-name polling 10s → 15s (matches stream-player.lisp)
Context: In frameset mode, front-page.js and stream-player.js both poll
the channel-name and now-playing endpoints. The sliding-window bug meant
the rate limit counter never reset as long as requests kept arriving
within the 60s timeout, eventually exhausting the budget and producing
429 errors for all API endpoints.
The r-simple-rate library has a bug where rate limit counters can go
negative and never reset. This happens because the reset condition
only triggers when amount >= 0, so negative amounts are permanently
stuck.
This fix adds:
- cleanup-corrupted-rate-limits function to delete corrupted entries
- db:connected trigger to run cleanup automatically on startup
This prevents the 429 error loops that occurred when counters became
corrupted with large negative values.