WattFlow freshness-gids

Herstel eerst. Daarna pas de training.

Freshness in WattFlow is een uitlegbare herstelscore op basis van Apple Health. De score kijkt naar slaap, rustige HRV, rusthartslag, ademhaling, temperatuur en recente belasting, zet die vast op een logisch ochtendmoment en gebruikt het resultaat daarna om actieve plantrainingen gecontroleerd lichter of rustiger te maken.

1. Kort samengevat

De huidige Freshness-engine is geen generieke “wellness score”, maar een trainingsgerichte readinesslaag. Alles loopt via één centrale flow: Apple Health lezen, ankerdag bepalen, score berekenen, snapshot opslaan en diezelfde score gebruiken in UI, widget en planadvies.

Apple Health Freshness gebruikt alleen Health-data voor herstelanalyse.
85 Neutrale referentiescore waar lage confidence naartoe terugtrekt.
2 Maximaal aantal echte intraday scorewijzigingen per analyse-dag.
Plan-ready De uitkomst wordt direct gebruikt door FreshnessTrainingAdvisor.
Belangrijk ontwerpprincipe. Freshness mag streng zijn, maar moet uitlegbaar blijven. Daarom werkt de engine met expliciete drempels, penalties, illness-caps en een zichtbaar morning lock, in plaats van een ondoorzichtige “AI-score” zonder redeneerlaag.

2. Welke data Freshness leest

Freshness wordt alleen berekend als Apple Health-sync aan staat en de Health-autorisatie echt verleend is. Zo niet, dan maakt de app de opgeslagen snapshots leeg en laat de planlaag geen herstelgestuurde aanpassingen zien.

2.1 Apple Health inputs

Input Waarvoor gebruikt Belangrijk detail
HRV (SDNN) Herstel en readiness Niet elk HRV-sample telt mee; selectie gebeurt op rust, slaap en ochtendcontext.
Rusthartslag Herstel en illness-signalen Mediaan binnen het recovery-observatievenster.
Slaapduur Morning readiness Komt uit een gemergde hoofd-slaapperiode, niet uit een rollend 24-uurs totaal.
Ademhaling tijdens slaap Illness- en herstelcontext Wordt alleen gelezen op slaapintervallen.
Polstemperatuur-afwijking Illness-signalen Alleen positieve afwijkingen duwen de score omlaag.
Active Energy en stappen Carry-over load en intraday load Worden in twee periodes opgesplitst: voor slaap en sinds ontwaken.
Workouts Loadclassificatie Een workout geldt als duidelijke belasting bij >= 30 min of >= 250 kcal.

2.2 Slaap als anker

De engine bouwt geen analyse uit “nu minus 24 uur”, maar vanuit een anker. Dat anker is bij voorkeur de laatste hoofd-slaap, zodat de ochtendscore voelt als een echte herstelscore voor vandaag.

Anchor selectie
  • Alle asleep-categorieën uit Apple Health worden eerst samengevoegd.
  • Blokken met een tussenruimte tot 30 minuten worden samengevoegd.
  • Een hoofd-slaapblok wint als het minstens 3 uur duurt en eindigt tussen 03:00 en 12:00.
  • Als dat niet lukt, gebruikt WattFlow een fallback-slaapblok van minstens 2 uur.
  • Als ook dat niet lukt, valt de engine terug op een inferrede ochtend-anker rond 07:00.
Periodeverdeling
  • Carry-over period: vorige wakkere periode tot aan de anker-slaap of ankerdatum.
  • Current-day period: vanaf ankerdatum tot nu of tot de volgende slaapstart.
  • Recovery interval: vanaf slaapstart of 3 uur voor ankerdatum tot maximaal 4 uur na ankerdatum.
  • Daardoor kan belasting van gisteren wel meetellen, maar niet op dezelfde manier als frisse ochtenddata.

2.3 HRV-selectie

HRV is de gevoeligste input in de hele engine. Daarom worden workouts rondom HRV uitgefilterd en kiest WattFlow niet blind voor “de laatste sample”, maar voor de meest bruikbare rustige subset.

Stap Regel
Validatie Een HRV-sample is ongeldig als het tijdens een workout valt, of binnen 90 minuten na het workout-einde.
Subset 1 sleepHRVSamples: HRV die overlap heeft met de anker-slaap.
Subset 2 morningHRVSamples: HRV tussen ankerdatum en maximaal 3 uur later.
Subset 3 calmHRVSamples: rustige samples buiten slaap en buiten morning-subset.
Keuzevolgorde Slaap met niet-low quality, anders calm met niet-low quality, anders morning, anders slaap, anders calm, anders alle geldige HRV.
Aggregatie De representatieve HRV van de dag is de mediaan van de geselecteerde HRV-samples.

