Skip to content

Rating and Debrief

The flight rating is a score from 0 to 1000 with a band word, built from four part scores of 0 to 100 each: climbing, gliding, speed and decisions. The pilot sees it on the gauge at the top of the Debrief, on the Debrief’s section cards and in the Rating section of Compare. The Debrief then answers a set of fixed questions, one section per part plus a Task section. Every number comes from the flight’s own analysis. No glider polar and no model is involved. The behaviour is described in the feature page Debrief and flight rating.

iOS is the reference. Android (:domain:debrief) is a line-by-line port: the same formulas, the same constants and the same floating-point order, with Swift’s rounded() reproduced as round-half-away-from-zero. Each section below says “same as iOS” unless a difference is listed.

Inputs this page relies on, specified elsewhere:

InputSpecified in
Thermal fields: vario (the thermal’s average climb), duration, altitudeGained, isAttempt (altitudeGained ≤ 0), altitudeLost, turn, entryTime, fixesFlight analysis §2.3, §5.3–5.4
Leg (glide) fields: distance (a 5-turnpoint optimised distance, not the path length), altitudeDifference, averageSpeed, averageGlideRatioFlight analysis §2.4, §5.5
Take-off, release, landing, engine runsFlight analysis §5.1
Wind per thermalFlight analysis §5.4
Free distance and its average speed; best one-hour optimisationFlight analysis §6, §7.6
Best task attempt, isCompleted, averageSpeed, start and finish height and ground speed, averageGlideRatio, averageCruiseSpeedFlight analysis §2.8, §7.5
Terrain elevation per fix, isElevationAvailableFlight analysis §8.1
The flight’s average glide ratio and cruise speedFlight figures
Leader analysis (thermal matching) and leeching analysisFlight analysis §2.9, Compare, ranking and statistics
Distances between coordinatesFlight analysis §7.1
Formatting (units, timeValue, percentageValue)Flight analysis §9

1. The scope: the task, or the whole flight

Section titled “1. The scope: the task, or the whole flight”

Most calculations read a scope of the flight rather than the whole track.

  • If the flight has a best task attempt whose first fix is earlier than its last fix, the scope is the time range [first.rawTime, last.rawTime] of that attempt’s fixes. Answers read over this scope say “On task” before their summary.
  • Otherwise the scope is the whole flight.
Scope valueDefinition
Thermal in scopeIts first fix’s rawTime (or entryTime without fixes) lies in the range
Glide in scopeIts start fix’s rawTime lies in the range
thermalsThe real thermals (actualThermals: isAttempt == false) in scope, in time order
allThermalsEvery thermal in scope, attempts included
averageClimbΣ altitudeGained / Σ duration over allThermals, m/s; nil when Σ duration = 0
thermalCountallThermals.count
thermallingTimeΣ duration over allThermals, s
thermallingSharethermallingTime / total × 100, where total is the range length on a task, else flight.duration; nil when total ≤ 0
thermals(turning:)For one turn direction: count; climb Σ altitudeGained / Σ duration of those thermals (nil if the duration is 0); share count / allThermals.count × 100 (nil with no thermals)
fixesThe fixes whose rawTime lies in the range (all fixes without a task)
lowestFix, highestFixMinimum / maximum pressureAltitude over fixes; without a task the flight’s own lowest and highest fix
windThe flight’s wind estimates (keyed by thermal entry time) whose key lies in the range

The release time is the release fix’s rawTime; without a release, the take-off’s rawTime + 600 s; without a take-off, 0.

soaringFixes are the scope’s fixes with rawTime > release and rawTime ≤ the last fix of the scope’s last real thermal. There are none when the scope has no real thermal. This keeps the tow and the landing approach out.

soaringLowestFix:

  • With terrain loaded (isElevationAvailable): the soaring fix with the smallest pressureAltitude − elevation.
  • Without terrain: the soaring fix with the smallest pressureAltitude.

heightAboveGround(fix) = max(0, pressureAltitude − elevation) in metres, or nil without terrain.

Ties in a minimum or maximum keep the first element in time order, on both platforms.

Source: vulture-ios/Packages/FlightScreens/Sources/FlightScreens/FlightDebrief/FlightScope.swift (FlightScope); vulture-android/domain/debrief/src/main/kotlin/be/fousa/vulture/domain/debrief/FlightScope.kt. Same as iOS.

Every part maps a figure onto 0–100 with one helper:

