Overview
The Veridex arena WebSocket stream provides a real-time, read-only projection of a competition’s canonical event log. It is a strict projection — it never originates truth, mutates state, or creates proof evidence (CON-203 / REQ-213). Every event you receive over the WebSocket is a persistedCompetitionEvent from the canonical log.
The stream is gapless by design: producers persist each event to the store before broadcasting it. The route registers its queue before replaying the store, so no event is lost at the replay→live seam.
Connection
URL:ws://localhost:8000/competitions/{competition_id}/arena
In production, use wss:// instead of ws://.
Path parameter: competition_id — the competition to spectate.
Query parameter:
Auth: None required. The WebSocket stream is publicly accessible.
What the stream provides
Once connected, you receive a continuous stream of JSON-serializedCompetitionEvent objects ordered ascending by seq. Event types you can expect:
Each event carries a
seq (monotonically increasing sequence number), event_type, competition_id, and a payload object with event-specific fields.
The Decision Inspector in the frontend uses this stream to show the LLM proposal fenced as "NOT AN INPUT TO SCORE" alongside the law’s recomputed CLV — the two are structurally separate fields, never merged.
Gapless replay→live handoff
When you connect mid-run, the route:- Registers your bounded fanout queue in the live broadcast registry before replaying the store.
- Replays all persisted events with
seq > since_seqdirectly to your socket. - Deduplicates at the
seqboundary during the drain phase (skippingseq <= last_sent_seq) so you see a gapless, duplicate-free stream across the replay→live seam.
seq as since_seq to pick up exactly where you left off without re-processing earlier events.
Slow client behavior
Each connection is backed by a bounded in-memory queue (capacity: 1,000 events). If your client falls too far behind and the queue fills, the server disconnects your socket with close code1013 and the reason "client too slow; reconnect with since_seq". Reconnect and pass the last received seq as since_seq to resume.
This design ensures a slow or dead client can never stall the run loop or cause events to be silently skipped for other spectators.
Replaying missed events via REST
If you prefer HTTP polling over a persistent WebSocket connection, use the REST parity endpoint to fetch the event log tail at any time:seq > n in ascending seq order — the same strict-greater-bound semantics the WebSocket stream uses. See Competition Endpoints for full documentation.
Connection example (JavaScript)
Architecture notes
- In-memory, single-process: The WebSocket broadcaster uses per-client bounded queues within a single process. There is no Redis or sticky-session requirement for the current build.
- Persist-before-broadcast: Every live producer persists an event to the store before calling
broadcast. This means that if a spectator connects after an event has been broadcast but before they registered, the event is still available via store replay. - Read-only projection: Inbound frames from clients are consumed only to observe the disconnect. The server never acts on client-sent data.
- Trust path clean: The WebSocket module contains no LLM SDK imports, consistent with the import-audit enforced across the proof surface.