WattFlow freshness-gids

Herstel eerst. Daarna pas de training.

Freshness is in de app nog steeds de zichtbare naam, maar onder water werkt WattFlow nu met een slaap-geankerde readiness-architectuur. De engine bouwt eerst een morning readiness op uit slaap, herstel en carry-over van gisteren, laat daarna alleen begrensde intraday bijsturing toe en gebruikt die ene uitkomst vervolgens in UI, widget, planadvies en AI-context. Daar bovenop zit nu ook een lichte subjectieve laag: check-ins en feedback helpen de score menselijker en persoonlijker te maken, zonder dat het systeem een black box wordt.

Leesgids versus audit. Deze pagina blijft de menselijk leesbare uitleg van Freshness. Voor de exacte implementatie, drempels, opslagkeys, lockredenen en codepaden is er nu ook WattFlow_Freshness_Audit.html.

1. Kort samengevat

De huidige Freshness-engine is geen generieke wellnessscore en ook geen medisch model. Het is een trainingsgerichte readinesslaag: eerst bepalen hoe hersteld je ochtend eruitziet, daarna voorzichtig volgen wat er overdag nog verandert. Alles loopt via één centrale flow: Apple Health lezen, anker-slaap kiezen, morning readiness berekenen, day score bijstellen, snapshot opslaan en diezelfde uitkomst gebruiken in UI, widget, training advisor en promptgenerator.

Waarom deze laag in de app zit

WattFlow wil niet alleen een training starten, maar ook context geven voor vandaag. Daarom leeft Freshness nu niet verstopt in een experimenteel hoekje, maar zichtbaar in Vandaag, Schema en Meer. De score moet helpen om beter te doseren, niet om meer dashboards te bouwen.

Waarom “Hoe voel je je?” bestaat

Slaap, HRV en rusthartslag zien veel, maar niet alles. Spierpijn, mentale stress, zware benen of een verrassend slechte nachtbeleving zijn precies het soort context dat sensoren missen. Daarom laat WattFlow je check-in meetellen, maar bewust licht en ondersteunend.

Apple Health Apple Health levert de objectieve herstel- en belastingsignalen.
Morning readiness De dag start met een slaap-geankerde ochtendscore. Pas daarna volgt beperkte dagbijsturing.
Confidence Beïnvloedt de score echt en verklaart ook wanneer de engine terughoudender moet zijn.
Trainability Naast herstel geeft WattFlow ook aan hoe verstandig een zwaardere trainingsprikkel vandaag is.
Check-in “Hoe voel je je?” stuurt de score bewust licht bij en helpt vooral nuance aanbrengen.
Feedback Na de rit kan jij teruggeven of de score klopte. Dat voedt later begrensde personalisatie.
Belangrijk ontwerpprincipe. Freshness mag streng zijn, maar moet uitlegbaar blijven. Daarom is het systeem modulair opgebouwd uit slaap, autonomic recovery, load context, caution, confidence, trends en trainability. Er is geen tweede parallelle score-engine en ook geen black-box AI die de echte score bepaalt.

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 uit Apple Health Autonomic recovery In de huidige overgangslaag gebruikt WattFlow een log-getransformeerde HRV proxy als opstap naar readiness-logica rond RMSSD / lnRMSSD.
Rusthartslag Autonomic recovery en caution Vergeleken met je persoonlijke baseline, niet met populatiegrenzen.
Slaapduur, fragmentatie, consistentie, diepe slaap Sleep component De slaapcomponent is breder dan alleen duur en is altijd gekoppeld aan de laatste hoofd-slaap.
Ademhaling tijdens slaap Caution-signaal Wordt aanvullend gebruikt, niet als hoofdscore.
Polstemperatuur tijdens slaap Caution-signaal Alleen met voldoende nachten eigen historie; tot die tijd neutraal.
Workouts, active energy en stappen Load context Workouts zijn leidend; gewone dagelijkse activiteit is vooral ondersteunende context.
Subjectieve check-in Lichte modifier Vermoeidheid, spierpijn, stress en slaapkwaliteit sturen de score beperkt bij.
Trainingsfeedback Persoonlijke calibratie “Te hoog / klopt / te laag” en “lichter / zoals verwacht / zwaarder” helpen later bij het afstemmen van bias en betrouwbaarheid.
Dutjes Day score-context Een geldig dutje kan een beperkte bonus geven, maar nooit boven de morning readiness uitkomen.
Feedback en historie Personalisatie Feedback stuurt geen black-box model, maar wel begrensde persoonlijke calibratie binnen vaste regels.

