rides.md

Changelog

Changelog

What shipped, when. No hype.

Feedback as evidence

AI feedback now gets cleaner ride context, planned workout intent, and any athlete notes you choose to add.

Added

  • Athlete notes. Add short context before feedback, like intake, heat, heavy legs, travel, or illness, and it stays saved locally for that ride.
  • Planned workout context. Paired Intervals.icu workouts now send the written plan, compliance, and planned-vs-actual threshold time so feedback does not mistake the workout shape for a fade.
  • Faffing in feedback context. Long, short, and micro stop totals are now included in ride markdown for long-day reads.

Changed

  • Feedback voice is stricter. The model now reads the ride as evidence, separates observed facts from possible explanations, and avoids single-ride causation claims.
  • Oxidation stays cost context. Feedback no longer turns carbohydrate oxidation into a gram-for-gram intake target.
  • Ride markdown is cleaner. Lab and athlete context are merged, route character has its own section, and ride analysis now separates computed facts from local labels.
  • Feedback layout reads like margin notes. The response now uses a field-note paragraph with compact side notes instead of numbered coach bullets.
  • Profile lab results are quieter. CPET setup and lab results were flattened so thresholds, FatMax, and substrate cost read as one instrument panel.

Fixed

  • HR-only rides can still get feedback. Rides without clean power data no longer fail validation before the request.
  • Planned ramps count correctly. Planned time above VT1 or FTP now prorates ramp steps instead of counting the whole step after a threshold crossing.

Race horizon, warmer paper

The planned page has a target now, and the whole app moved to the warm-paper field notebook look.

Added

  • Next up. The next race from Intervals.icu now sits above Planned, so the week has a visible target.
  • Countdown and date. Far-out events show rounded weeks; inside 30 days it switches to days, with the calendar date beside it.
  • Light, dark, and system themes. Switch in the header or let it follow your OS. Charts, the route map, and readouts all adapt.
  • Adventure photos on the home page. The hero shows a different ride each visit, from Sa Calobra to the Icelandic highlands, with coordinates to match.
  • All your training, not just rides. Strength, runs, and swims show up in your planned sessions now, with a link to open the workout video on YouTube.
Planned page showing the next upcoming event above the weekly workout list
The next event sits above the weekly plan, with countdown and calendar date.

Changed

  • Warm-paper redesign. The dark slate interface is now ink on warm paper, with a deeper, quieter green. Same data, calmer page.
  • Readable chart colors. Power curve, substrate, and elevation plots share one distinguishable pigment set instead of neon, and stay legible in either theme.
  • Everything lines up. The menu, page titles, and content start at the same place on every page, with one shared header style across rides, ride, and profile.
  • Planned rides are built around the workout. The session’s profile, your fuel target, and what you’ll burn per hour sit together, not scattered as separate stats.
  • Readiness reads at a glance. A small color-coded chip shows how ready you are, on both the ride and your ride list.
  • The weekly label stays with the workouts. Next 7 days now labels the workout list, not the event above it.
  • Cleaner ride page. The ride view drops the vanity maximums and low-signal power metrics, gathers the headline numbers into one tidy grid, and puts your AI feedback right under the analysis.
  • Faffing, measured. Time Budget now shows moving vs. stopped time and your stop sizes as plain cards, with the elapsed timeline sitting between them.

Fuel by the clock

Your fuel target is set by how long you ride and what your gut can absorb, capped by what you actually burn.

Changed

  • Fuel target follows a duration ladder. 30 g/h up to an hour, 60 to two hours, 90 past that, your gut cap on long days. Jeukendrup’s recommendation chart, not your substrate curve.
  • It shows on every planned ride now. No lab test, no FTP required. Duration and your gut cap are enough.
  • Capped at what you burn. On an easy ride where you oxidize less carb than the ladder asks, the target drops to that. You’re never told to eat more than you burn.
  • Default gut cap stays 90 g/h. 120 has become common practice but isn’t strongly evidenced as necessary, so it’s opt-in once you’ve trained for it.
  • AI feedback leads with the ride. The coach opens with what actually happened, then the numbers, instead of a metrics dump.

Added

  • Z2 / fat-focus note. Genuinely easy rides get a nudge: if you’re training fat adaptation, fuel lighter than the target.
  • Workout profile reads at a glance. The planned-ride bars are coloured at your VT1, grey below and yellow above, and you can hover any block for its watts.

Fixed

  • NP splits and decoupling ignore stopped time. The half-by-half comparison now lines up with your headline NP, and trainer rides with no wheel speed keep their numbers.

