ADR-0034 — Provider coverage flags are the read-path contract
- Status: Accepted
- Date: 2026-08-27
- Related: ADR-0021 (quarantine over guess), ADR-0033,
docs/architecture/data-plane-integration.md§1 gate 3, §5
Context
TheSports refuses nothing we pay for: 107 of 169 documented endpoints answer, and all 62
refusals map 1:1 onto proposal line items we did not buy. Entitlement is not the
problem. Coverage is — endpoints that answer code: 0 and return thin or empty data
for most matches.
Measured 2026-08-27 from the whitelisted host:
| surface | endpoint | populated |
|---|---|---|
| Football lineups | match/lineup/detail | 2 of 12 live; coverage.lineup set on 117 of 379 (31%) of a day's matches |
| Football post-match player stats | match/player_stats/detail | 2 of 20 finished, across 20 distinct competitions |
| Football post-match team stats | match/team_stats/detail | 2 of 20 |
| Football goal build-up | match/goal/line/detail | 1 of 20 |
| Football text commentary | tlive | 3 of 111 live observations (2.7%), pooled — 0/33 and 0/40 (2026-08-27), 0/12 finished, 3 of 38 distinct live matches (2026-08-29). Competition-gated, see the amendment below |
| Cricket odds | odds/history | 11 of 41 matches (27%), BET365 only, eu only |
| Cricket standings | season/table/detail | 13 of 33 seasons (39%) |
| Cricket brackets | bracket/season | 0 of 33 seasons |
| Basketball standings | season/recent/table/detail | 4 of 8 — exactly the seasons with has_table=1 |
| Basketball shot charts | match/shoot/point | 5 of 12 |
The provider publishes flags that predict this, and they were measured to be reliable:
coverage.lineup— cricket: flag1→ data on 28 of 29, flag0→ data on 0 of 4. Football: exactly the 2 of 12 that carried the flag.season/list.has_table— basketball: predicts standings exactly, 4 of 4 both ways.coverage.mlive— does not predictmatch/live/history. It is not a general-purpose "has data" flag and must not be used as one. Confirmed a second time, on an independent surface, 2026-08-29: it also fails to predict the cricket ball timeline, and from the other direction —8yomo3c8woy9m0jcarriesmlive: 0in the diary while streaming 146 deliveries intimeline[].oversthat grew by 10 in eight minutes, andzp5rzpcogdnpq82carriesmlive: 1and also streams. Cricket ball-by-ball is therefore gated on the presence oftimeline[].oversitself, never on the flag; a flag gate would have suppressed a live, correct, growing feed. A flag that fails to predict on two independent surfaces is not a weak flag, it is the wrong instrument.
The proposal sells against league counts — "1970+ leagues", "All leagues" — and never discloses a coverage tier. That gap is the single largest commercial ambiguity in the contract, and it is also the largest design hazard: a tab designed against the proposal is a tab that is empty most of the time.
Decision
The read path reads the coverage flag before it reads the data, and a field's measured coverage decides whether it is a surface at all.
- Flag-gate the call. Where a flag exists and was measured to predict, the read path
consults it and does not issue the call when it is
0. A flag that does not predict (coverage.mlive) may not be used as if it did. - Three tiers of product commitment, assigned from measured coverage:
- ≥ ~85% — a surface. May be a permanent element. (Cricket lineups 85%; cricket post-match cards 23/23; basketball trend 12/12.)
- ~30–85% — an enhancement. Renders when present, is absent when not, and never occupies a labelled tab or a reserved slot that can be empty. (Football lineups 31%.)
- < ~30% — not a surface. Not built, and not designed. (Football post-match player and team stats 10%, goal-line 5%, cricket odds 27%, football commentary 2.7%.)
- Absence stays absent. A missing value renders as nothing — never
0, never a dash, never the last known number. This isfinancial-security.md§1 applied to display data: a blank score is honest, a stale or invented one is not. - Every coverage number in a design document carries its date and its sample. "2 of 20 finished matches across 20 distinct competitions, 2026-08-27" — not "rare".
Consequences
- Several surfaces that the provider's proposal implies are available are hereby not designed: a football commentary feed, a football post-match statistics tab, a football goal-map, and a cricket odds surface.
- Cricket odds are explicitly out: 27% of matches, one book, moneyline only, with
asiaandbsnever returned across 41 matches. A 27%-covered price is worse than no price. - Coverage ratios must be re-measured before any surface is promoted between tiers, and the measurement is cheap — one sweep from the whitelisted host.
- The coverage boundary is the strongest item to put to the provider commercially: which competitions are in our coverage for lineups / player stats / goal-line, and what tier expands it.
Amendment — 2026-08-29: the tlive evidence was wrong, the decision is not
The evidence is corrected. The tier assignment and the decision are unchanged.
This ADR recorded football tlive as 0 of 33 live and 0 of 12 finished and called it
"never once" — an absolute claim resting on three null probes. It is false. Re-measured
2026-08-29 02:31–02:41 UTC over 38 distinct live matches, tlive is populated on 3, with
real English commentary at minute granularity:
"45'+7' First Half ends, Necaxa 0, Cruz Azul 1.""2' Attempt blocked. Daniel González (CF Atlante)'s right foot shot. Jhojan Julio assists."
Pooled over the same population and stated with dates — 0/33 and 0/40 (2026-08-27), 0/12 finished, 3/38 (2026-08-29) — that is 3 of 111 live observations, ≈ 2.7%. Still tier 3, still not a surface, still not built. A single snapshot read in isolation gives 3/26 = 11.5%, which is above this ADR's own 10% bar and would not have carried the conclusion; the pooled figure is the defensible one.
But the shape is coverage, not noise, and that is the part worth recording. Joined to
football/match/diary, all three sit in two competitions and those competitions are fully
covered:
| competition | live matches in window | with tlive |
|---|---|---|
9k82rekhp6repzj | 2 | 2 (100%) |
p3glrw7hevqdyjv | 1 | 1 (100%) |
| all 30 others found in the diary | 30 | 0 |
No coverage flag predicts it. The payload carries only mlive, lineup and gif. All
three tlive matches have lineup: 1 — but so do 10 matches without it (3 of 13 = 23%,
useless as a gate). gif: 1 appears on 2 of the 3 and on only 1 of the other 30, but the
third tlive match has gif: 0, so it does not predict either.
The general rule this adds to §1. Where a flag exists and predicts, gate on the flag.
Where no flag predicts but the payload itself proves presence, gate on the payload:
render the surface if and only if the field is non-empty for this match, inline and
self-gating, never as a labelled tab. Do not build a hand-maintained competition allowlist
— it encodes a snapshot of provider coverage and rots silently as that coverage moves. The
cricket ball timeline is gated this way for the same reason (see the mlive bullet above).