HRV quality

  • 0 samples = none
  • 1 sample = low
  • 2 samples = medium
  • 3+ samples = high

Wat dit praktisch betekent

Eén losse ochtendwaarde mag meedoen, maar telt lichter. Pas bij meerdere rustige samples wordt HRV stevig genoeg om echt een lock te dragen en de volledige penalty of steun mee te nemen.

3. Zo wordt de score opgebouwd

De uiteindelijke Freshness-score komt uit een vaste keten: baselines bouwen, statussen bepalen, penalties optellen, confidence toepassen, illness-cap toepassen, morning lock beslissen en pas daarna eventueel intraday bijsturen.

3.1 Baselines en ratios

Metric Baselinevenster Aggregator Ratio
HRV Laatste 28 geldige dagen Mediaan today / baseline
Rusthartslag Laatste 28 dagen Mediaan today / baseline
Slaapduur Laatste 14 dagen Gemiddelde today / baseline
Ademhaling Laatste 14 dagen Mediaan today / baseline
Active energy Laatste 7 dagen Gemiddelde today / baseline
Stappen Laatste 7 dagen Gemiddelde today / baseline

3.2 Statusregels en penalties

Metric Normal Deviated Strong deviation Penalty
HRV ratio >= 0.95 0.85 t/m 0.94 < 0.85 12 / 24, daarna vermenigvuldigd met sample-factor
Rusthartslag ratio <= 1.03 1.03 t/m 1.08 > 1.08 10 / 20
Slaap ratio >= 0.90 0.75 t/m 0.89 < 0.75 10 / 20
Ademhaling ratio <= 1.05 1.05 t/m 1.12 > 1.12 Geen directe scorestraf, wel illness-signaal
Temperatuur < 0.3 °C afwijking 0.3 t/m 0.49 °C >= 0.5 °C Geen directe scorestraf, wel illness-signaal
HRV sample-factor
  • 0 samples -> factor 0.0
  • 1 sample -> factor 0.5
  • 2 samples -> factor 0.75
  • 3+ samples -> factor 1.0
Activity load
  • Carry-over high bij clear workout, energy-ratio > 1.35 of steps-ratio > 1.40
  • Carry-over medium bij energy-ratio > 1.10 of steps-ratio > 1.10
  • Current-day gebruikt een tijdgeschaalde baseline; voor 09:00 wordt high nog gematigd naar medium

Combo-penalties

  • HRV strongDeviation + rusthartslag strongDeviation -> +10
  • Slaap strongDeviation + carry-over load high -> +8

Carry-over recovery factor

  • HRV normaal én slaap normaal -> factor 0.5
  • Eén van beide normaal -> factor 0.75
  • Beide niet normaal -> factor 1.0

3.3 Confidence en illness cap

Freshness straft niet onbeperkt door als data ontbreekt. In plaats daarvan schuift de ochtendscore bij lage zekerheid terug richting een neutrale referentie van 85.

Confidence-penalty Waarde
Geen HRV0.2
Geen rusthartslag0.2
Geen slaap0.2
Geen ademhaling of temperatuur0.1
Onvoldoende historie0.2
confidence = clamp(1.0 - totalConfidencePenalty, 0.0, 1.0)
rawBeforeIllnessCap = clamp(100 - totalMorningPenaltyBeforeIllnessCap)
rawFreshness = applyIllnessCap(rawBeforeIllnessCap, illness)
adjustedMorningReadiness =
  applyIllnessCap(
    clamp(85 + (rawFreshness - 85) * confidence),
    illness
  )

Illness detectie

  • Likely als ademhaling sterk afwijkend is en temperatuur afwijkt.
  • Likely ook bij ademhaling afwijkend + temperatuur afwijkend + rusthartslag sterk afwijkend.
  • Possible als minstens twee flags tegelijk aan staan.

Illness caps

  • none -> geen cap
  • possible -> score max 60
  • likely -> score max 35

3.4 Morning lock en intraday

WattFlow laat de score niet de hele ochtend wild bewegen. Eerst probeert de engine te bepalen of er al genoeg signalen zijn om de ochtendscore vast te zetten. Pas daarna mag de dagbelasting nog gecontroleerd doorwerken.