Stop math, cleaned up

Time Budget now separates moving, stopped, and stop-size patterns without counting sensor noise as a stop.

Changed

  • Moving time is speed-based. Moving now means record time above 0.5 km/h; standstill is everything else, including device pauses, record gaps, and stationary recording.
  • Stop size table. Long, short, and micro stops now show count, duration, and share of standstill before the chronological table.
  • Micro-stop noise filtered. Stops under 10 seconds are ignored, while 10 second to 5 minute stops are summarized without adding table rows.
  • Pause rows keep their source. Device pauses and record gaps keep details like GPS movement without bringing back the wide Source column.
Time Budget showing moving, standstill, and long, short, and micro stop rows
Time Budget. Moving stays speed-based; stopped time is split by useful duration bands.

Where the time went

Time Budget. See where elapsed time went: moving, standstill, and the stops that mattered.

New

  • Time Budget panel. Moving time, standstill time, and stop-size rows show the stop pattern before the table.
  • Source labels. Device pauses, record gaps, standstill, and coasting. The file can't know whether that was sleep, resupply, ferry, or faffing.
  • Built after analyzing 54 hours to Trieste. Twenty-two hours not moving. Needed to see where that time went.
Time Budget analysis showing stops timeline and table
Time Budget. Long stop blocks from the FIT file, source-labeled.

Oxidation is not intake

Oxidation is what your body burns. Intake is what your gut absorbs. They are related, not equal.

Changed

  • Profile table renamed and reframed. “Carb fuel balance” is now “Substrate cost from lab curve.” Columns are estimated CHO and fat oxidation per landmark, with a one-line physiology interpretation. The old sustainable, −X g/h deficit, and balance point labels are gone — they implied a fueling ledger that doesn’t exist.
  • “Fuel Cost” card renamed to “Estimated Oxidation.” Same numbers, honest name. Ride markdown and AI feedback context follow the same naming.

Added

  • “Oxidation is not intake” section on /method/fueling/. Why glycogen reserves, gut-transporter limits, and endogenous fat oxidation make modeled metabolic cost different from a carbohydrate intake target.

Fueling method

Carb demand is simpler now: raw substrate curve, visible assumptions.

Added

  • Fueling method page. The profile now links to the current calculation: inputs, substrate conversion, planned-vs-completed logic, gut cap, and model history.

Changed

  • Carb demand uses the raw substrate curve. The old VT1-based ×0.85 / ×0.90 / ×0.95 dampening is gone; gut cap and duration now shape the intake target instead. Why it changed.

Readiness on rides

Ready, sleep score, form — where you need them, not where they don't belong.

Added

  • Ready on the planned workout card. Today's workout shows Ready, Sleep score, and Form inline — color-coded green/orange/red so you know before you clip in.
  • Ready on ride pages. Open any ride and the summary shows ride-day readiness context when Intervals.icu has it.

Changed

  • Sleep score replaces sleep hours. A percentage that accounts for your sleep need, not just raw duration.
  • Form replaces TSB. Same number (CTL − ATL), clearer name. Uses the previous day's training load so the value reflects pre-ride state.
  • FTP source docs clarified. CPET thresholds are not treated as FTP — only manual profile entry or FIT device threshold.
  • "Today" label highlighted in brand color on the planned workout list.

Removed

  • Readiness from the profile page. It belongs on rides — planned or completed. The profile is for lab data and settings.

Profile redesign + fuel balance

Profile rebuilt around carb cost at each landmark.

Added

  • Carb fuel balance table on the profile. Shows corrected carb demand, gut cap, fat burn, and whether you can replace what you're spending — at FatMax, VT1, gut-cap match, RER 1.0, and VT2.
  • Gut-cap match point. The wattage where carb demand equals gut absorption. Below it, intake keeps up. Above it, glycogen draw.
  • Planned fueling works without FTP when workout steps use absolute watts. A 2 h @ 160 W session now uses the substrate curve directly.

Changed

  • Profile focuses on landmarks. FatMax, VT1, VT2 are the primary cards. VO₂max and max power demoted to a summary line.
  • CHO correction updated. Four bands using VT1 and RER 1.0 instead of the old three-band VT1-only model.
  • FTP only from you. Manual profile field or FIT device threshold. CPET no longer creates or stores an FTP estimate.
  • Ride feedback markdown trimmed. No raw laps, no full substrate table. Fuel cost and key substrate points in a compact Coach Context block.

