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| Term | Current implementation |
|---|---|
| base_percentile | (N - placement) / (N - 1) |
| exponent | 0.6 |
| max_points | 1000 |
| field_factor | clamp(0.85, 1.30, 1 + 0.15 * ln(N / 20)) |
| race_mode_modifier | first_to_line=1.00, fastest_time=0.95, timed_segments=0.90 |
| event_weight | Organizer-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) / NAthlete 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`