2.2 Slaap als anker

De engine bouwt geen analyse meer uit “nu minus 24 uur”, maar vanuit een anker. Dat anker is bij voorkeur de laatste hoofd-slaap, zodat de ochtendscore echt voelt als herstel voor vandaag in plaats van een willekeurig tijdvenster.

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 hersteldata uit slaap en rustige ochtend.

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. In de huidige implementatie is dit nog een readiness-proxy boven op Apple Health HRV-data, met als expliciete richting een RMSSD / lnRMSSD-gedachte in plaats van absolute SDNN-drempels.

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 als overtuigend recovery-signaal mee te tellen.

2.4 Check-ins, feedback en opslag

Freshness leest dus niet alleen Apple Health, maar ook een kleine lokale gebruikerslaag. Die laag is bewust simpel: niet bedoeld als dagboek, maar als corrigerende trainingscontext. Alles wordt lokaal in de gedeelde appgroep opgeslagen, zodat dezelfde state ook voor widgets en andere appdelen beschikbaar blijft.

Onderdeel Hoe het werkt Waarom zo
Check-in Één check-in per analysedag. Een nieuwe save overschrijft de vorige voor dezelfde dag. Freshness heeft dagcontext nodig, geen stapel losse meningen op dezelfde ochtend.
Feedback Feedbackrecords worden op analysedag samengevoegd, zodat scorefeedback en trainingsgevoel samen één dagbeeld vormen. De app wil leren van de dag, niet van elk los knopje als aparte waarheid.
Bewaarlimieten Check-ins: 30 recente dagen. Feedback: 60 recente dagen. Genoeg voor trends en personalisatie, zonder eindeloze opslag of oude ruis.
Opslag FreshnessUserSignalsStore in app group group.app.ergtrainer.shared. Widgets en app gebruiken dan dezelfde persoonlijke Freshness-context.
Refreshgedrag Na een check-in of feedback laat AppModel de Freshness-engine direct opnieuw lopen. De gebruiker moet de bijgestelde context meteen terugzien.

3. Zo wordt de score opgebouwd

De uiteindelijke Freshness-score komt uit een vaste keten: persoonlijke baselines opbouwen, componenten scoren, caution en confidence toepassen, morning readiness vastzetten en daarna alleen begrensd intraday bijsturen.

3.1 Baselines en ratios

Metric Baselinevenster Aggregator Extra context
HRV proxy Laatste 28 geldige dagen Mediaan + rolling mean WattFlow bewaart ook spreiding en HRV CV om stabiliteit en ruis mee te nemen.
Rusthartslag Laatste 28 dagen Mediaan Wordt als recovery-indicator altijd tegen je eigen normaal afgezet.
Slaap Laatste 14 dagen Gemiddelde / mediaan per onderdeel Duur, fragmentatie, midpoint-consistentie en diepe slaap hebben ieder hun eigen referentie.
Ademhaling Laatste 14 dagen Mediaan Alleen als caution-context.
Load context Laatste 3 en 14 dagen Gemiddelde load-units WattFlow onderscheidt acute en chronische load plus hun verhouding.
Geen populatie-drempels. Het model normaliseert signalen vooral tegen je eigen historie. Daardoor gaat het minder om “goed of slecht voor iedereen” en meer om “wat wijkt voor jou af van je normale patroon?”.

3.2 Componenten en score-opbouw

Component Hoofdinput Rol in morning readiness Opmerking
Sleep component Slaapduur, fragmentatie, consistentie, diepe slaap Vormt een expliciet deelscoreblok Diepe slaap telt bewust licht mee en domineert de score niet.
Recovery component HRV proxy, rusthartslag, HRV-stabiliteit Vormt het autonomic recovery-blok HRV-stabiliteit gebruikt rolling spreiding en CV als extra context.
Load context Carry-over workouts, energy, stappen, acute/chronic verhouding Remt de ochtendscore als er nog belasting doorwerkt Workouts zijn leidend; gewone dagelijkse activiteit is veel minder zwaar.
Caution Ademhaling, temperatuur, rusthartslag, subjectieve signalen Kan de score cap-en en trainability verlagen Geen medische diagnose; wel een expliciete voorzichtigheidslaag.
Confidence Compleetheid, historie, conflictsignalen Dempt extreme uitkomsten richting neutraal Confidence is dus niet alleen decoratie, maar een echte modifier.
Sleep component
  • Duur: zwaarste gewicht
  • Fragmentatie: middengewicht
  • Slaapconsistentie: middengewicht
  • Diepe slaap: lichte nuance
