This page is the arithmetic, written out. It is longer than a marketing page has any business being, and that is on purpose: a figure you cannot interrogate is a figure you will abandon the first week it disagrees with you.
Step one · one session becomes one numberEvery recorded session is reduced to a single scalar called its load. The formula is unglamorous:
load = minutes × (relative intensity)²
Relative intensity is expressed against your threshold, where 1.0 means threshold effort — the pace or power or heart rate you could hold for roughly an hour, not your maximum. The square is what makes an hour at threshold cost several times an hour easy, and it is the standard quadratic weighting from the open literature rather than something invented here.
Getting that intensity out of a recorded workout is the hard part, and there are three ways to do it. Trainora tries them in order of how much they can be trusted, and records on the session which one was used, so that when your data quality changes mid-season — you buy a power meter, or stop wearing a strap — the two kinds of session sit side by side in the same chart and you can see which is which.
If none of the three applies — no power, no heart rate, no reported effort — the session gets no load at all. It is not recorded as a zero. A zero would quietly deflate your fitness for weeks; instead the app asks you for an effort rating.
Two things then knock confidence down a step each. If the threshold the estimate is measured against is itself a population estimate rather than something you entered or measured, the load standing on it cannot be high-confidence. And if usable samples cover less than eighty per cent of the session's duration, it drops too — a ninety-minute ride with ten minutes of power data is not a power-based session, whatever the arithmetic says. The app reports that coverage figure, so it can tell you why a number is uncertain rather than only that it is.
Step two · days, including the empty onesLoads are totalled per calendar day into a dense series with zero-load days included. This sounds like a detail and is not. A gap is information: a rest day has to appear in the series so that it can decay your fitness. Skipping empty days would mean a fortnight off looked identical to a fortnight of training compressed into fewer entries.
Step three · two moving averagesThe daily series feeds two exponentially weighted moving averages, the Banister impulse-response model. Each day, for each series:
value += α × (today's load − value), where α = 1 − e−1/τ
Why fatigue moves faster. The two α values differ by a factor of about 5.7, and that single ratio is the whole behaviour of the chart. A hard session pushes fatigue up by roughly an eighth of the gap between it and that session's load, and fitness up by roughly a fortieth. Take a week off and fatigue has shed half of itself in five days while fitness has shed barely a tenth — which is precisely the taper effect, falling out of the arithmetic rather than being bolted on. It also means form runs negative through any honest block of hard training. That is not a warning. It is what building looks like.
Drawn by running the recurrence above over a synthetic twelve-week history — three sessions a week, three weeks up and one down. Not a screenshot, and not anybody's real training.
Notice the shape of the fourth week in each block. Fatigue falls off a cliff; fitness barely dips. That is the same τ ratio again, seen from the other side.
Recomputed, never patchedThe whole series is recomputed from your full history every time it is needed, rather than updated incrementally from yesterday's stored value. Incremental updates drift, and a drifted number is unreproducible — which makes any bug in it impossible to pin down. Same history in, byte-identical numbers out, on every device and on every launch. There is no random seeding anywhere in the engine and no aggregation that depends on hash ordering, which is a boring engineering property that happens to be the difference between a chart you can argue with and one you cannot.
Step four · how certain it isConfidence is not decorative and it is not a vibe. It is a function of how many days of your recorded training the model has actually seen — counted from the first day with a load on it, never from the first day of the computation window. That distinction matters more than it looks: counting the window would report high confidence for somebody with three sessions, simply because the app chose to compute over 180 days. That is exactly the flattering number the whole engine exists to avoid.
Tap any figure in the app and you get four things: what it is, how it is worked out, how sure it is, and what it cannot tell you. The confidence section is computed rather than written — it says how many days you are standing on and roughly how many more would raise it a step. "Low confidence" on its own is the category's failure restated politely; the useful version is an instruction.
The first fortnight, honestlySo: you install the app on a Monday. For the first six days there are no numbers. On day seven a fitness figure appears marked low, and it will look absurdly small, because an exponential average starting from zero takes about six weeks to approach anything like the level your training actually supports. You have to know that to read the early chart without being misled, and the app tells you — but you should hear it here too.
Meanwhile the plan is not waiting for the model. The first four-week block is generated from what you told the app during setup: your sport, the days you have, and a race if there is one. It uses zones only — no paces, no heart-rate targets, because printing "4:15/km" for somebody with no measured threshold is the single fastest way to have a person train at the wrong intensity while believing the app measured it. Three sessions a week by default, more than four refused, the long session on the last training day of your week, one key session, and nothing hard in the two days before a race you have entered.
If you import history — Trainora reads .tcx and .gpx exported from a watch or another platform — the ladder starts from that history's first day rather than from installation day, and the picture fills in immediately. That is the fastest way past the awkward fortnight, with one catch: without max, resting and threshold heart rate on file, imported sessions carry no load at all, and the app says so before you import rather than after.
Above the day there is a week. Trainora buckets daily loads by your own calendar's week boundaries — Monday for a French athlete, Sunday for an American one — and computes three things from complete weeks only:
Partial weeks are excluded from all three, on both sides. A history that stops on a Wednesday would otherwise report a collapse in load that is an artefact of where the data ends.
ZonesFive, at the level the app shows by default: recovery, easy, steady, threshold, hard. The boundaries are fractions of your threshold — 0.60, 0.75, 0.88 and 1.00 — upper-exclusive, so every value falls in exactly one zone with no gaps and no overlaps. Heart rate and power scale with effort; pace does the opposite, since a faster pace is a smaller number, so its fraction is inverted before classification. More granular models exist in the literature and do not earn a place on the default screen.
A note on vocabularyTrainora's words are load, fitness, fatigue, form and intensity. It deliberately does not use the trademarked terminology of the commercial platforms in this space for the same quantities. The underlying models — Banister's impulse response, exponentially weighted load, the fourth-power treatment of a power series — are open literature, and this is a naming decision rather than a technical one. If you have used those other products, the concepts will map across without difficulty; the numbers will not be identical, because the estimators are not identical.
Next: a week, worked — the same model seen from the other end, as a block of sessions with a reason attached to each one.
Also in this notebook: the front page, what the watch does, where this is weakest (which is the proper companion to this page), questions, the changelog, support, privacy and terms.
© 2026 Oshi Lab · contact@oshi-messenger.com