decision.altitude_floor: measure what the name says, and drop a prior the archive does not support - #520
Merged
Conversation
The metric was labelled "How high the pilot commits to the next climb"
(Commit%) and explained as the height still in hand "at the moment they
commit to a climb" — but the computation never looked at a climb. It
swept the 30 s-smoothed altitude trace for local minima with 100 m of
prominence either side, and reported the median as a band percentage.
It is now "How low the pilot gets between climbs" (Floor%), computed by
walking each consecutive PAIR of post-start climbs and taking the lowest
fix between them, keeping the gaps that descended at least 100 m. Same
question, structural answer: "between climbs" is the loop bound rather
than something the prominence sweep happened to produce, so the run out
to the first climb, the glide to goal and a sled run are excluded
because nothing was climbed after them. No smoothing, no prominence, and
the reported low is a real fix altitude rather than a 30 s mean that
flattens a deep save upward.
Audited over the whole glidecomp-archive (184 tasks, 25 comps, 4,762
pilot-tasks):
- The two definitions agree closely — Spearman 0.87 on pilot ordering,
median 40.6% of band against 38.2% — and separate the leaderboard
equally: median |rho| 0.43 against 0.40, stronger on 51% of tasks.
This is a change made for explainability, not for signal.
- Coverage rises to 85.0% of started pilots from 83.7%, but shifts
which pilots qualify: three climbs are needed for two gaps where two
dips used to do.
- The old prior direction 'higher' does not hold. Only 69% of 147
task correlations take the assumed sign, and two large fields are
emphatically opposite — Bright 2023 open T3 (85 pilots, rho +0.73,
top ten at 33% of band against the bottom ten at 78%) and Bright
2024 open T2 (95 pilots, rho +0.52). Whether height in hand pays is
a property of the day, so direction drops to 'neutral' (the v9
treatment) and the sign becomes the finding.
The explanation also states the band's real endpoints — p10 of the
field's thermal entries, p90 of its exits — so a negative reading reads
as expected rather than alarming. Over the archive 2.3% of scored pilots
sit below 0%.
FIELD_ANALYSIS_VERSION 17 -> 19 rolls stored reports onto the new
label, explanation, direction and values.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…or-metric-explanation-2ffc88 # Conflicts: # web/engine/src/field-analysis/metrics/decision.ts # web/engine/src/field-analysis/version.ts
|
Preview Deployment |
pokle
pushed a commit
that referenced
this pull request
Aug 1, 2026
18 commits, of which #519 ("Simplified Technical English across the field analysis, and metric labels that name the quantity") lands squarely on the charts this branch changed. Git auto-merged all four overlapping files — their edits were to caption prose, ours to axis geometry — but the merge being clean is not the same as the work still being right, so: - #519 rewrote every metric's FULL label. RankScatter's x-axis title is built from `metric.label`, so this is where phase 1 could have broken: a label that already carried its unit would have produced "Glide speed (km/h) (kilometres per hour)". None do. Checked by walking all 22 rows of the ranking in the running app and reading every title the scatter drew: the longest is 69 characters ("How much of the thermal the pilot climbed before leaving it (percent)") and still fits the plot without clipping, and the ratio-unit metrics correctly get no parenthetical. The new labels are a straight improvement to the axis titles. - The heatmap's axis titles and the day-profile stack's shared time-axis title survived intact. - #521 added a thermals chart with its own inline x title. Left alone on purpose — 9px and left-anchored are deliberate choices for a 320-unit panel, and adopting the shared helper would silently overturn them. Plan doc updated where master has overtaken it: §D is half-answered (full labels done by #519/#520, FIELD_ANALYSIS_VERSION now 20; the cryptic SHORT labels in the heatmap remain), §A is marked shipped with the two places it came out differently, and the baseline table is marked as a snapshot — the same page now measures 17,523 px / 9,081 words, so a phase claiming a reduction must prove it against a fresh measurement. §B, §C, §E, §F, §G, §H are untouched: the legends #519 reworded are still inline, and the comp page still has zero ⓘ. Verified: typecheck:all, 1,238 engine and 533 frontend unit tests, 52 e2e, 33 SSR e2e. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UyMHUij8wpMk6rZzX3yqaY
pokle
pushed a commit
that referenced
this pull request
Aug 2, 2026
Merges master (2cb994c) and audits MetricLanes across the whole glidecomp-archive: 184 tasks, 1,104 families, 3,239 lanes. New web/scripts/audit-metric-lanes.ts, following audit-score-charts.ts: it scores every task in a comp library with the real engine, builds the real field-analysis report, runs buildLanes over each family the way MetricFamilySection does, and checks the invariants the drawing code relies on — dots pair by trackFile, every percentile sits strictly inside (0,100), the value printed at a lane's end is the value of the dot at that end (the one most likely to be silently wrong, since a 'lower'-is-better lane is flipped), the order is deterministic under reversed input, and no outcome metric gets a lane. Zero invariant violations across the archive. The three fixes below all come from things the audit COUNTED rather than things it failed on — each renders as a blank or an average-looking dot, which is why no test was going to catch them. 1. A lane measuring ONE pilot is dropped (136 of 3,401 lanes). Midrank puts a lone value at exactly 50, so the lane stated "this pilot was dead average" when it meant "only one pilot could be measured". There is no field for a percentile to sit within. The value is still in the per-pilot table, which is where a single reading belongs. This also halved the all-identical lanes, 283 -> 127. 2. The default profile falls past a leader with nothing to draw (5 of 861 charts). It was rank 1 unconditionally; a winner who never shared a thermal has no gaggle metrics at all, so those charts drew no connector — the rows-of-dots state the default exists to prevent. Now the best-ranked pilot appearing in at least two lanes, because a single dot is not a profile. Zero such charts remain. 3. An all-identical lane says so. 127 lanes stack every dot on P50 under a bare figure, which reads as a broken chart; it now reads "every pilot 0.4 m/s". Also adopts two conventions master landed while this was open: the shared XAxisTitle/YAxisTitle from charts/AxisTitle.tsx (#501 — every chart names its axes in the plot, because a caption is read once and an axis continuously), and nothing needed for #520's decision.altitude_floor going 'higher' -> 'neutral', since the orientation is data-driven. bun run test:all (1279 engine/script, 584 frontend, 508 comp, 92 auth), typecheck:all, and test:e2e:ssr (33 passed). Re-driven in a browser: axis titles clear the gutter, connector and readout unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R1Zrf2tMEP2QHK6jWboAQq
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Branch preview: https://claude-altitude-floor-metric.glidecomp.pages.dev
The metric was labelled "How high the pilot commits to the next climb" (
Commit%) and explained as the height still in hand "at the moment they commit to a climb" — but the computation never looked at a climb. It swept the 30 s-smoothed altitude trace for local minima with 100 m of prominence either side.It is now "How low the pilot goes before the next climb" (
Floor%), computed by walking each consecutive PAIR of post-start climbs and taking the lowest fix between them, keeping the gaps that descended at least 100 m. Same question, structural answer: "between climbs" is the loop bound rather than something the prominence sweep happened to produce, so the run out to the first climb, the glide to goal and a sled run are excluded because nothing was climbed after them. No smoothing, no prominence, and the reported low is a real fix altitude rather than a 30 s mean that flattens a deep save upward.Audited over the whole archive
184 tasks, 25 comps, 4,762 pilot-tasks from pokle/glidecomp-archive, scoring each task and running the real metric.
direction: 'higher'prior does not hold, so it drops toneutral(the v9 treatment). Only 69% of 147 task correlations take the assumed sign, 16 are wrong-signed at |ρ| ≥ 0.3, and two large fields are emphatically opposite — Bright 2023 open T3 (85 pilots, ρ +0.73, top ten at 33% of band against the bottom ten at 78%) and Bright 2024 open T2 (95 pilots, ρ +0.52). Whether height in reserve pays is a property of the day, so the sign is the finding.Two things the audit cleared rather than changed, both recorded in comments so the next reader doesn't re-ask:
The explanation also now states the band's real endpoints — p10 of the field's thermal entries, p90 of its exits — so a negative reading reads as expected rather than alarming. Over the archive 2.3% of scored pilots sit below 0%.
Notes for review
FIELD_ANALYSIS_VERSION18 → 19 rolls storedtask_field_analysisreports onto the new label, direction and values.decision.altitude_floormoves to the 55% coverage tier in the kosci integration gate. That is a fixture property, not a scope one: the synthetic tracks are climb-poor (15 of 41 started pilots take fewer than three climbs, against an archive median near nineteen). Real-archive coverage went up, not down.bun run test:allgreen (engine 1229, frontend 518, auth-api 92, competition-api 477) andtypecheck:allclean.🤖 Generated with Claude Code