ADR-0024: Viewed fixtures outrank in-play fixtures in Betfair stream cap truncation
Date: 2026-07-29 Status: Accepted
Context
A single Betfair stream subscription is hard-capped at 200 markets
(MAX_MARKETS_PER_SUBSCRIPTION, BetfairStreamClient). When classified demand exceeds the cap,
StreamManager.desiredMarketMembership truncates at fixture granularity by priority tier.
The original tier order was IN-PLAY (1) > VIEWED (2) > rest (3).
On 2026-07-29 prod carried ~191 baseline in-play markets (20 live soccer + 13 tennis fixtures).
A client actively viewing and betting The Hundred fixture 35871459 (MI London v London Spirit)
pushed demand to 204–207; truncation skipped exactly that fixture because it ranked below
unwatched in-play soccer. Result: frozen exchange odds on the client's screen, and bets placed
at stale prices that lapsed (2 orders) or sat unmatched for up to ~25 minutes. The in-play
discovery poll (listMarketCatalogue, inPlayOnly, maxResults: 200, FIRST_TO_START) is
itself saturated on such evenings, so the cricket fixture never enters the in-play tracked set
and can only stream via viewer interest — which the old ordering then sacrificed first.
Decision
Viewed fixtures (refCount > 0 — a player has the fixture open over WebSocket) are ALWAYS the
top truncation tier. In-play fixtures come second. Grace/rest remain third. Within a tier the
ordering is unchanged: earliest subscribedAt, then fixtureId. Whole-fixture greedy truncation
is unchanged.
A fixture that is both viewed and in-play ranks in tier 1 (refCount is checked first).
Consequences
- A fixture a player is actually looking at can no longer be displaced from the stream by unwatched in-play fixtures; live prices follow the player.
- Under sustained over-cap demand, enough concurrent viewers on distinct fixtures can displace ALL unviewed in-play fixtures. Odds/volume logging to TimescaleDB (fraud detection) pauses for displaced fixtures while demand stays over the cap. Accepted: player-facing correctness beats background logging coverage.
- The residual pressures are NOT addressed here and remain follow-ups: the 200-market stream cap itself, in-play poll saturation (cricket never auto-streams on busy soccer evenings), per-fixture market budgeting, and multi-connection streaming.