Recovery component
  • HRV proxy versus persoonlijke baseline
  • Rusthartslag versus persoonlijke baseline
  • HRV stabiliteit of instabiliteit
  • Trendcontext als extra nuance

Load context

  • Acute versus chronische load wordt apart gevolgd.
  • Carry-over van gisteren telt mee in de morning readiness.
  • Day score gebruikt daarna current-day load sinds ontwaken.

Subjectieve check-in

  • Vermoeidheid, spierpijn, stress en slaapkwaliteit.
  • Werkt bewust licht bij en is nooit dominant.
  • Wordt ook gebruikt als caution- en trendcontext.
Waarom die check-in licht blijft. De tekst in de app zegt het bewust letterlijk: “Deze check-in stuurt je Freshness licht bij. Hij is bewust ondersteunend en niet dominant.” Dat is geen copytruc, maar productlogica. De score mag menselijker worden door subjectieve context, maar de app wil voorkomen dat één slechte mood de volledige trainingslaag overneemt.

3.3 Confidence en illness cap

Confidence en caution zijn volwaardige lagen in de engine. Confidence zegt hoe stevig de score staat. Caution zegt of meerdere signalen samen om extra voorzichtigheid vragen. Beide lagen zijn uitlegbaar.

Confidence-zakker Effect
Geen HRV, RHR of slaapConfidence daalt zichtbaar en de score wordt teruggetrokken richting neutraal.
Onvoldoende historiePersoonlijke baselines en trends krijgen minder gewicht.
Geen check-inGeen blokkade, maar wel iets minder vertrouwen in de totale context.
Conflicterende signalenConfidence daalt en de uitleg meldt expliciet dat signalen niet helemaal dezelfde kant op wijzen.
Nap-onzekerheidEen dutje kan helpen, maar nooit de score boven je ochtendbasis tillen.
morningReadiness =
  weighted(sleep, recovery, load, subjective)
  - cautionAdjustment
  + trendAdjustment

freshnessMorning =
  confidenceAdjusted(morningReadiness)
  |> applyCautionCap()

Caution / illness

  • Ademhaling, temperatuur, rusthartslag en subjectieve signalen worden samen bekeken.
  • De laag blijft deterministisch en geeft altijd redenen terug.
  • De app gebruikt dit als trainingscontext, niet als diagnose.

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 wordt geprobeerd de morning readiness stevig vast te zetten. Pas daarna mag de day score nog gecontroleerd bewegen door workouts of een geldig dutje.

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.
Day score
  • Workouts en duidelijke huidige dagbelasting kunnen de day score verlagen.
  • Een geldig dutje kan een beperkte bonus geven, maar nooit boven de morning readiness.
  • Maximaal 2 echte scorewijzigingen per dag.
  • Elke intraday stap blijft begrensd en uitlegbaar.
morningReadinessScore = locked ? adjustedMorningReadiness : provisionalMorningReadiness
dayScore = min(
  morningReadinessScore,
  morningReadinessScore + intradayAdjustment + napBonus
)

3.5 Personalisatie en neutraal profiel

Onder de score zit nu ook een expliciet personalisatieprofiel. Dat profiel start neutraal en schuift pas op als er genoeg historie, check-ins en feedback zijn. WattFlow gebruikt hier geen vrij lerend model, maar een set begrensde gewichten en betrouwbaarheden.

Neutraal profiel Startwaarde Betekenis
HRV-gewicht0.34Hoe zwaar autonome hersteldata meeweegt in de totale score.
RHR-gewicht0.22Rusthartslag als tweede herstelanker naast HRV.
Slaapgewicht0.28Slaap blijft een hoofdcomponent en niet alleen een randvoorwaarde.
Subjectief gewicht0.08De check-in is ondersteunend, niet leidend.
Load-gewicht0.18Recente belasting remt de score waar nodig af.
Caution-gewicht0.18Voorzichtigheidssignalen krijgen een echte remfunctie.
Recovery half-life1.2 dagenHoe lang eerdere belasting ongeveer doorwerkt.
Score bias0Neutraal startpunt totdat feedback laat zien dat de score systematisch te hoog of te laag zit.
Wat feedback hier doet

Als jij vaker “te laag” teruggeeft dan “te hoog”, dan mag het profiel de scorebias heel beperkt omhoog trekken, en omgekeerd. Dat gebeurt binnen vaste grenzen van -6 tot +6. Het systeem leert dus voorzichtig, niet onbeperkt.