Morning lock
  • Als morning-HRV niet echt verwacht wordt, lockt de score zodra ankercontext en kernsignalen aanwezig zijn.
  • Als morning-HRV wel verwacht wordt, lockt de score zodra HRV-quality minstens medium is.
  • Vanaf 09:00 lockt de score ook met ankercontext + kernsignalen.
  • Vanaf 11:00 volgt een harde fallback-lock, ook als het ochtendbeeld nog niet perfect compleet is.
Intraday
  • Current-day load geeft na lock een intraday-aanpassing van 0, -4 of -9.
  • Verschillen tot en met 2 punten worden genegeerd.
  • Maximaal 2 echte scorewijzigingen per dag.
  • Elke intraday sprong wordt begrensd op 10 punten per stap.
if locked == false:
  morningReadinessScore = clamp(85 + (adjustedMorningReadiness - 85) * 0.5)
else:
  morningReadinessScore = adjustedMorningReadiness

candidateFreshness = applyIllnessCap(
  clamp(morningReadinessScore + intradayAdjustment(currentDayLoad)),
  illness
)

4. Wat de score in de app doet

De score blijft niet in een debuglaag hangen. Ze komt direct terug in de plan-tab, de Freshness-detailview, de widgetsnapshot en vooral in het voorbereiden van de volgende plansessie.

4.1 DailyState en UI

DailyState bevat onder meer

  • freshness
  • illness
  • generalLoad
  • scorePhase
  • confidence
  • shortReason en detailedReason
  • morningReadinessScore en morningLockedAt

Publieke afleiding

  • RecoveryStatus good bij 70 tot 100
  • moderate bij 40 tot 69
  • low onder 40
  • Widgettekst wordt overruled door illness-signalen: “Mogelijk ziek” of “Rust of herstel”.

4.2 Plan-aanpassingen

Elke geplande workout loopt via FreshnessTrainingAdvisor.prepareWorkout(...). Daardoor kan een sessie ongewijzigd blijven, lichter worden of vervangen worden door een herstelrit.

Voorwaarde Actie Intensity factor Duration factor
illness == likely Replace 0.65 0.60
illness == possible + intensieve workout Replace 0.72 0.70
generalLoad == high + intensieve workout Replace 0.75 0.75
freshness < 40 + intensieve workout Replace 0.72 0.65 tot 0.85, afhankelijk van score
freshness < 40 + rustige workout Reduce 0.90 0.65 tot 0.85
freshness 60-69 Reduce 0.97 0.95
freshness 50-59 Reduce 0.95 0.90
freshness 40-49 Reduce 0.92 0.85
Wat is “intensief” in deze laag? Voor de advisor tellen categorieën vo2max, omslagpunt en test als blokken die de engine liever vervangt dan slechts licht terugschaaft.

4.3 Freshness prompt

Naast de deterministische advisor kan WattFlow ook een compacte freshness-prompt opbouwen. Die prompt is veel lichter dan het volledige AI-plancontract en is bedoeld om een externe AI kort context te geven over herstel, belasting en aankomende sessies.

User freshness: 64
Illness: possible
General load: medium
Confidence: 0.70

Upcoming workouts:
tuesday: Basis duur
thursday: Omslag bouwen
saturday: Lange duur

Goal:
FTP verhogen

Event days:
20 jun 2026

Request:
Adjust plan, keep structure, reduce overload.

5. Relevante bronbestanden

Bestand Rol
WattFlow/Services/AppleHealthService.swift Leest Health-data, bouwt anchors, splitst carry-over en current-day periodes, selecteert HRV.
WattFlow/Services/FreshnessCalculator.swift De hoofdengine: baselines, statusregels, penalties, confidence, illness cap, morning lock en intraday clamp.
WattFlow/Domain/FreshnessModels.swift Publieke modellen zoals DailyState, snapshots, breakdowns en load/illness enums.
WattFlow/Services/FreshnessTrainingAdvisor.swift Past planworkouts aan op basis van Freshness en beslist keep / reduce / replace.
WattFlow/Services/FreshnessPromptGenerator.swift Bouwt een compacte herstelprompt voor externe AI.
WattFlow/Views/FreshnessDetailView.swift Detailweergave met score-ring, metric cards, charts en penalty-uitleg.
WattFlow/AppModel.swift Refresh-orchestratie, snapshot-opslag en koppeling naar de planlaag.
Verwante documenten. Voor de planlaag en AI-prompts ga door naar WattFlow_Trainingen.html. Voor dagelijks gebruik en support blijft de operator handleiding handiger. Voor volledige app- en datarouting blijft de hoofdgids leidend.

Deze freshness-gids is afgestemd op de huidige Freshness-engine, planadvisor en Health-flow zoals die in de code staan op 3 april 2026.