Skip to main content

Ranking Points Pipeline

The ranking points pipeline transforms tournament results into granular point awards. This page documents how getTournamentPoints processes each participant's tournament performance.

Pipeline Overview

Tournament Record
|
v
1. Policy Resolution Find POLICY_TYPE_RANKING_POINTS
|
v
2. Participant Hydration getParticipants({ withRankingProfile: true })
| -> structureParticipation per draw
v
3. Per-Draw Processing For each draw a participant entered:
|
+-> 3a. Profile Selection getAwardProfile (specificity scoring)
+-> 3b. Position Points finishingPositionRanges[accessor]
+-> 3c. Per-Win Points pointsPerWin or perWinPoints (level-keyed)
+-> 3d. Bonus Points champion/finalist bonusPoints
+-> 3e. Quality Wins getQualityWinPoints (ranked opponent bonus)
+-> 3f. Doubles Attribution pair -> individual point distribution
|
v
4. Output personPoints, pairPoints, teamPoints

Profile Selection

When a participant has a structureParticipation entry, getAwardProfile finds the best matching awardProfile from the policy.

Specificity Scoring

Profiles are scored by counting their populated scope fields. A profile that specifies drawTypes, levels, and maxDrawSize (score 3) beats a catch-all profile with no scope constraints (score 0).

Scored fields (1 point each):

FieldMatches Against
eventTypesevent.eventType
drawTypesdrawDefinition.drawType
drawSizesdrawDefinition.drawSize
maxDrawSizedrawDefinition.drawSize <= maxDrawSize
stagesstructureParticipation.rankingStage
stageSequencesstructureParticipation.stageSequence
levelslevel parameter
maxLevellevel <= maxLevel
flightsstructureParticipation.flightNumber
maxFlightNumberflightNumber <= maxFlightNumber
participationOrderstructureParticipation.participationOrder
dateRangesstartDate/endDate within range
category.*Each populated CategoryScope field

Priority override: If any matching profile has an explicit priority number, the highest priority wins regardless of specificity score.

CategoryScope Matching

The category field on an awardProfile uses CategoryScope to match against the event's competitive context:

category: {
ageCategoryCodes: ['U18'], // event.category.ageCategoryCode
genders: ['MALE'], // event.gender
categoryNames: ['Junior'], // event.category.categoryName
categoryTypes: ['AGE'], // event.category.type
ratingTypes: ['WTN'], // event.category.ratingType
ballTypes: ['GREEN'], // event.category.ballType
wheelchairClasses: ['QUAD'], // event.wheelchairClass
subTypes: ['ADVANCED'], // event.category.subType
}

Each field uses contains semantics: if the scope field is present, the event value must be in the array. Absent fields match everything.

Position Points

Position points are determined by the participant's finishingPositionRange — a numeric range representing where they finished in the draw structure.

The Accessor

const accessor = Math.max(...finishingPositionRange);

The accessor is used to look up points in the profile's finishingPositionRanges:

FinishfinishingPositionRangeaccessorPolicy key
Champion[1, 1]11
Runner-up[2, 2]22
SF losers (no 3-4 playoff)[3, 4]44
3rd place (with playoff)[3, 3]33
QF losers[5, 8]88
R16 losers[9, 16]1616
tip

In draws without a 3rd-place playoff (standard single elimination), both semifinal losers get finishingPositionRange: [3, 4] and accessor 4. Set the key 4 value to your intended "semifinal loser" points.

Position Value Resolution

The value at each policy key can be:

  • Simple number: { 1: 1000 } — 1000 points regardless of level
  • Level-keyed: { 1: { level: { 1: 1000, 2: 500, 3: 300 } } } — varies by tournament level
  • Draw size threshold: { 1: [{ threshold: 16, value: 800 }, { threshold: 32, value: 1000 }] } — varies by draw size
  • Flight-specific: { 1: { flights: { 1: 1000, 2: 500 } } } — varies by flight number

Multi-Structure Draws

For draws with multiple structures (FIC, Curtis Consolation, Compass), participants may have structureParticipation entries in multiple structures. The pipeline iterates all entries and takes the maximum position points across structures (see Multi-Structure Draws):

Main draw R2 loser:      accessor 24 -> 75 pts
Consolation SF finisher: accessor 12 -> 150 pts
Final position points: 150 pts (consolation finish is better)

This happens automatically — no special policy configuration is needed for multi-structure draws.

Per-Win Points

Per-win points are awarded when a participation has no position points (the accessor doesn't match any finishingPositionRanges key) or through a dedicated per-win config.

Simple Per-Win

awardProfile: {
pointsPerWin: 60, // flat value per match won
}

Level-Keyed Per-Win

awardProfile: {
perWinPoints: {
level: { 1: 300, 2: 225, 3: 150 }
}
}

maxCountableMatches

Caps the number of wins counted for per-win points per participant per draw:

awardProfile: {
maxCountableMatches: 5,
// or level-keyed:
maxCountableMatches: { level: { 3: 5, 4: 4 } },
}

When a participant has wins across multiple structures (e.g., qualifying + main draw), the cap applies cumulatively across all participations sharing the same award profile.

Bonus Points

Champion and finalist bonuses based on the participant's best finishing position across all structures in a draw:

awardProfile: {
bonusPoints: [
{ finishingPositions: [1], value: { level: { 6: 50, 7: 25 } } },
{ finishingPositions: [2], value: { level: { 6: 30, 7: 15 } } },
],
}

The bestFinishingPosition is Math.min(finishingPositionRange) — the best position the participant could have achieved.

Doubles Attribution

Controls how pair (doubles) points flow to individual participants:

rankingPolicy: {
doublesAttribution: 'fullToEach', // or 'splitEven'
}
ModeEffect
'fullToEach'Each individual receives 100% of pair points
'splitEven'Each individual receives 50% of pair points (rounded)
Not setPoints only on pair record, not distributed to individuals

PointAward Output

Each award in personPoints contains a granular breakdown:

{
positionPoints: 500, // from finishingPositionRanges
perWinPoints: 225, // from per-win config
bonusPoints: 50, // from bonusPoints config
points: 775, // total: position + perWin + bonus
winCount: 3, // total wins in this draw
rangeAccessor: 4, // finishingPositionRange accessor used
eventType: 'SINGLES',
drawId: 'draw-abc',
drawType: 'SINGLE_ELIMINATION',
category: { ageCategoryCode: 'U18' },
level: 3,
startDate: '2025-06-01',
endDate: '2025-06-07',
}