Wat late training hier doet

De calculator houdt nu ook lateTrainingSensitivity bij. Wie vaker laat traint en daarna slechter slaapt of lagere HRV laat zien, krijgt een profiel waarin carry-over en herstelverval iets zwaarder meetellen.

4. Wat de score in de app doet

De score blijft niet in een debuglaag hangen. Ze komt direct terug in Vandaag, Schema, Meer, de Freshness-detailview, de widgetsnapshot, de training advisor en de AI-context. De app gebruikt nog steeds de naam Freshness, maar de inhoud is readiness-gedreven.

4.1 DailyState en UI

DailyState bevat onder meer

  • freshness
  • trainabilityScore en trainabilityLevel
  • illness
  • generalLoad
  • scorePhase
  • confidence
  • confidenceLevel en cautionLevel
  • shortReason en detailedReason
  • dominantReason en changedReason
  • 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”.
  • Vandaag toont de dagcontext, de plankaart en snelle route naar training of schema.
  • Schema toont dezelfde score als plancontext boven de catalogus.
  • Meer bevat Freshness instellingen: databronnen, privacy en compacte score-uitleg.
  • De huidige detailview toont vooral score, signaalkaarten en achtergrondcontext; subjectieve input en feedback leven nog steeds mee in engine, opslag en advisorlogica.
Waarom check-in én feedback allebei bestaan. “Hoe voel je je?” helpt de score voor vandaag. De feedbackknoppen helpen WattFlow later beter afstemmen hoe betrouwbaar die score en het trainingsadvies voor jou zijn. De ene laag is dus acute context, de andere is langzamere calibratie. In de huidige code zijn beide lagen nog volledig aanwezig via AppModel en FreshnessUserSignalsStore, ook nu de zichtbare UI vooral rond signaalkaarten en dagcontext draait.

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. De advisor kijkt daarbij niet meer alleen naar de ruwe score, maar ook naar caution, confidence, load-context en trainability.

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
trainability == low Replace of reduce 0.74 tot 0.90 0.72 tot 0.78
freshness < 40 + intensieve workout Replace 0.72 0.60 tot 0.80, afhankelijk van score
freshness < 40 + rustige workout Reduce 0.90 0.60 tot 0.80
freshness 60-69 Reduce 0.95 tot 0.97 0.92 tot 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 readiness, confidence, caution, trends, trainability en aankomende sessies. De prompt is dus geen vervanging van de score, maar een contextlaag voor planbijsturing of evaluatie.

User freshness: 64
Morning readiness: 68
Trainability: 61 (controlled)
Illness: possible
General load: medium
Confidence: 0.70 (moderate)
Caution: moderate
Main reason: slaap bleef onder je normale patroon
Score changed: vandaag zie je meer load dan gisteren

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: readiness-componenten, confidence, caution, morning lock, day score, trends, trainability en personalisatie.
WattFlow/Domain/FreshnessModels.swift Publieke modellen zoals DailyState, component snapshots, trend/output types en compatibiliteitslagen voor de app.
WattFlow/Services/FreshnessUserSignalsStore.swift Bewaart subjectieve check-ins, feedback en het persoonlijke calibratieprofiel.
WattFlow/Services/FreshnessTrainingAdvisor.swift Past planworkouts aan op basis van Freshness, confidence, caution, load-context en trainability.
WattFlow/Services/FreshnessPromptGenerator.swift Bouwt een compacte herstelprompt met readiness-context, explanation en trainability.
WattFlow/Views/FreshnessDetailView.swift Detailweergave met score-ring, signaalkaarten en herstelcontext; de subjectieve laag wordt in de huidige code vooral via engine- en opslagpaden gevoed.
WattFlow/AppModel.swift Refresh-orchestratie, snapshot-opslag, subjectieve signalen en koppeling naar planlaag en widgets.
Grenzen van het systeem. Freshness is geen medisch product en doet geen diagnose. Bij beperkte data of korte historie zal confidence lager zijn. Personalisatie werkt alleen binnen vaste, deterministische grenzen en pas als daar genoeg historie en feedback voor beschikbaar is.
Verwante documenten. Voor de letterlijke code-audit ga naar WattFlow_Freshness_Audit.html. 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 met readiness-architectuur, planadvisor, trends, trainability, check-ins, feedback en personalisatie zoals die in de code staan op 13 april 2026.