scaled(value, low, high) = clamp((value − low) / (high − low) × 100, 0, 100)
scaled(value, low, high) = 0 when high == low

low scores 0 and high scores 100. low may be larger than high for a figure where less is better.

A part that has nothing to read from returns no score. It is left out of the rating, and its card says “Not rated”.

What the pilot sees: “2.15 m/s · 71 % of your best climb · 9 min lost in weak climbs”.

Conditions (otherwise no climbing score):

  • At least 4 real thermals in scope (scope.thermals.count ≥ 4). A ridge or wave flight is not rated on its climbing.
  • scope.averageClimb exists.
  • The best lift exists and is greater than 0.
  • scope.thermallingTime > 0.

Best lift (the day’s best climb as a pilot means it):

  1. Take the real thermals in scope that lasted at least 120 s. If fewer than 2 did, take all real thermals in scope.
  2. Sort their vario values from high to low.
  3. Take the top max(2, n / 4) values (integer division).
  4. Best lift = the mean of those values.

Time lost in weak climbs (also the “Where I lost time” answer, §4.2):

for each real thermal in scope with vario < averageClimb and altitudeGained > 0:
lost = duration − round(altitudeGained / averageClimb) (seconds)
keep it if lost > 0
total lost = Σ lost

Nothing is lost when averageClimb is missing or ≤ 0.

Score:

liftUsed = averageClimb / bestLift
lostShare = totalLost / thermallingTime
climbing = round(0.6 × scaled(liftUsed, 0.35, 0.75) + 0.4 × scaled(lostShare, 0.30, 0.0))
ConstantValueMeaning
Minimum real thermals4Below it, no score
Lasting thermal120 sDuration for the best-lift sample
Best-lift sampletop max(2, n/4)Of the lasting thermals
Lift used: 0 points0.3535 % of the best lift
Lift used: 100 points0.7575 % of the best lift
Lost share: 0 points0.3030 % of the thermalling time lost
Lost share: 100 points0.0Nothing lost
Weights0.6 / 0.4Lift used / lost share

Facts on the card: the average climb; “x % of your best climb” (liftUsed as a whole percentage); and “t lost in weak climbs” (in hours and minutes) only when totalLost > 0.

Note that averageClimb includes the attempts (height and time), while the best lift and the time lost read only the real thermals.

What the pilot sees: “18.4 km detour (12 %) · L/D 42:1”.

The gliding score measures how far the cruise track went beyond the straight line.

The line and the detour:

  • Task: if the flight has a task and a best task attempt with distance > 0, the line is the attempt’s distance. The detour is the sum of the per-leg detours of the task’s legs (OptimizedLeg.detourDistance, a leg without one counts 0).
  • Otherwise: if the free distance is greater than 0, the line is the free distance. The detour is the whole-flight detour (below), or 0 when that is nil.
  • Otherwise there is no gliding score.

If the line is shorter than 10,000 m, there is no gliding score.

Cruise track length. Both detours walk a list of fixes and collapse every thermal into a straight line:

cruise = 0; i = 1
while i < fixes.count:
if fixes[i] belongs to a thermal T:
last = index of T's last fix in the list
cruise += distance(fixes[i−1], fixes[last]); i = last + 1
else:
cruise += distance(fixes[i−1], fixes[i]); i = i + 1
detour = cruise − line; nil when detour ≤ 100 m
  • Whole-flight detour (flightDetour): all the flight’s fixes, against the free distance. nil with fewer than 2 fixes or no free distance.
  • Task-leg detour (detourDistance): the leg’s fixes, from the fix credited at the previous turnpoint to the fix credited at this one, against the straight distance between those two fixes. nil with fewer than 2 fixes.

Score:

share = detour / line
gliding = round(scaled(share, 0.28, 0.08))
ConstantValueMeaning
Minimum line10,000 mBelow it, no score
Detour: 0 points28 %A wander
Detour: 100 points8 %Clean
Insignificant detour≤ 100 mCounted as none

The thresholds come from eight logbook flights measured on 2026-10-07: good pilots on assigned tasks fly 10 to 20 % over the line.

Facts: “d detour (x %)”, then “L/D n” from the flight’s average glide ratio when it has one. The glide ratio is shown but not scored: scoring it would need the glider’s index.

What the pilot sees: “92.4 km/h · 2 of 5 on the day”.

