Skip to main content

ADR-0033 — TheSports is the single score authority; Roanuz is retired

  • Status: Accepted
  • Date: 2026-08-27
  • Supersedes: Roanuz as a live cricket data source
  • Related: ADR-0032, ADR-0035, docs/architecture/data-plane-integration.md §3, §8

Context​

Hannibal has carried two cricket data providers. Roanuz predates TheSports and owns the ball-by-ball UI path end to end. TheSports was integrated in August 2026 as a four-sport display feed (cricket, tennis, soccer, basketball).

Roanuz is already off in every environment — ROANUZ_ENABLED=false in dev, dev1, dev2, staging and prod, verified in the running containers and on disk 2026-08-22; the code default is false; backend/src/exchanges/index.ts:267 is the only construction site, so getRoanuzProvider() returns undefined and every consumer routes through that one function. Zero Roanuz API or WebSocket traffic in 24h across all four running environments.

But ball-by-ball is still Roanuz-wired, and therefore dark. It has no second feed: routes/cricket.ts:125 resolves to Roanuz, gets null, and returns a 404 that hides the whole live-feed section. Real users hit this — prod 1 subscribe → 404, dev 20 → 404.

Meanwhile everything needed to replace it exists and has zero production callers: ballGlyph(), describeBall(), currentRound() and formatIncidentMinute() in strykr-fe/src/lib/theSportsDetail.ts, the 28px ball-pill strip in LiveFeedSection.tsx, and the CricketBall / CricketInningsTimeline types. Cricket timeline[].overs and .wickets are flowing over MQTT right now.

Running two score authorities is not a hedge. It is two decoders, two identity schemes, two sets of coverage assumptions and an unanswerable question whenever they disagree.

Decision​

TheSports is the sole authority for score, phase, per-period splits, timeline, ball-by-ball and match statistics, for all four sports. Roanuz is retired.

Betfair and Bifrost remain the sole authority for fixture existence, orientation, markets, prices, exposure and settlement. The data plane is structurally barred from all of those: TheSportsDataAdapter implements IMultiSportDataProvider, which has no odds, order or settlement surface, and cannot join the exchange ProviderRegistry (typed to IExchangeAdapter). The firewall is a type, not a naming convention.

The cutover runs in dependency order:

  1. Replace the resolveToRoanuz gate in routes/cricket.ts with a TheSports match resolution off thesports_fixture_links.
  2. Repoint LiveFeedSection from Roanuz's CricketBallUpdate to TheSports timeline[].overs / .wickets, through decodeBallsPerRound() — timeline[] position 2 is "number of rounds", not overs, and The Hundred uses 5-ball rounds.
  3. Re-home or retire the non-ball-by-ball consumers of ballByBallService.
  4. Delete adapters/roanuz/ and the ROANUZ_* config block.
  5. Revoke the Roanuz credentials at the provider and strip them from every .env.

Roanuz may be deleted only when all five of these are true:

  • cricket ball-by-ball renders from TheSports on a live fixture, observed;
  • no route, service or job calls getRoanuzProvider();
  • matchGradeService / tossAnalysisService / cricketAnalysisService each have a TheSports source or are explicitly retired as products;
  • player photos have a source or an explicit fallback (TheSports player/list.logo is 59% populated for cricket; the Roanuz team-images JSON asset is currently the fallback);
  • credentials revoked.

Consequences​

  • tossAnalysisService has no replacement feed and must be retired, not ported. TheSports carries no toss information on any endpoint, for any sport. This is a product decision that the cutover forces and that nobody has yet made.
  • Cricket ball-by-ball becomes subject to the three-gate chain (ADR-0032): a fixture must be classified and linked before a ball can be drawn on it.
  • The 404 that currently hides the live-feed tab is separately wrong in its copy (routes/cricket.ts:135 claims "Only major international matches are supported"). That is a user-facing defect with its own ticket, deliberately not bundled into step 1.
  • Dormant provider credentials in five .env files become a credential-hygiene item with an owner.