Join Cycling’s Adaptive Plans: What Happens When You Miss A Session
Every training plan works fine until Thursday.
I spent eleven weeks on Join with a simple brief: break it. Not by quitting, but by training the way people actually train. Late meetings, a head cold, a club run that turned into a race, a work trip to Leeds with no bike. If an adaptive AI coach can’t cope with a Wednesday evening that evaporates, it isn’t adaptive, it’s a PDF with a subscription.
The short version of this join cycling app review: Join’s rescheduling is the best I’ve tested at absorbing chaos, and that same strength is what makes it hard to tell whether you’re still training towards the thing you signed up for. Those two facts are the same fact.
The setup: a real athlete, a real target
Test subject is me. 74kg, FTP 312W at the start of the block (20-minute test, 0.95 multiplier, 328W for 20), a decent but unspectacular threshold and a sprint that stopped existing around 2019. Target event: a hilly 100-mile gravel event in mid-September, entered properly, with a real number to hit. Secondary target: a club 25-mile TT six weeks before, because a hard, dated effort mid-block is exactly the sort of thing that reveals whether a plan still knows what it’s building.
Setup was Wahoo Kickr Core indoors, Assioma Duo outdoors, Garmin 840 head unit, everything syncing to intervals.icu as source of truth so I could audit what Join thought happened against what actually happened. Join pulled from Strava. Zwift handled the indoor sessions when I couldn’t face ERG on the Wahoo app.
Join asked for available hours per weekday, not a fixed weekly total. That distinction turns out to be the whole architecture. I gave it: Monday 0, Tuesday 90 minutes, Wednesday 90, Thursday 60, Friday 0, Saturday 4 hours, Sunday 3 hours. About 11.5 hours a week available, which it filled to roughly 8 hours 20 in week one.
Disruption one: the single midweek miss
Week three. Tuesday’s session was 4x8 minutes at 105% FTP (328W), 4-minute recoveries, 74 TSS. I skipped it. No excuse logged, no “I’m sick” button pressed, just nothing recorded.
Wednesday morning the plan had already changed. Here’s the before and after, pulled from my notes:
BEFORE (as planned Sunday night)
Tue 4x8 @ 328W 74 TSS 90 min
Wed Endurance Z2 58 TSS 90 min
Thu Recovery 28 TSS 60 min
Sat Long + 3x12 SST IF 0.72 210 TSS 4h
Sun Endurance 145 TSS 3h
Week total: 515 TSS
AFTER (Wednesday 06:40, following the Tuesday skip)
Tue [missed]
Wed 4x8 @ 328W 74 TSS 90 min
Thu Endurance Z2 42 TSS 60 min
Sat Long + 3x12 SST IF 0.72 210 TSS 4h
Sun Endurance 128 TSS 3h
Week total: 454 TSS
Note what it did. It moved the intensity, not the volume: the 4x8 shifted to Wednesday intact, at the same wattage and the same duration. The endurance ride got compressed into Thursday’s 60-minute slot and lost 16 TSS. Sunday shed 17 TSS to protect the gap between the Wednesday intervals and Saturday’s sweet spot. Total weekly load dropped 12%, which is roughly what you’d expect from losing one of five sessions and recovering most of it.
TrainerRoad’s Adaptive Training, when I ran the same experiment last winter on a Build plan, did something different: it left the week’s remaining sessions alone and adjusted the next week’s difficulty based on my Progression Levels. Both are defensible. Join’s is more useful on a Wednesday morning when you want to know what to do tonight.
Disruption two: four days gone
Week six. A cold, the proper kind. Monday through Thursday, nothing. I logged it in Join’s illness field, which matters, because when I ran an unlogged four-day gap in week nine it behaved noticeably differently.
With illness flagged, Join rebuilt the return as a ramp:
| Day | Original | After illness flag |
|---|---|---|
| Fri | rest | Z1 45 min, 28 TSS |
| Sat | 4h, 210 TSS, 3x12 SST | 2h 15, 98 TSS, no intensity |
| Sun | 3h, 145 TSS | 1h 30, 72 TSS |
| Mon (next) | rest | rest |
| Tue | 5x6 VO2 @ 118% | 3x10 @ 95% FTP, 62 TSS |
That’s a 59% reduction on the returning weekend and a substituted, easier Tuesday. Reasonable. Conservative, arguably too conservative for a four-day cold, but I’d rather a coach err that way. The unlogged version in week nine, by contrast, just pushed everything forward and took about 20% off the first weekend back. Join treats silence as “busy”, not “broken”. Flag your illnesses.
Disruption three: the club run that became a race
Week eight, Saturday. Plan said 4 hours, IF 0.72, 3x12 sweet spot. What happened was 3 hours 40 at IF 0.81 with 14 minutes above threshold and a 5-minute effort at 348W up a climb that someone decided was a KOM opportunity. 268 TSS against a planned 210.
Join’s response on Sunday morning was the smartest thing it did all block. It didn’t just dial Sunday back. It replaced Sunday’s 3-hour endurance ride with 2 hours at a lower ceiling (power capped rather than just shorter), then removed Tuesday’s VO2 session entirely and replaced it with tempo, then reinstated a VO2 session on the following Thursday. It read the Saturday effort as having already delivered the week’s high-intensity stimulus and rearranged around that rather than stacking more on top.
Compare that to how a static 12-week Build plan handles the same Saturday: it doesn’t. You show up Tuesday to 5x6 at 118%, fail the third interval, and either grind out a junk session or bin it and feel like you’ve fallen behind.
Where the calendar-first model starts to blur
Here’s the problem, and it took until about week seven to see it.
Join doesn’t ship you a periodised block with a name on it. There’s no screen that says “you are in week 3 of a 5-week VO2max build, next comes a recovery week, then a 4-week threshold block.” It generates the next stretch of sessions from your current state, your available hours, your event date, and what you’ve actually done. Ask it what phase you’re in and there’s no satisfying answer, because in a meaningful sense there isn’t one.
For eight weeks that felt like sophistication. Then I audited the block in intervals.icu and found this:
Weekly time above 105% FTP (minutes)
wk1 18 wk5 22 wk9 11
wk2 24 wk6 0 wk10 9
wk3 16 wk7 12 wk11 14
wk4 8 wk8 31* wk12 10
*includes club-run race efforts
There’s no shape to that. A deliberate VO2 block would show three or four weeks at 25-35 minutes and then a deliberate drop. What I got was a noisy plateau averaging 14.6 minutes a week, because every time the plan started to accumulate intensity, real life took a session out and Join, quite correctly by its own logic, protected recovery and rescheduled. The rescheduling was always locally right. The aggregate was a block with no peaks in it.
My FTP after eleven weeks: 318W. Up 6 watts, about 2%. For an intermediate athlete who’s been training for years, on 8 hours a week, that’s fine. It is not what a well-executed VO2 block does. My 25-mile TT came in at 58:41, 43 seconds slower than the same course in May, on a day with slightly more wind. The gravel hundred went well because 8 hours a week of consistent, appropriately-fatigued riding is a genuinely good preparation for a 6-hour endurance event. Consistency is a real training effect. It just isn’t the same training effect as progressive overload in a targeted energy system.
The trade, stated plainly
Block-based plans encode intent. Join encodes availability.
If you miss a session in a block plan, you’ve damaged something specific and you know what it was: you lost a VO2 session in a VO2 block, so either you make it up or that block is 25% less effective. The plan is brittle and the brittleness is informative. Join is robust and the robustness is silent. It absorbs the miss so smoothly that you never register the cost, and eleven weeks later you’ve done eleven weeks of good, well-recovered, structurally ambiguous training.
Which of those you want depends on something Join can’t know: whether this is a year where you’re chasing a specific number or a year where you’re just trying to ride a lot without falling apart. I’ve written more about how the major platforms differ on exactly this question in AI Coaching Platforms, Tested, including how TrainerRoad and Xert make the opposite trade.
How I’d actually use it
Three things made Join substantially better for me, and none are in the onboarding.
Set your available hours honestly low. I initially gave it optimistic numbers (4 hours Saturday, every Saturday) and it built weeks I was always slightly failing. Dropping Saturday to 3 hours and Sunday to 2 produced a plan I hit 9 weeks out of 11, and the adaptive engine works much better when it’s responding to success than to chronic shortfall.
Use the event system aggressively. Join’s behaviour around a dated A-event is noticeably more structured: taper logic kicks in, and the three weeks before the gravel hundred were the most coherent stretch of the whole block. Volume went 8h 40, 7h 10, 4h 20, with intensity held and long-ride duration cut. If you want structure out of Join, give it deadlines. I now put a fake B-event every 6 weeks, and it sharpens the intervening weeks visibly.
Audit outside the app. Join won’t show you the twelve-week picture in a way that exposes what I found above. Export to intervals.icu, look at time-in-zone by week, and ask whether the shape matches what you thought you were building. Takes five minutes a month.
At £12.99 a month (annual billing works out around £9), it’s priced against TrainerRoad and undercuts a human coach by a factor of fifteen. For a self-coached rider whose calendar is the actual constraint, that’s a strong offer. Go in knowing the app is optimising for the week in front of you, and that somebody still has to hold the season in their head. Currently, that somebody is you.