Cross-country speed of a flight: the best task attempt’s averageSpeed if that attempt is completed, otherwise the free distance’s averageSpeed. A flight with neither gets no speed score.

Among several flights. When the Debrief or Compare holds more than one flight, the speed is ranked among the others that have a cross-country speed:

rank = (number of other flights with a strictly higher speed) + 1
count = (number of other flights with a speed) + 1
speed = round(100 − 60 × (rank − 1) / (count − 1))

First of the day scores 100 and last scores 40. Flights with equal speeds share the better rank. The fact “rank of count on the day” is added.

Alone. When no other flight has a speed, the speed is read against a fixed band for the detected sport:

speed = round(scaled(ownSpeed, low / 3.6, high / 3.6)) ownSpeed in m/s
Sport0 points100 points
Glider50 km/h120 km/h
Hang glider (delta)20 km/h60 km/h
Paraglider15 km/h45 km/h

The speed is not handicapped by the glider’s index.

What the pilot sees: “412 m above the ground at 14:32 · 15 % of thermals abandoned”.

The score starts at 100 and loses points:

DeductionPointsCondition
Low point−35Low point height < 300 m
Low point−15300 m ≤ low point height < 500 m
Engine−20 per runEach engine run starting after the release time
Abandoned thermals−10More than 25 % of the thermals in scope are attempts (needs ≥ 4 thermals)
Height lost in thermals−10Height lost inside thermals > 10 % of the height gained (needs ≥ 4 thermals)
decisions = round(max(0, 100 − deductions))

Low point height:

  1. Take soaringLowestFix (§1). Without one, there is no low-point deduction or fact.
  2. With terrain loaded: the height is heightAboveGround of that fix. Fact: “h above the ground at time”.
  3. Without terrain: the height is lowest.pressureAltitude − takeoff.pressureAltitude. Fact: “h above take-off at time”. The take-off stands in for the ground. This is skipped (no deduction, no fact) when there is no take-off fix, the take-off’s pressure altitude is 0, or the low point is below the take-off (a launch from a slope).

Engine runs: runs whose start fix’s rawTime is greater than the release time. Fact: “Engine used for t”, the sum of their durations.

Thermalling, only when the scope has at least 4 thermals (attempts included):

  • attemptShare = attempts / allThermals.count. Deduct 10 if attemptShare > 0.25. Fact “x % of thermals abandoned” when there is at least one attempt.
  • gained = Σ altitudeGained, lost = Σ heightLost over allThermals, where a thermal’s height lost is −altitudeLost (0 or positive). Deduct 10 if gained > 0 and lost / gained > 0.10. Fact “h lost again in thermals” when gained > 0 and lost > 0.

If no fact was collected (no low point, no engine run and no thermalling fact), there is no decisions score.

P5-4, fixed on both platforms 2026-10-20 (Calculation fixes §1). Thermal.altitudeLost is the sum of the negative fix-to-fix deltas, so it is never above 0; the readers here and in §4.5 used to ask for altitudeLost > 0, which never held, so the deduction, the fact and the question never applied. Both platforms now read the height lost, −altitudeLost (Thermal.heightLost).

Source (all parts): vulture-ios/Packages/FlightScreens/Sources/FlightScreens/FlightRating/FlightRating+Compute.swift (climbing(in:), bestLift(among:), gliding(of:), speed(of:among:), crossCountrySpeed(of:), decisions(in:), thermallingDeductions(in:), lowPoint(in:)), FlightRating.swift (scaled); vulture-ios/Packages/FlightScreens/Sources/FlightScreens/FlightDebrief/FlightQuestionAnswering.swift (timeLost(in:)), FlightQuestionAnswering+Flight.swift (flightDetour(of:)); vulture-ios/Packages/FlightScreens/Sources/FlightScreens/Models/DetailOptimizationItem+Legs.swift (detourDistance). Android: vulture-android/domain/debrief/src/main/kotlin/be/fousa/vulture/domain/debrief/FlightRating.kt, FlightQuestions.kt (timeLost, flightDetour). Same as iOS.

A flight is rated only if it has a free distance or a best task attempt. It also needs at least one part score. Otherwise there is no rating, and the Debrief opens without a gauge.

PartWeight
Climbing0.30
Gliding0.25
Speed0.25
Decisions0.20

Missing parts hand their weight to the others: the weights of the parts present are scaled to sum to 1.

