- /card player lookup was a leading-wildcard substring match with a Python
ulower() UDF over 6.16M player_games_hist rows — a full scan measured at
27s live before the ~2s render. Add a prefix fast-path
(nick LIKE 'name%' COLLATE NOCASE) that uses the existing NOCASE index
(~1ms), falling back to the ulower substring scan only when the prefix
finds nothing. Same fix applied to _resolve_player_uids_batch (compare/stats).
Lookup: 27,205ms -> 1ms.
- Completed-season recap cache served ANY cached PNG forever, including files
rendered mid-season (frozen at whatever point they were last viewed). Only
serve from cache when the file's mtime is after season end; otherwise
re-render. Fixed in both BOT/utils.py and web/server.js (shared cache).
- Replace squadron card "Rating change" with "Place finished" (#rank / total),
derived by ranking clans by final total_score among those active in-season.
- Add (CARD)/(RECAP) timing logs for prod observability.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Fix 1: UV_THREADPOOL_SIZE=24 via start_server.sh wrapper (libuv reads OS
environ; process.env and PM2 env blocks don't propagate on this system)
- Fix 2: Stale-while-revalidate for leaderboards — serve cached/stale data
instantly, refresh in background; dedicated aggregateCache isolated from
the 100-entry responseCache; single-flight dedup for concurrent computes
- Fix 3: Background warmer precomputes current + last-completed season
leaderboards at +20s boot and every 4 min
- Fix 5: Adaptive TTL (5 min live, 24 h completed) via aggregateCacheTtl
- Fixes 1+2 combined: player page stall 95s -> 3.6s under concurrent heavy
leaderboard load; warm hits served in 1-4ms (was 13-53s)
A player who changed squadrons could end up with two rows in
squadron_members (old + new clan). Without ORDER BY, LIMIT 1
returned whichever row the primary-key B-tree (clan_id, uid) put
first — i.e. the lowest clan_id, which was the stale entry. This
caused the player page to show the old squadron while the homepage
search (which only reads player_games_hist) showed the correct one.
Fix: add ORDER BY updated_at DESC to both the API roster lookup in
server.js and the web fallback lookup in web/server.js, so the most
recently synced membership always wins.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add a 'Voice channel tally' group to /help with the three commands.
- Add a Voice Channel Tally section to the website docs (docs.ejs).
- Translate the commands.tally bot strings + help_group_tally into all 10
other bot locales, and the new docs.* web strings into all 10 web locales.
- Fix stale need_one_input string (ign/squadron_short -> username/squadron).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Shows paying squadrons as pill links (SHORT // LONG → /squadrons/<short>) above the footer, with a 15-min server-side cache backed by entitlements DB + SQUADRONS.json.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>