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
directionfield; 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
percentileis 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-labelreads “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
playerScoutendpoints 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.