Removed

  • Coggan comparison table from the profile.
  • Threshold (FTP) estimate card from the profile. A CPET can inform threshold — it does not hand you FTP.
  • Lab markdown export.

Smarter feedback + security

Better AI feedback, tighter security, no more CDN scripts.

Changed

  • AI feedback uses precomputed fuel cost. Carb demand, fat burn, and energy are calculated from your actual power distribution, not estimated by the model. No more wrong math.
  • Better AI feedback. Shorter, more direct, uses your precomputed data instead of guessing. Structured workouts are evaluated on execution, not design.
  • No more CDN scripts. All JavaScript is bundled locally. Tailwind compiled at build time instead of loaded from a CDN.

Added

  • Numbered action items in feedback with green indicators for scannability.
  • Coach context block in ride markdown. Duration tier, session type, fuel cost summary, recovery, and key substrate points — all pre-digested so the model reads, not guesses.

Security

  • Content Security Policy enforced. script-src 'self' — no external JavaScript can run on rides.md pages.
  • Intervals.icu credentials default to session storage now. Opt in to persist with “Remember this device.”
  • HSTS, X-Frame-Options DENY, Permissions-Policy, strict Referrer-Policy.

Fuel Cost + Recovery + Navigation

Cleaner fueling card, recovery data from Intervals.icu, separate about page.

Changed

  • Fueling → Fuel Cost. Four numbers: g/h, carbs, fat, kcal. No food tips, no advice. The card shows what the ride cost metabolically. The AI feedback says what to do about it.
  • Gut-limited rides show a one-liner when demand exceeds absorption: capped at 90 · body burns 100.
  • Settings → Profile. Same page, clearer name. Markdown export moved to the bottom.
  • About page is now separate from the changelog.

Added

  • Recovery data in ride markdown. If Intervals.icu is connected, the AI feedback now sees your resting HR, sleep, recovery %, and form (CTL/ATL/TSB) for the ride day.
  • AI feedback FAQ on the homepage.
  • Numbered action items in feedback output for better scannability.

Security

  • Content Security Policy enforced. No more CDN scripts — all JavaScript bundled locally.
  • Intervals.icu credentials now default to session storage. "Remember this device" checkbox to persist.
  • Added HSTS, X-Frame-Options DENY, Permissions-Policy, and strict Referrer-Policy headers.

AI feedback

Optional AI feedback on a ride. FIT files still stay local.

Added

  • Get feedback button on /ride/. Streams a Quick Take, metabolic read, pacing notes, and prescriptions for the current ride.
  • Feedback is saved in your browser so revisiting the same ride does not re-run the model. Refresh feedback forces a new run.

Privacy

  • FIT files are still parsed entirely in your browser.
  • Clicking Get feedback sends the ride summary and extracted lab values (thresholds, substrate curve) to OpenAI. No raw files, nothing automatic.

Threshold & timing

FTP estimation got honest. Smart recording got correct. Pauses stopped inflating everything.

Changed

  • Threshold estimate uses the VT1/VT2 midpoint now, not VT2 × 0.75. Labeled as "Threshold (FTP) estimate" — not claimed as measured FTP.
  • FIT-reported threshold_power beats the CPET estimate when both exist. Manual FTP still wins over everything.
  • Zone time, fueling, work (kJ), NP, power curve, and decoupling all weight by real elapsed seconds. Smart-recording FIT files no longer overcount dense sections.
  • Pause gaps (> 10 s between samples) are excluded from energy, zone, and fueling integration.
  • Fueling demand and totals use active time. Duration thresholds (< 45 min, 3–4 h, ≥ 4 h) still use elapsed time to classify the ride.
  • Fallback NP includes zero-power coasting as 0 W instead of dropping it. Descents count.

Fixed

  • Profile FatMax fallback matches /ride/ (~84% VT1, was 55%). Lab-vs-Coggan table and ride zones now agree.
  • Clearing the FTP field no longer leaves a stale "manual" source behind. Downstream labels update correctly.
  • The method page and all docs now match the live math — active hours, single target, midpoint estimate.

Profile & fueling

Profile got simpler. Fueling got a transition zone. The method page caught up.

Changed

  • Fueling target has a real 3–4h bridge now — under 45 min says “Not worth optimizing,” 45 min–3h stays demand-driven, 3–4h floors at 70% of gut cap, 4h+ targets gut cap.
  • Profile is one form, one lab block, one destructive action at the bottom. No duplicate clear buttons.
  • FatMax stayed. Zone 2 estimate is gone. The substrate curve now marks FatMax and FTP directly.
  • The method post now matches the live math instead of documenting an older rule.

