A training model has to survive us attacking it before it earns a pixel on your screen — and this one didn't.
2026-07-16 · 7 min read · Brevet · AI-assisted
Drafted with AI assistance and reviewed by a human. The science is sourced and real; the article isn't medical advice.
The short version: Most training apps hand you a confident number — a form score, a freshness percentage — from a model that has never met you. We built a more honest one, with a few separate states instead of a single number. Then, before it touched your screen, we spent weeks trying to prove it wrong. It mostly failed the tests. So we didn't ship it — and this is the story of why refusing to ship is the whole point.
Open almost any training app and it will tell you how fresh you are today. A percentage. A little coloured ring. A word like "primed."
Here's the question nobody asks: where did that come from? On most platforms it comes from a model watching your training load — one number for how much fitness you've built, one for how tired you are — and subtracting the second from the first. That's it. That model dates from 1975. It's called the Banister model, and it is genuinely useful the way a hammer is useful. It's also blunt. It treats three hours of easy endurance and forty minutes of savage intervals as the same "load," just different sizes, and it has never heard of you specifically.
I got tired of that. So I built something that, on paper, is better.
Instead of one fatigue number, the new model carries a few separate ones. How deep your aerobic base is. Your sharp top-end. How fresh you are right now. How well you hold power late into a long ride, when everyone falls apart at a different point. It reads those from things your body and your rides already produce — morning heart-rate variability, how much power your heart rate is "buying" you, how your time splits across the zones.
The dream is obvious: a model that learns which of those is actually you and stops pretending you're the population average.
And that's exactly where it gets dangerous. Because the moment a model claims to know something personal about you, it can be confidently wrong about you — and hand you a number that feels precise and means nothing.
So before it went anywhere near your dashboard, we tried to break it.
Gate one: can it even be pinned down? A fancy word for a simple worry. Given a season of your data, is there one answer the model settles on — or could ten completely different internal settings produce the same numbers, meaning the "answer" is really a coin flip? We ran the whole thing as a throwaway simulation with a known truth baked in, then asked it to recover that truth. It managed — but only after we stripped it back hard, until it was really personalising one single number and holding everything else at the population default.
Gate two: does it survive being slightly wrong? In the real world you never have the perfect constants. So we deliberately fed it the kind of small errors you'd actually have. The part that made the model yours — the clean separation between "your aerobic base changed" and "you're just tired today" — came apart. The two got tangled, and the model started reading a good breakfast as a fitness gain. That's not a rounding error. That's the headline feature failing.
Gate three: run it silently on real data. This is the honest one. We switched the model on for a single rider — me, a year of real training — in a mode that computes everything and shows nothing. A shadow. Then we looked at the two numbers it was allowed to learn about me.
Both of them slammed straight into the wall.
A parameter pegged at the very edge of its allowed range isn't a finding. It's the maths equivalent of a shrug. The model couldn't find a value that fit me, so it fled to the boundary and stopped.
Here's where most teams quietly bury it. I didn't — a shrug is a question, not an answer. So I went looking for why the model was shrugging.
Two of the reasons were my own fault. First, I'd been feeding it five to seven times more training load than its own maths could handle, shoving one of its internal numbers so far past its working range that the whole thing broke. That wasn't the model failing. That was me handing it garbage. Second, when I measured my aerobic base I was counting my hard interval days as if they were easy endurance rides — so a heavy week looked like my base was falling apart, when really I'd just done more intervals. The model dutifully concluded "your training isn't building your base." That sounded like an honest, humbling result. It wasn't a result. It was my bug.
So I fixed both. Scaled the load back to where the maths holds. Counted only the genuinely easy rides when reading aerobic base. Ran it again.
And the honest core held. The one number the model can actually learn about me turned out to be the same one our shipped, boring model already learns — nothing more. On my single year of data, all the extra machinery personalises exactly nothing new. That one isn't a bug I can fix. That's the answer.
That's the ending. The fancier model does not go on your screen. The 1975 one — the blunt, population-level hammer that is at least honest about being built for everyone — stays exactly where it is.
And here's the part I actually like: the breaking worked twice. Once on the model — it told me its fancy internal states don't earn their place on your screen yet. And once on me — it surfaced two bugs I'd have happily shipped if I'd been trying to make the demo look clever instead of trying to break it. The model now writes, in its own output, "I couldn't identify a personal value for you" — in plain maths, not a confident fake number. If it ever does find a real, honest answer on enough riders' data, we'll see it say so. Only then does the conversation about showing you anything even begin.
This isn't the first time. The readiness score already refuses to show you a number for your first couple of weeks, because until it has learned your baseline, any number is a default plus noise. We once built a fancier recovery model and threw it out because it recharged your battery four to five times too fast against the validated curve. Same reflex, every time: under-claim and be right, rather than over-claim and be TrainerRoad with nicer charts.
What I'm not claiming. I'm not saying the idea is dead. A rider with years of dense data, or a few hundred of them together instead of one, might yet show a signal worth personalising — and there's a specific date on the calendar where a separate, live experiment tells us whether the one number that did survive is worth anything at all. I'm also not saying the old model is good. It's a blunt instrument; we'd love to replace it. I'm saying this replacement hasn't earned the job, and I won't dress it up as if it has.
Every other app is racing to show you more confident numbers. The most honest thing a training tool can do is show you fewer — and tell you which ones it doesn't trust yet, including its own.
Brevet is a training and wellness tool, not a medical device within the meaning of EU MDR 2017/745. Everything here describes what a model does with training data — never what your numbers mean about your health. You always have the final say.