W = Σ weight of the parts present
weighted = Σ (partScore × weight) / W (0 when W = 0)
rating = round(weighted × 10) 0 … 1000

Example: climbing 80, gliding 60, speed 70, no decisions score: W = 0.80, weighted = (24 + 15 + 17.5) / 0.80 = 70.625, rating 706.

RatingBandColour
0–399RoughRed
400–549FairOrange
550–699SolidYellow
700–849StrongGreen
850–1000OutstandingBrand blue (secondary tint)

A part’s card takes the colour of the band of partScore × 10. For example, a climbing score of 72 is coloured as 720, Strong.

rate(flight, among: flights) is called with every flight on the map (the Debrief) or in the comparison (Compare), the rated flight included. Only the speed part depends on the other flights (§2.4). Climbing, gliding and decisions read only the flight itself. The same flight can therefore score differently alone and on a competition day.

Compare rates every compared flight among all of them. The Debrief rates the selected flight and keeps each flight’s rating once computed, by object identity, so moving the selection back and forth does not rate again.

Source: vulture-ios/Packages/FlightScreens/Sources/FlightScreens/FlightRating/FlightRating.swift (init(components:), Band, Component.Kind.weight), FlightRating+Compute.swift (rate(_:among:)), FlightDebrief/FlightDebriefViewModel.swift (ratings), Compare/CompareFlightsViewModel.swift; Android: FlightRating.kt (rate, weighing, Band.of), FlightRatings.kt, vulture-android/domain/compare/src/main/kotlin/be/fousa/vulture/domain/compare/CompareData.kt. Same as iOS.

The Task section’s card draws every declared leg as a bar. Its width is the leg’s share of the declared task distance: the sum of the waypoint-to-waypoint distances, or equal shares when that sum is 0. Its colour depends on the leg’s speed against a reference speed:

  • Reference: the attempt’s averageSpeed if the task was completed and that speed is above 0. Otherwise the mean of the flown legs’ speeds.
  • A leg not flown is grey. With no reference speed, a flown leg is Solid.
Leg speed / referenceBand
< 0.75Rough
0.75 – < 0.90Fair
0.90 – < 1.05Solid
1.05 – < 1.20Strong
≥ 1.20Outstanding

Status: “Completed” (with distance and speed), “n of m legs” (n = legs with a speed), “Not started” (with the declared distance) or “No task”.

Source: FlightDebrief/DebriefSection.swift (DebriefTaskSummary.make, color(forSpeed:)); Android DebriefSection.kt (bandForSpeed). Same as iOS.

When a question is offered (FlightQuestion.applies(to:)):

QuestionsOffered when
Best thermal, Weakest thermal, Longest glide, Where I lost time, Where I stayed too long, My lowest point, My strongest hour, Left or right, The detour, Glides that cost the most height, What made up my speedAt least one flight
The windSome flight has wind estimates
Engine useSome flight has an engine run
My weakest hourSome flight lasted at least 90 min
Thermals I abandonedSome flight has an attempt
Where I lost height in thermalsSome flight has a thermal whose height lost (−altitudeLost) is above 0
The task, leg by leg; My slowest legSome flight has a task
My startSome flight has a best task attempt
My final glideSome flight completed its task
The task’s rulesSome flight’s task has a start maximum height > 0, a finish minimum height, or an AAT minimum time
Who climbed best, Who was highest, Who had the best glide ratio, Who thermalled least, The day’s best thermal, Who flew farthest, Who needed the fewest thermals, Who was lowest, Who followed whomMore than one flight
Who flew the task fastest, Who had the fastest final glide, My legs against the fastest, Who started when, Thermals the winner used and I passedMore than one flight, and some flight has a best task attempt

A section is shown when at least one of its questions is offered. Within a section, the questions about the selected flight come first (“This flight”), then those among the flights (“Among the flights”).

Rows. Single-flight answers are about the selected flight.

  • A thermal row reads “Thermal n · time” with “+gain · vario · duration”. n is the thermal’s 1-based position in all the flight’s thermals (attempts included). The time is the first fix’s local time.
  • A glide row reads “Glide n · time” with “distance · speed · L/D ratio”. n is the glide’s 1-based position in the flight’s glides.
  • A flight title is the competition ID (or registration) in upper case and the pilot’s name, joined by ” · ”. If neither exists, the flight’s date.

“On task” is put before a single-flight summary when the scope is the task. For a ranking it is used only when every flight’s scope is its task.

