accepted

PercentileBar always renders percentiles on the upward scale; inversion happens upstream

The bar geometry never inverts. A metric with `percentile: 15, originalDirection: "lower"` renders a 15% bar plus a "lower is better" badge — not an 85% bar. The chart owns rendering; the caller owns statistical correctness.

PercentileSurfaces chart-apidata-integrityfootball-semantics

Context

Lower-is-better metrics (errors, fouls committed, tackles lost) can be rendered two ways:

  • Invert inside the chart — errors-percentile-15 becomes a bar at 85%. The visual reads “good player”. But now the chart is doing a semantic flip that depends on a direction field; consumers who accidentally double-invert (flip upstream, flip again in the chart) get silent wrong answers.
  • Render the raw percentile, badge the direction — errors-percentile-15 renders a short bar with a “lower is better” annotation. The visual reads “bottom-15% errors = great”. One direction, no double-flip risk.

Double-flip silently-wrong is the worse failure. Ambiguous bars with no badge are the weaker but more common failure mode.

Decision

  • percentile is always display-scale (0 at the left, 100 at the right).
  • originalDirection: "lower" renders an inversion badge and an accessibility note, never flips the bar.
  • Callers (scouting layer, adapter) own any inversion needed before passing percentiles to the chart.
  • aria-label reads “Player A, errors, 15th percentile (lower is better)” — screen readers get the direction without visual inference.

Consequences

  • Callers pre-compute percentiles against the correct direction; the chart stops being a semantic trap.
  • Inversion bugs become visible: a bar at 15% with no “lower is better” badge is obviously an un-inverted error metric, not a silent wrong answer.
  • Future provider adapters that surface percentiles directly (some ship playerScout endpoints with pre-computed percentiles) feed the chart without transformation.
  • Composition with RadarChart / PizzaChart follows the same rule — all percentile-consuming charts assume display-scale input.
← All decisions