accepted

BumpChart input ranks must be 1..N ordinal; no auto-derivation from raw metrics

`BumpChart` expects a `rank` field that is already a discrete 1..N ordinal. It never derives rank from `points` / `goals` / `xG` internally. Tie-breaking (dense vs min vs max) is a narrative choice and lives upstream; the chart refuses to own it.

BumpChart data-integrityapifootball-semantics

Context

Auto-ranking inside the chart sounds convenient — pass points, get a bump chart — but it hides the tie-breaking rule. Two clubs on 42 points with the same goal difference: are they both rank 3, or one rank 3 and one rank 4? Dense ranking, min, max, and average all have football-editorial justifications, and different competitions break ties differently (goals scored, head-to-head, draws). Baking any of them into the chart picks a narrative the consumer didn’t ask for.

Decision

rank is required input, strictly 1..N. Values ≤ 0 or > totalTeams emit [rank.invalid] and exclude the row. Raw metric fields (points, etc.) pass through to tooltips and labels but never drive rank. Ranking, including tie-breaks, happens upstream in an adapter or aggregation step.

Consequences

  • [rank.invalid] is added to the warning taxonomy; consumers can filter the code to detect malformed inputs.
  • The chart stays honest about what it’s plotting — the input rank is the rendered rank. No hidden transformations.
  • Standings-specific logic (head-to-head, GD tie-breaks) lives in the ingestion layer. Campos ships no league-table aggregator today.
  • Consumers combining rank traces from different sources must align on a tie-breaking rule before passing to the chart; the chart can’t detect mismatches.
← All decisions