Fixed

  • Lab import now replaces the uploader instead of leaving the drop box on screen after a file is loaded.
  • Curve highlights survive window resize now.

Ride & fueling

The ride view got rebuilt. The fueling card got honest. The profile page stopped fighting itself.

New

  • Fueling card — one number, one actionable line. “75 g/h · ~1 bar + 1 gel per hour.” Source badge tells you if it’s from your lab or a guess.
  • Markdown export — full athlete context included. Substrate curve, thresholds, gut cap. One copy gives any AI what it needs.
  • IF per hour in hourly splits. VI is gone — nobody looked at VI per hour.
  • Power zones as bars — vertical, with time and percentage. Reads top to bottom, not scattered across bullets.
  • Hourly merge — last-hour fragments (<30 min) roll into the previous hour. No more misleading 13-minute “H11” rows.
  • New journal post — Three days in Mallorca.

Changed

  • One ride view. Lite view is dead. Progressive disclosure now. Scroll for depth, don’t switch pages.
  • Primary vs secondary stats. Hero split into distance, time, elevation (the ride) and NP, TSS, IF (the load).
  • Human duration. Says 2h 45min now. Because that’s what humans say.
  • Map moved below analysis. You came for the numbers, not the map.
  • Laps collapse, splits don’t. If you rode 10 hours, you want every hour.
  • Context → Profile. Because that’s what it is.
  • Profile page rebuilt — gut capacity lives in the form, consistent width, no more “Thresholds” header for a page that also has weight and gut capacity.
  • Homepage — three cards, no screenshots. Rides, Profile, Analysis. That’s the product.

Fixed

  • Cadence surfaced. Was hidden in “background metrics.” Cadence is not a background metric.
  • Consistent profile width. No more jumps between three container widths.

Fueling from lab data

Drop your spiro XML, get substrate curves and intake estimates. Try it on /profile/.

Indoor bike desk setup during a Z2 ride
Added fueling zones to rides.md. Built it during a Z2 ride, obviously.

New

  • Substrate curves — fat/carb oxidation, VT1/VT2 zones, substrate profiles from your lab XML.
  • Workout fueling estimate — paste a workout, get carb intake range and glycogen burn.
  • Saved profile. Set once, reuse on ride analysis.
  • FTP range derived from VT1/VT2.
  • Demo included. Try it without your own data.

Fixed

  • Below-VT1 correction. Low-intensity workout steps handled properly.
  • Oxidation vs intake — clearly labeled. Same curve, different questions.

Changed

  • Reference labels show what’s from the XML vs what’s derived.
  • GitHub deploys — push to main, site updates.

Demo mode

Drop a file or try a demo — no account needed.

New

  • Demo ride — one click, no upload.
  • Drop-first homepage. Drop zone front and center.

Fixed

  • Decoupling warnings separate metric issues from sensor faults.
  • Demo IF. Rides show IF and threshold estimates correctly.

Polish

Tone pass on ride detail. Better edge-case handling.

New

  • Metric tooltips — more context where it matters.
  • Virtual rides — handled properly. No broken GPX buttons.

Fixed

  • GPX rides. Incomplete route data no longer breaks the page.

Launch polish

Launch polish — icons, metadata, social previews.

New

  • Icons & OG — favicons, Apple touch, OG images. Links look right when shared.
  • SEO metadata. Full set.

Ride page

Ride analysis moved to its own page at /ride/.

New

  • Dedicated analysis page. No longer crammed into homepage.
  • Topo maps. Toggle added.

Detour

Brief detour into route tooling. Mallorca prototypes. Most got removed a day later.

Race execution

From static report to real analysis.

New

  • Race execution panel — hourly pacing, match analysis, elevation splits.
  • Markdown copy. Copy the whole ride as markdown.
  • Editable context — FTP, VT1/VT2, FatMax, weight. Zones update live.
  • Auto-restore. Last ride loads automatically.

Fixed

  • Power curve gaps. Ride data gaps no longer break it.

First deploy

First deploy. Rest day in Mallorca.

Cyclists riding through Sa Calobra in Mallorca
Sa Calobra, Mallorca 2026

New

  • FIT drop — drop a file, see the ride. Map, summary, laps, power curve. Nothing leaves your browser.
  • Wahoo connect. Pull your last rides.
  • Core metrics — NP, TSS, VI, decoupling, work, peak power. Data quality flags when the file is noisy.
  • Gradient route on a dark map.