The room's scroll-of-events feed only updated on refresh — a gamer
watching the SCROLL view never saw a co-player's deposit / role pick /
sig appear. Now every recorded GameEvent nudges all open room sockets to
re-fetch the feed.
- drama.models.record() broadcasts a `scroll_update` to the `room_<id>`
group via transaction.on_commit — so the live re-fetch sees the
committed row, and a rolled-back TestCase never fires it (zero overhead
/ channel-layer traffic for the plain IT suite). _broadcast_scroll_update
is fully guarded: a missing/unreachable channel layer must NEVER break
event recording (falls back to refresh-to-update). One central hook
covers every event writer, current + future.
- RoomConsumer gains a `scroll_update` relay handler (same one-liner shape
as gate_update / turn_changed).
- New `scroll_status` view + url (epic:scroll_status,
room/<id>/scroll/status) renders JUST core/_partials/_scroll.html with
the same events/viewer/scroll_position context as room_view's inline
paint, so the swapped feed is identical.
- room-scroll.js listens for `room:scroll_update`, fetches the partial,
swaps #id_drama_scroll, then re-applies the saved Frame/Redact filter +
restarts the buffer dots on the fresh nodes. URL comes from
.room-page[data-scroll-status-url]. Refactored the dots + filter into
re-runnable helpers; existing behavior (title reel IO, filter form,
localStorage) preserved.
TDD:
- drama RecordBroadcast ITs: record() schedules the broadcast on commit
(captureOnCommitCallbacks execute=True) and NOT before commit.
- RoomConsumer relays scroll_update (InMemory layer, WebsocketCommunicator).
- ScrollStatusViewTest: endpoint renders the feed section, reflects the
latest events, is the bare partial (no navbar/aperture chrome).
544 drama+epic ITs green — the on_commit hook is inert under TestCase, so
no existing event-writer test regressed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>