a6ce20761b731737771f569f631112d0a2632d32
The flaky tray→thumbnail→hex animation after the 12s countdown. Root cause: the confirm ran in a threading.Timer thread inside the web process, and _fire broadcast polarity_room_done / pick_sky_available via async_to_sync(group_send) from an ephemeral per-call event loop. With the Redis channel layer that publish is unreliable across loops (the production analog of the "broadcast must originate in daphne" test trap), so the live events reached the client only sporadically — the server-side state (sig assignment, SKY_SELECT) still committed, which is why a refresh always showed the concluded hex but the animation usually didn't play. Fix (chosen: migrate to Celery — the path the tasks.py docstring already called for): _fire becomes the @shared_task confirm_polarity_room, enqueued by schedule_polarity_confirm via apply_async(countdown=seconds). The worker is a stable long-lived process whose channel-layer singleton is never shared with a serving loop, so its group_send reaches daphne reliably; it also survives web-worker restarts. No task revocation needed — cancellation/supersession ride the existing cache token guard (cancel just deletes the token; a stale queued task no-ops). Dropped threading.Timer + the _timers registry. Test settings get CELERY_BROKER_URL='memory://' so apply_async queues without a live Redis and without running the task (no worker) — mirrors the old timer that was scheduled but never fired inside a sub-12s test. NOT eager: eager would ignore the countdown and assign significators synchronously during the ready POST. test_tasks rewritten: confirm_polarity_room called directly (task body), schedule asserts the enqueue + countdown + fresh-token supersession; the broadcast itself stays IT-uncoverable under InMemory (known channels limit). Also: room.js now auto-reconnects the room WebSocket with capped exponential backoff (1s→30s, reset on open, halted on beforeunload). A dropped socket (proxy idle-timeout, blip, server restart) previously stayed dead until a manual refresh, silently losing every live event — an independent reliability gap that compounded the "sporadic" feel. 602 epic ITs + 18 task UTs green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Description
No description provided
Languages
Python
45.5%
JavaScript
36.1%
HTML
9.6%
SCSS
8.6%
Jinja
0.1%