room SCROLL applet: live async refresh over WebSocket (not just on page reload)
Some checks failed
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline failed

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>
This commit is contained in:
Disco DeDisco
2026-06-03 02:56:36 -04:00
parent 71c00699a1
commit 8ca3f79561
9 changed files with 187 additions and 23 deletions

View File

@@ -681,6 +681,21 @@ def room_view(request, room_id):
return render(request, "apps/gameboard/room.html", ctx)
def scroll_status(request, room_id):
"""Render JUST the room scroll-of-events feed (`core/_partials/_scroll.html`)
— fetched by room-scroll.js on a `scroll_update` WS nudge so the SCROLL
applet refreshes live without a page reload. Same query + context keys as
the `events`/`viewer`/`scroll_position` block in `room_view`, so the swapped
feed renders identically to the initial paint (the redact filter + buffer
dots are re-applied client-side after the swap)."""
room = Room.objects.get(id=room_id)
return render(request, "core/_partials/_scroll.html", {
"events": room.events.select_related("actor").all(),
"viewer": request.user,
"scroll_position": 0,
})
@login_required
def room_post(request, room_id):
"""Append a Line to the room's game-table thread (the POST view of the