Ranking Methodology

This page is the source of truth for how points and rankings are currently computed in production.

1. Event points

For each valid finisher, event points are computed with the formula below.

event_points = (base_percentile ^ exponent) * max_points * field_factor * race_mode_modifier * event_weight
TermCurrent implementation
base_percentile(N - placement) / (N - 1)
exponent0.6
max_points1000
field_factorclamp(0.85, 1.30, 1 + 0.15 * ln(N / 20))
race_mode_modifierfirst_to_line=1.00, fastest_time=0.95, timed_segments=0.90
event_weightOrganizer-defined multiplier, configured per event at creation time (default 1.0).

2. No time decay

Rankings do not apply recency decay. Once an event result is in a season, its points contribute at full value for that season.

3. Aggregation to ranking score

N = clamp(3, 8, floor(total_results * 0.6))
ranking_score = sum(top N event_points) / N

Athlete is marked provisional when total results are below the minimum required results (currently 3 by default).

Worked examples

Example A: Winner in a 100-person first-to-line event

base_percentile=1.0, field_factor≈1.241, mode=1.00 -> points≈1241.4

Example B: 10th place in a 50-person fastest-time event

base_percentile=(50-10)/49≈0.816, curved≈0.886, field_factor≈1.137, mode=0.95 -> points≈956.8

Example C: Event weight effect

same base score 1000 points with weight 1.3 -> 1300 points; with weight 0.9 -> 900 points

Example D: 9 results aggregation

N=floor(9*0.6)=5; if top 5 event points are [1200,1100,980,950,900], score=(5130/5)=1026.0

Scope and grouping

Rankings are computed per season + discipline, with additional rank positions by gender and age group.

Seasons are calendar years (for example, 2026: January 1 to December 31).

Implementation reference

  • `public.compute_event_points(target_event_id uuid)`
  • `public.compute_athlete_ranking(target_athlete_id uuid)`
  • Tables: `events` (weight), `results`, `ranking_snapshots`, `ranking_event_details`, `ranking_seasons`

Go to live rankings