In Bordure you are the sports director, not a rider. You build the season, write the race plan, then watch from the team car with the radio in hand. That puts one demand on the engine: it has to carry a race to its end, credibly, without anyone telling it what to do after the start, with up to 176 starters, teams that all play by the same rules, and no winner decided in advance.
This post follows a race in the order the engine builds it: the tick, the physics, the energy reserves, the groups, the decisions, perception, the radio, bad luck, then what makes the whole thing replayable and measurable. It says nothing about careers, contracts or training: only what happens between the start and the finish. Everything lives in a TypeScript package with no Node, no Electron and no React, which reads neither the clock nor Math.random.
Seven rules before the first line
The engine did not come from a feature list but from seven pillars, set down before the code and checked by tests. Each has a precise technical consequence, which is why the rest of this post reads as their implementation.
Intentions, not commands
You issue a plan and radio instructions. Never a power output, a line through a corner or the exact moment of an attack.
See the plan and the AI →A race finishes by itself
With no input at all after the start, the race ends sensibly on the staff’s plan alone.
See the default plan →The same rules for everyone
Opposing teams play the same plans, with the same rules and the same perception as you. No scripted winner.
See the decision function →Imperfect information
The interface only receives filtered projections, with their source and their age. Never the engine’s internal state.
See perception →A radio with a delay
An instruction leaves with a delay, gets an acknowledgment, and is tracked per recipient. Repeating an order gives no bonus.
See the radio →Presentation never touches the simulation
Text, playback speed and pauses have no influence on the race. Slicing the playback differently changes neither the race, nor the feed, nor the stops.
See replay →Determinism
Same seed, same content, same commands at the same ticks: same result, on any JavaScript engine.
See determinism →One tick, seven phases
The engine advances in steps of 5 simulated seconds (TICK_S). Inertia is neglected at that granularity: the model is quasi-static, and a group’s speed is computed from each rider’s power, with no acceleration integrated.
The mechanical engine simply applies paces. What chooses them, the AI and the radio, sits behind an interface (PacingDecisions). With no policy, everyone rides at a default “tempo” pace, which lets the mechanics be tested without the decisions.
Around the engine, the session
Inside the engine
Since weather arrived (T08), the engine slips three things between regrouping and decisions: the end of the return behind the team cars, incidents, and placement in echelons.
Two details matter more than they seem. First, every team’s decisions are read from the state at the start of the tick: nobody reacts to what another team has just decided in the same step, so the order in which teams are processed does not matter. Second, the finish is interpolated inside the tick: the crossing instant is not rounded to the 5-second step, which lets a sprint be decided by fractions of a second.
Physics fits in one equation
For a rider pushing a given power, speed is where the power delivered equals the forces opposing it: gravity, rolling resistance and air.
The engine has to find v given P: the speedForPower function inverts the relation by bisection, every tick and for every rider. That is why the sine and cosine of the slope angle never go through trigonometry: for a grade g/100, sin(atan g) = g/√(1 + g²) and cos(atan g) = 1/√(1 + g²), mathematically identical and much faster.
The surface enters through the rolling coefficient: 0.004 on asphalt, 0.0075 to 0.0315 on cobbles depending on the sector’s stars and the rider’s cobbles attribute. On descents, speed is capped by the technicality of the road and the rider’s descending skill. As for the draft, it is the factor from which almost all peloton tactics flow: 1 when alone, less than 1 inside a group (section 04).
| Case | Input | Expected |
|---|---|---|
| Flat, alone | 70 kg · 250 W | ≈ 10.3 m/s (37 km/h) |
| 8 % climb | 60 kg · 360 W | ≈ 5.7 m/s (20.5 km/h, VAM ≈ 1,630 m/h) |
| −6 % descent | 70 kg · coasting · technicality 0 | ≈ 14.7 m/s (53 km/h) |
The legs: one power, two tanks
Each rider carries fifteen integer attributes, from flat to composure. Converting them into physical parameters is the engine’s job, not the content’s: the content describes a rider, and the mechanics derive what he can sustain. The terrain attribute sets his critical power (CP); his reserves drain and refill tick after tick.
| Quantity | What it represents | How it evolves |
|---|---|---|
| Critical power | What the rider can hold without blowing up. cpWkg = 4.4 + 2.2 · a/100, with a the terrain attribute, blended between flat, hill and mountain according to the grade. | Multiplied by form and by day form. Reduced by durability, the bonk and, above 1,500 m, altitude. |
| W′ (anaerobic reserve) | From 12 to 30 kJ at 70 kg, depending on acceleration, hill and sprint. It is the fuel for attacks. | Above CP: W′bal −= (P − CP) · dt. Below it, Skiba-style recovery, slower when riding close to CP: τ from 316 to 862 s for an average rider. |
| Glycogen | (7,000 + 30 · endurance) · m/70 kJ. Metabolic cost P · dt / 0.23, of which a carbohydrate share that rises with intensity. | Feeding at 1,500 kJ/h, except in the last 20 km. |
| Durability | Accumulated fatigue. After 1,500 kJ of work, CP loses a fraction per additional 1,000 kJ. | Fraction 0.035 − 0.025 · resistance/100, loss capped at 15 %. |
| The bonk | The wall. Below 25 % of starting glycogen, CP drops. | Linearly down to 0.75 + 0.15 · resistance/100 of CP when glycogen reaches zero. |
| Day form | A “good day” or a “bad day”, hidden: no team knows it. | Factor exp(0.035 · z), z drawn from a normal distribution clipped to ±2.5. |
Day form is discreet but indispensable: without it, results followed the hierarchy of attributes almost exactly, and there was no point in racing. Its 3.5 % standard deviation is slightly above the measured day-to-day variability: it also absorbs what the model does not represent (positioning, motivation, small troubles).
In the first version, W′ and glycogen were in absolute joules. A 53 kg climber therefore had as many reserves as a 75 kg rouleur, which is 30 % more per kilo: he won almost every climbing race, while heavy sprinters hit the bonk. On the calibration bench’s first pass, a 57 kg rider won 36 to 38 % of the hilly and mountain races. Reserves are now scaled to body mass.
Groups: the draft makes the race
A peloton is not a list of riders, it is a physical object. Two consecutive riders 20 m apart or less form a group; the peloton is the largest of them all. Gaps are not set by hand: the time gap between two groups is the distance separating them divided by the speed of the rear group. They emerge from the physics.
The numbers are made up for the sketch. In the engine, each group has a stable identifier (that of the most advanced rider when it formed) and every gap is recomputed each tick.
The draft multiplies drag: at 1 you take all the air, at 0.5 you take only half. It depends on your place in the group.
| Situation | Factor | Note |
|---|---|---|
| Alone, or on the front | 1 | No draft. |
| Paceline, 2 to 5 riders | 0.75 | Paceline factor, for a rider not on the front. |
| Paceline, 6 to 19 riders | 0.68 | |
| Paceline, 20 riders or more | 0.62 | |
| In the wheels of a group of 20 or more | 0.5 | The rider is enveloped by the peloton. |
A puller spends 1/n of the time on the front, n being the number of pullers. The average factor is (1 + (n − 1) · paceline draft) / n. Worked example with the formula: four pullers in a group of 20 or more, (1 + 3 × 0.62) / 4 = 0.715.
Then the rules chain together. Designated pullers aim for an intensity, a fraction of their effective CP, which is a power averaged over the rotation: a group that cooperates therefore goes faster than a lone rider at the same intensity. Each member computes the power he needs to hold that speed with his draft; as long as it is within his means he follows and dips into W′ above CP. When W′ is empty he gets dropped, rides at his CP and the gap opens by itself. To avoid yo-yoing, a dropped rider cannot push above CP to come back until W′ has recovered to 25 %.
A group where nobody wants to pull does not enjoy a rotation nobody decided on: its speed is the average of those each member would hold alone on the front at 60 % of his effective CP, which gives a peloton at 36 or 38 km/h on the flat. An attack is a move planned apart from the rest of the group: attackers aim for their intensity, capped by the power available over the tick, and the rest of the group is recomputed without them. A sprint, finally, is an all-out effort that fades once W′ is empty.
“Without this rule, a climber and a sprinter pulling together rode at the average of the two paces, and nobody got dropped.”
On climbing pace (T10)That rule is why a climb is not handled like the flat: from 2 % grade, a group’s pace slides from the average of its pullers toward the highest of their speeds, which it reaches at 5 %. There, the draft is worth almost nothing and the strongest rider sets the rhythm.
One AI for every team
There is no intelligence for the opponents and another for you. There is decideTeam: one function that receives the team’s view, the public knowledge, its plan and its memory, and returns each rider’s decisions. The player’s team goes through it, with the plan the player wrote. The opposing teams do too, with the plan their staff derived from the public reputation of their riders.
That symmetry is tested. Identical squads under different team identifiers receive the same roles, and a team’s decisions do not change when an opponent’s reserves are altered.
The plan is the only tactical entry point
| Field | Values | Meaning |
|---|---|---|
| doctrine | finale · sprint · offensive | Save energy for the finale, control the race for a sprint, or race on the attack. |
| riders | every starter, with a role | Leader, alternate, protector, chase puller, free rider, lead-out, domestique. The order of the alternates is the order of succession. |
| fallback | switch · wait · release | If the leader is dropped: switch to the alternate, wait for him, or release the riders. |
| maxChasers | integer from 1 to 4 | Teammates committed at most to a chase. |
| attackZones | distance ranges | Zones suited to attacks by the leader and the alternates. |
The engine validates the plan and only produces codes; the wording comes from the narrative text layer. A plan with no leader is allowed: the team then chases for nobody.
The staff’s default plan is that of every opposing team and the draft offered to the player. It only reads public reputation and the reading of the course: offensive doctrine for a team that does not aim to win, otherwise sprint on a flat course and finale elsewhere; attack zones placed on the finale’s climbs, and on the hardest cobbled sectors of a classic.
That reading of the course is code too. The engine classifies a race as flat, hilly, mountain, cobbles or gravel; it spots the climbs, their difficulty and, recently, the walls (200 m at 6 % or more); and it determines the finale, which starts 30 km from the finish (earlier on cobbled classics and gravel), pulled forward to the foot of the climb or sector it overlaps.
Who pulls: five collective rules
Every tick, the AI evaluates for each team and each group who should pull and at what intensity. Five rules share the task: the breakaway and front groups, the controlled chase, defence in the finale, climbing tempo and the sprint lead-out. The most telling is the chase, where the team of a trapped leader aims for a target gap that shrinks as the finish approaches: G*(D) = min(240 s, max(0, (D − Dcatch) · 4 s/km)). The 4 seconds per kilometre is what an organised chase can really claw back with the drafts of section 04. The actual gap to that target then picks the effort level:
| Level | Condition | Leading team | Other interested teams |
|---|---|---|---|
| 0 · let it go | e < −30 s | 1 puller at 0.65 | — |
| 1 | −30 ≤ e < 0 s | 2 pullers at 0.78 | — |
| 2 | 0 ≤ e < 30 s | 3 pullers at 0.85 | 1 puller at 0.85 |
| 3 | e ≥ 30 s, or dangerous move | 4 pullers at 0.93 | 2 pullers at 0.93 |
Intensities are fractions of the puller’s effective critical power. A “dangerous move” is a front group that contains a favourite, or more than six riders.
What each rider decides
On top of those collective rules, each rider has his own list of priorities, evaluated in this order:
- Sprint underway: he carries on to the line.
- Launch the sprint, unless he is working for a leader present in his group. The launch distance depends on what his W′ lets him hold, and a good tactician gets it wrong less often.
- Attack underway: it lasts 120 seconds at most, while W′ ≥ 35 % and it has been neither neutralised nor cleared.
- New attack: a draw, depending on the case (see below).
- Collective instruction: pull at the requested intensity.
- Get back: in a group behind the peloton, at 0.72.
- Otherwise, follow.
An attack is never triggered by a script: it is a rate per minute converted into a probability per tick, p = 1 − e^(−λ·Δt/60), drawn from the rider’s own random stream, and only when his conditions are met. A rider with aggression 0.8, as leader in an attack zone of his plan with enough W′ and a timing of 1, has a rate of 0.5 · (0.5 + 0.8) = 0.65 per minute, which is roughly a 5 % chance per tick of launching the attack. It will start at 130 % of his critical power, capped by what he can actually produce.
| Case | Who, when | Min W′ | Rate (per minute) | Intensity |
|---|---|---|---|---|
| Breakaway | Free rider in the peloton, breakaway window open, fewer than 5 riders ahead. | 80 % | 0.2 · (0.5 + aggr) | 1.25 |
| Zone | Leader or alternate, inside one of the plan’s attack zones. | 70 % | 0.5 · (0.5 + aggr) · t | 1.30 |
| Breakaway finale | Front group ahead of 2 to 12 riders, 20 km or less to go. | 80 % | 0.4 · (0.5 + aggr) | 1.20 |
| Counter in the finale | Free rider, or teammate of an offensive team, between 3 and 20 km out. | 80 % | 0.02 · aggr | 1.20 |
| Marking | Leader or alternate when a threatening opponent attacks, in the finale. | 40 % | p = 0.3 + 0.5 · composure, per tick | 1.30 |
The timing t is 2 in the plan’s last zone; elsewhere 0.4 for a tactician (he waits), 1 otherwise.
What each team sees of the race
The engine knows everything. The teams do not. Between the exact state and the policy that decides, there is a perception layer, identical for all. Each team knows the race through two sources.
What the team sees
The groups that contain one of its riders, and those whose gap to one of those groups is 250 m at most. For those, everything is exact at the current tick: composition, speed, who is attacking. The riders of a team share what they see over the earpiece, with no delay.
The public bulletin
One bulletin per minute (every 12 ticks), identical for every team. It lists the groups in true order with a noisy gap: round(g + N(0, 2 + 0.03 · g)) seconds, forced to increase from one group to the next.
| True gap g | Std. deviation | Reading |
|---|---|---|
| 30 s | 2.9 s | The announcement is almost exact. |
| 120 s | 5.6 s | A few seconds of error. |
| 300 s | 11 s | About ten seconds of uncertainty over five minutes. |
Values computed with the formula above. A group known only from the bulletin is then placed at its announced position plus its speed multiplied by the age of the information.
A group known only from the bulletin is therefore estimated: its position is projected forward with the elapsed time. A rider the bulletin placed in a group that is now in view, who is no longer there and is seen nowhere, has an unknown group until the next bulletin. Finishes and abandonments, for their part, are public.
And you, the director? You receive an even poorer projection: groups with their source and age, and for your riders, feelings in words reported every three minutes, staggered from one rider to the next. Never a reserve, a power or a speed, and a test checks that those fields do not exist in the projection.
| Word | When the engine picks it |
|---|---|
good | W′ ≥ 90 % and glycogen ≥ 60 %. |
ok | Everything else. |
hard | W′ < 50 % or glycogen < 35 %. |
empty | Glycogen < 20 %, or rider dropped. |
The riders themselves know their exact legs: the policy reads their real reserves. It is you who receive only words.
Perfect perception (perfect: true) gives every team the exact view. It is not a game mode: it is a reference. With it, the previous ticket’s race is reproduced to the byte, which proves the perception layer changes nothing as long as you do not distort it. Measured afterwards, it did not disturb calibration: 44.1 km/h average on the flat classic in both cases.
The radio: saying isn’t doing
Your only actions during a race are radio instructions. An instruction has recipients, an intent (help the chase, save energy, protect the leader, attack in a zone, mark an opponent, change leader or doctrine, resume the plan) and an end condition (until further notice, until a point, until a gap). Only structural errors refuse it: a questionable tactic is accepted, then possibly reported as impossible.
At worst, in a big peloton, the order reaches the rider 20 s after sending, and you only find out 10 s later.
On reception, three things can happen. If a more recent instruction for the same slot has already arrived, this one is too late and is discarded. If it is a sacrifice (chase, protect, save energy) addressed to a leader, an alternate or a free rider, the rider can refuse it, depending on his character. Otherwise it replaces the previous one on the same slot only: marking an opponent while saving energy remains possible, because those are two distinct slots.
The probability of refusal is clamp((ambition − (loyalty + teamwork)/2) / 100, 0, 0.5). With an average personality (50, 50, 50) it is 0. For a rider with ambition 80, loyalty 30 and teamwork 40, the calculation gives (80 − 35) / 100 = 0.45. A domestique never refuses.
Finally, repeating an order gives no bonus. A recipient who already has the same instruction in transit or in force is removed from the send; if nobody is left, the instruction is refused as a duplicate. Repeating restarts no delay.
| State | Meaning |
|---|---|
pending | Sent, not yet received, or received without the car knowing. |
received | Team instruction received, waiting for the rest of the team. |
active | Received and being carried out. |
impossible | Received but not executable for now, with the reason; becomes active again if the situation changes. |
done | End condition reached, or rider finished or abandoned. |
superseded | Replaced by a more recent instruction for the same slot. |
refused | Refused by the rider, because of his character. |
cancelled | Cancelled at your request, through the same radio path, hence with the same delay. |
cancelRequested | Director side only: cancellation requested, outcome not yet reported. |
A cancellation is not a rewind: the old instruction can still be received or carried out while the cancellation is on its way.
Wind, rain, punctures
The day’s weather is a piece of race data, not an engine draw: wind (speed and direction), rain or not, constant throughout the race and public. The headwind enters the aerodynamic term of section 02. The crosswind does not change the physics: it makes echelons.
When the crosswind exceeds 3 m/s, an echelon forms. Its strength is s = clamp((crosswind − 3) / (7 − 3), 0, 1). In a group of more than 12 riders, that is the width of the road: the first 12 keep their draft, the rest ride “in the gutter”, almost fully exposed, spend more and end up dropping. The group splits. Order in the echelon goes first to the pullers, then to a score placement + team bonus + a little luck. The AI knows it: a contending team has two riders pull at 0.9 to slide its leader into the right echelon.
“Outside top 40”: the winner is not among the 40 best aptitudes for the race profile. East and west winds blow across the course’s north–south stretches; the peloton shatters into echelons (the yellow bars). In a north wind it stays together but the race lasts much longer.
The results say something about the sport. In calm weather, incidents change neither speed nor hierarchy: a rider who stops mostly gets back behind the cars. Rain multiplies crashes and produces surprise winners. Crosswind breaks the peloton into echelons and favours rouleurs. And in strong wind, the best sprinters run short of glycogen and lose the sprint to fresher riders: twenty winners out of thirty outside the top 40 in a north wind, despite thirty bunch finishes.
Bad luck is drawn, never decided
Every tick, each rider who is riding makes a draw: he has an incident with probability 1 − exp(−λ · d), d being the distance covered in the previous tick in kilometres, and a second draw picks the nature. All these draws come from a separate random stream (engine.incidents).
| Incident | Rate | Consequence |
|---|---|---|
| Puncture | 1 per 5,000 km on asphalt, 1 per 400 km on cobbles | Stop of 15 to 35 s. |
| Mechanical | 1 per 10,000 km, three times more on cobbles and gravel | Stop of 10 to 45 s. |
| Crash | Depends on group size, technicality, surface and finale (× 1.5 in the last 20 km, × 2 in the last 5); also on descents, even alone. | Riders behind fall in turn with probability 0.55 (group of 20 or more) or 0.3, up to 8 on the ground. Abandonment in 10 % of cases, otherwise a stop of 15 to 60 s and a minor injury. |
After an incident, the rider benefits from the shelter of the cars (factor 0.55), for ten minutes at most and until he has joined a group of more than 5 riders. That is what lets him, most of the time, get back.
The terrain has a say
The base engine grew in layers, and each added a rule without breaking another. This post does not detail them, but here is what they bring.
Cobbles
Rolling resistance rises with the sector’s stars and the cobbles attribute (from 0.0075 to 0.0315). Vibrations wear down critical power, up to 20 %. The draft loses some of its effect and, as in an echelon, only the first riders in a group keep it: the accordion.
Gravel
Rolling resistance from 0.0054 to 0.0143 depending on stars, the rider’s skill and rain. On a climb, part of the power no longer drives the rider forward: the wheel slips.
Altitude
Above 1,500 m, critical power drops by 7 % per 1,000 m. At 3,000 m the model gives −10.5 %. Races that never exceed 1,500 m do not change by a single bit.
Time trials
A day has a kind (road, individual, team or prologue) and a dedicated AI sets the pace over the course. A road race does not change by a single bit.
Mountain finales
The finale is pulled forward to the foot of the second-to-last climb if it starts 70 km or less from the finish: tempo, attack zones and defence then apply on the last two climbs.
Walls
A short climb counts as a real climb if it is at least 200 m at an average of 6 %. The Paterberg (360 m at 12.9 %) thereby enters the reading of the course, with its weight in the plans.
Same seed, same race
Determinism is the pillar that costs the most and pays back the most. Without it, you cannot reproduce a bug, compare two versions, save a race in progress or calibrate anything at all. It rests on four things.
A precise generator
xoshiro128** over four 32-bit integers, seeded by splitmix32. 32-bit arithmetic through Math.imul: the result is identical on any conforming JavaScript engine.
Named streams
Each subsystem draws from its own stream, derived from the seed and a hash of its name: ai.rider.<id>, engine.incidents, perception.radioTour, radio.<team>… Adding draws in one does not shift the others.
Maths ported by hand
ECMAScript leaves exp, log, sin, pow “implementation-approximated”. The engine therefore ships its own versions, ported from fdlibm 5.3 in plain JavaScript. ESLint forbids the others.
A journal, not a snapshot
A race save is the list of requests that changed it, with a checkpoint. Resuming means preparing the race and replaying the journal.
“Node 26 and Electron 44 returned results that differed by one ulp on a share of values, and a career diverged in its second season.”
Finding behind T39, 3 October 2026That sentence is the reason for the third point. The test labs ran under Node, the application under Electron, and their maths functions did not return exactly the same bit. One ulp of difference on a form value, and the next season’s race changed. The fix is a port of fdlibm 5.3, checked on 30 million values identical bit for bit with the original C library, and a test that runs the same career under Node and under Electron then compares the fingerprint of the complete state.
The journal also protects pillar 6. The controller that plays the race takes its stop decisions tick by tick: slicing the playback differently changes neither the race, nor the feed, nor the stops, and a test checks it. Presentation therefore cannot alter the simulation. In return, a save carries the version of every model (physics, engine, AI, perception, radio, random draw): if any has changed, it is refused, with a message naming the model and both versions, rather than replayed wrongly.
The calibration bench
A deterministic engine guarantees that a race can be replayed, not that it looks like cycling. For that there is directeur lab: it runs hundreds of races with no instructions, using the staff’s plans, in the real session (perception, radio, incidents, day form), and measures what comes out. It reads the engine’s exact state: it is a diagnostic tool, never something the player reads.
Seven targets say what a peloton should look like. A target is not judged below 20 races on the terrain, each measurement carries its 95 % confidence interval, and a gap is significant only if the whole interval lies outside the target. The 35 % ceiling for the most frequent winner was first set at 25 % without measurement, then revised along the way.
| Target | Range | Measured |
|---|---|---|
| Speed on the flat | 40 to 45 km/h | 43.8 km/h (CI95 43.5 to 44.2) |
| Winning breakaways | 10 to 25 % | 11 % (CI95 8 to 14 %) |
| Bunch finishes on the flat | at least 50 % | 84 % |
| Climbers win in the mountains | at least 80 % | 91 % |
| Favourites often, not always | 40 to 80 % | 57 % · 76 % · 82 % (flat, hilly, mountain) |
| No systematic winner | at most 35 % | 29 % · 30 % · 30 % |
| Nobody dominates everywhere | under 5 % on his worst terrain | 1 % |
At measurement, favourites won 82 % of mountain races, slightly above the range, but the gap was not statistically significant: the report flags it without counting it.
The targets drove ten adjustments in the first pass. Four tell the story well:
| Observed defect | Fix |
|---|---|
| A 57 kg rider won 36 to 38 % of the hilly and mountain races. | W′, glycogen and durability scaled to body mass. |
| The whole peloton reached the finale on the verge of the bonk. | Draft of 0.5 in the wheels of a peloton (the paceline factor stays unchanged). |
| 67 % bunch finishes at the top of an hors-catégorie climb. | Climbing pace set by the strongest puller. |
| The mountain breakaway was always caught before the foot of the last climb. | Target junction point at 8 km in the mountains, 15 km on hilly courses, 6 km for a sprint. |
The bench also runs as a test suite: 100 seeds per course, drawn weather, failure on any significant gap, about 45 seconds on nine threads at the time of T10. And since it is deterministic, its results depend neither on the number of threads nor on the clock: a test checks that.
What isn’t right yet
The engine’s sporting numbers are calibration hypotheses, not validated truths, and we would rather say so up front. Here is what we know we do not yet do well.
- Hilly courses were still too bunched at the T10 measurement. The peloton arrived almost whole at the foot of the final wall: 98 % of races ended with at least 20 riders within 5 s, and breakaways almost never won there (1 %). Calibration tickets have revisited the question since, but it is the kind of race where we stay vigilant.
- Strong wind on the flat needs watching. At 7 m/s or more (21 races out of 200 at the T10 measurement), 43 % of winners were favourites and 38 % came from outside the top 40: more surprises than on the rest of the flat. It is an open calibration point.
- The physics is quasi-static. Inertia is neglected at the 5-second scale, and air density is constant at 1.225 kg/m³ everywhere, altitude included. When altitude was added (T66), the drop in critical power was modelled but acclimatisation was not.
- Outside careers, knowledge of roles stays exact and shared. In free races and on the bench, every team reads the same exact aptitudes; only in a career does each team read its own riders in its own dossier and the others through public reputation.