Task legs come from the attempt’s leg breakdown (DetailOptimizationItem.legs): one leg per pair of consecutive credited fixes, with the unflown waypoints appended. A flown leg has a duration (last fix − first fix), a distance (straight line between those fixes) and a speed distance / duration. Legs are numbered 1…n by their position in the list.

QuestionAnswer
The task, leg by legSummary: “Completed at speed” (attempt averageSpeed), “Not completed, distance” (attempt distance), or “The task was not started” (no attempt). One row per leg: “Leg n to waypoint”, with ”· Final glide” on the last leg; values: leg distance, leg speed, L/D (the leg’s cruise glide ratio), “k thermals” (the real thermals fully inside the leg).
My startRow “Start · time”: the attempt’s start height (startAltitude, else the first fix’s pressure altitude) and start ground speed. Row “First climb”: the scope’s first real thermal. Summary “Away r of n”: among the flights with an attempt, r = 1 + the number that started strictly earlier (by first-fix rawTime). Shown only with more than one start.
My final glideOnly for a completed task. The leg is the last leg with a speed. Row “Final glide · time”: distance, speed, duration (last − first fix), L/D, and the height used first.pressureAltitude − last.pressureAltitude (shown when > 0). Row “Finish · time”: finish height (finishAltitude, else the last fix’s pressure altitude), finish ground speed. Summary “Finished h under the minimum height” when the attempt has a minimumFinishAltitudeDifference (its absolute value).
The task’s rulesOne row per rule that applies; each says what the flight did, the limit, and “kept” or the excess. Start height: the zone’s maximumAltitude > 0 against startAltitude; broken when the height is above the maximum (“d over”). Finish height: the finish zone’s minimumAltitude, completed tasks only, against finishAltitude; broken when below (“d under”). Task time: the AAT minimum time, completed tasks only, against last − first attempt fix; broken when shorter (“d short”). Summary “Every rule kept” or “Rules broken: n”. Airspace is not checked.
My slowest legNeeds more than one flown leg. Row: the flown leg with the lowest speed (speed, distance, duration). Summary “Average leg v”: the mean of the flown legs’ speeds (not distance-weighted).
Who flew the task fastestThe flights with an attempt: completed ones first, then by averageSpeed, highest first. A completed flight shows its speed; others show “Not completed, distance”.
My legs against the fastestThe fastest flight is the completed one with the highest averageSpeed. If it is the selected flight: “You were the fastest.” Otherwise the flown legs are paired by position, up to the shorter list. Each row shows “my speed vs their speed” and myDuration − theirDuration as “t behind” (> 0) or “t ahead”. The summary sums the differences: “Against flight, completed at speed · t behind/ahead in all”.
Who started whenThe flights with an attempt, by start fix time, earliest first: start time, start pressure altitude, start ground speed.
Who had the fastest final glideThe completed flights, by the speed of their last flown leg, fastest first: speed, distance, duration.
Thermals the winner used and I passedThe fastest completed flight (as above). If that is the selected flight: “You were the fastest.” Otherwise the scope’s real thermals of both flights are matched with the leader analysis: a pair qualifies when their time gap max(entries) − min(exits) is at most 120 s and their centres are at most 1,000 m apart. Pairs are matched greedily, closest first. The winner’s unmatched thermals, sorted by height gained (highest first), up to 8 rows. Summary “flight: k thermals you passed, m shared”.
QuestionAnswer
Best thermalThe scope’s real thermal with the highest vario. Summary: “Average climb v” (scope.averageClimb).
Weakest thermalThe scope’s real thermal with the lowest vario. Same summary.
Where I lost timeThe thermals of §2.2’s time-lost list, most time lost first, up to 5 rows: “Lost t · vario”. Summary: “total lost in all · Average climb v”.
Where I stayed too longFor each real thermal in scope with at least 9 fixes and vario > 0, the tail is its last ⌊count / 3⌋ fixes. tailVario is the mean of the tail fixes’ vario. The thermal is listed when tailVario < vario / 2, with lost time = tail last rawTime − tail first rawTime. Sorted by lost time, up to 5 rows: “Last third t · tailVario vs vario”. Summary “total lost in all”.
Left or rightscope.thermals(turning: .left) and (.right) (§1, attempts included): count, share of thermals in %, climb. Summary “Left climbed better” or “Right climbed better” when both climbs exist and differ. Mixed-turn thermals count in neither row.
Who climbed bestThe flights by scope.averageClimb, highest first, with the thermal count.
The day’s best thermalAll real thermals in scope of all flights, by vario, highest first; top 3, each with its flight.
QuestionAnswer
The detourRow “The whole flight”: the whole-flight detour (§2.3), when not nil. Row “Worst leg · Leg n to waypoint”: the task leg with the largest detourDistance, when it has one.
Longest glideThe scope’s glide with the largest distance.
Glides that cost the most heightThe scope’s glides with distance ≥ 3,000 m, altitudeDifference < 0 and a glide ratio. Sorted by glide ratio, lowest first; top 3, each with “−height lost”. Summary “Average L/D n”: on a task, the attempt’s averageGlideRatio; otherwise (or when that is missing) the flight’s average glide ratio.
The windOver the scope’s wind estimates: row “Average wind” (mean of the speeds; the directions are not averaged) and row “Strongest wind · time” (speed and direction of the strongest estimate, with its thermal).
Who had the best glide ratioThe flights by the flight’s average glide ratio (whole flight, not scoped), highest first, with average cruise speed.
QuestionAnswer
What made up my speedRow “Cruise”: on a task the attempt’s averageCruiseSpeed, else the flight’s average cruise speed; plus L/D the same way. Row “Circling”: scope.thermallingShare % and thermallingTime. Row “Climb”: scope.averageClimb and “n thermals” (thermalCount, attempts included). Summary “Cross-country speed v”: on a task, the completed attempt’s averageSpeed; otherwise (including an uncompleted task) the free distance’s averageSpeed.
My strongest hourThe flight’s best one-hour optimisation (Flight analysis §7.6): row “Best hour · start time”, its distance and average speed. The map stretch runs from the fix at its first index to the fix at its last index.
My weakest hourSee §4.4.1.
Who flew farthestThe flights by free distance, farthest first, with its average speed. Whole flight, not scoped.
Who thermalled leastThe flights by scope.thermallingShare, lowest first, with thermalling time and thermal count.
Who needed the fewest thermalsThe flights by scope.thermalCount (attempts included), fewest first, with average climb and, for a completed task, the task speed.
  1. Flown fixes. On a task, the scope’s fixes. Otherwise the fixes from the release time (§1) to the landing fix’s rawTime, both inclusive (no landing: to the end).

  2. If the flown fixes span less than 90 min (last − first rawTime), there is no answer.

  3. Covered distance along the fixes, where a thermal covers only the straight line from its entry to its exit:

    covered[0] = 0
    for i in 1..<n:
    if fixes[i] and fixes[i−1] belong to the same thermal T:
    step = (i is T's last fix in the list) ? distance(fixes[entry], fixes[i]) : 0
    else:
    step = distance(fixes[i−1], fixes[i]); if fixes[i] is in a thermal: entry = i
    covered[i] = covered[i−1] + step
  4. Sliding window. For each start index s, e is the first index with rawTime[e] − rawTime[s] ≥ 3600. Stop when there is none. The hour’s distance is covered[e] − covered[s]. Keep the smallest; ties keep the earliest.

  5. Rows:

    • “Weakest hour · time”: its distance and distance / (rawTime[e] − rawTime[s]) as a speed.
    • “Circling”: the time inside the window spent in the scope’s thermals (attempts included), each thermal clipped to the window, as a % of the window and as a duration.
    • “Climb”: for the thermals entered inside the window, Σ altitudeGained / Σ duration and their count (only when Σ duration > 0).
  6. Summary “Average pace v”: covered[last] / (last − first rawTime) over all the flown fixes.

The question is offered when the flight’s total duration is at least 90 min. The answer then measures the flown fixes, which can be shorter, so the answer can still be empty.

QuestionAnswer
My lowest pointRow “Lowest point · time”: soaringLowestFix, or the scope’s lowestFix when the soaring part is empty. Value “h above the ground · altitude” with terrain, else the pressure altitude alone. Row “The save”: the first real thermal in scope whose first fix is at or after the low point.
Thermals I abandonedEvery attempt in scope, in time order: height gained and duration. Summary “a of n thermals abandoned, t in all” (n = allThermals.count, t = the attempts’ total duration).
Where I lost height in thermalsThe thermals in scope whose height lost (−altitudeLost) is above 0, by height lost, most first; top 5: “lost h” (positive), the gain and the vario. Summary “lost lost of gained gained” (lost = Σ height lost, gained = Σ max(0, altitudeGained)).
Engine useEvery engine run of the flight (not scoped): “Run n · time”, duration and start pressure altitude. Summary “n runs, t in all”.
Who was lowestEach flight’s soaringLowestFix (or scope lowestFix). If every flight has terrain, they are ranked by height above the ground; otherwise by pressure altitude. Lowest first.
Who was highestEach flight’s scope highestFix, by pressure altitude, highest first.
Who followed whomSee §4.5.1.

This answer is computed in the background (“Reading the tracks…”). It is computed once per set of flights and then kept.

  • Fixes per flight: the fixes from the best task attempt’s first index to its last index, or the whole flight without an attempt.
  • Leeching: the pairwise leeching analysis runs over every pair of flights. Its windows are merged into one summary per pilot. The algorithm, its constants and the classification are in Compare, ranking and statistics and Flight analysis §2.9. In short: independent if the total window time is under 60 s; follower if the follow ratio is ≥ 0.75; leader if it is ≤ 0.25; otherwise racing.
  • Flew alone: for each fix of a flight, it is not alone if some other flight has a fix within 10 s of it (the nearest in time) that is within 1,000 m. Flew alone % = alone fixes / all fixes × 100. nil with ≤ 1 fix or no other flight.
  • Row per flight: the classification. When the window duration is > 0, also “led t” and “followed t”. Then “x % alone” when known.

Source (all questions): vulture-ios/Packages/FlightScreens/Sources/FlightScreens/FlightDebrief/FlightQuestion.swift (applies(to:), section, isAmongFlights), FlightQuestionAnswering.swift, FlightQuestionAnswering+Flight.swift, FlightQuestionAnswering+Flights.swift, FlightQuestionAnswering+Task.swift, FlightQuestionAnswering+Breakdown.swift, FlightQuestionAnswering+Hour.swift, vulture-ios/Packages/FlightScreens/Sources/FlightScreens/Compare/CompareAnalyses.swift, Compare/CompareFlightsViewModel+Proximity.swift (nearestFix), vulture-ios/Packages/Flights/Sources/Flights/Models/LeaderAnalysis.swift. Android: vulture-android/domain/debrief/src/main/kotlin/be/fousa/vulture/domain/debrief/FlightQuestion.kt, FlightQuestionAnswering.kt, FlightQuestionAnsweringFlight.kt, FlightQuestionAnsweringFlights.kt, FlightQuestionAnsweringTask.kt, FlightQuestionAnsweringBreakdown.kt, FlightQuestionAnsweringHour.kt, CompareAnalyses.kt; the screens in vulture-android/feature/debrief only draw them.

The numbers are the same on both platforms. These are the only behaviour differences:

WhereiOSAndroid
The wind: average and strongestReads the wind dictionary in hash order. The floating-point sum of the average, and which of two equally strong estimates is “strongest”, can differ from run to run.Reads the estimates in time order. Deterministic.
My strongest hour, unusable indexesThe map stretch falls back to the optimisation’s turnpoint fixes alone.The stretch covers the track from the first turnpoint to the last.
Places on the mapHold the Flight, Thermal, Leg or fixes.Hold the flight id and indexes. The same places.

Earlier differences in leg numbering and the final-glide label (Android B31–B33) are now fixed on iOS too: the answers number legs 1…n by position and mark the last leg as the final glide. A zero-length leg (two turnpoints credited at one fix) is dropped without bringing the turnpoint back as unflown.

  • No rating: no free distance and no task attempt, or no part could be scored (§3.1).
  • Divisions by zero are guarded: scaled with high == low gives 0; averageClimb and the turn climb are nil without thermalling time; the speed rank’s count − 1 is never 0 because ranking needs at least one other flight; the weighted rating is 0 with no weights.
  • Rounding: part scores and the rating round half away from zero. The rating is rounded once, after the weighing, from the already-rounded part scores. Time lost per thermal rounds the time at the average climb to whole seconds.
  • Percentages in facts (“71 %”) are whole percentages of a 0–1 share. Durations in facts use hours and minutes; durations in answers use the app’s time format (Flight analysis §9).
  • Scope mismatch: gliding and the speed rank read the attempt or the whole flight directly, not FlightScope. “Who had the best glide ratio”, “Who flew farthest” and “Engine use” are whole-flight figures even on a task.