IntervalEngine : le commentaire sur les pauses disait l'inverse d'Apple
L'en-tête affirmait que `HKLiveWorkoutBuilder.elapsedTime` « exclut déjà les pauses », et en tirait que le moteur n'avait rien à savoir de la pause ni de l'auto-pause. La doc Apple dit le contraire, vérifié à la source le 2026-08-20 : « The elapsed time for the workout based on the builder's current contents, including pauses. » Conséquence si on câblait le moteur dessus telle quelle : une pause de 5 min ferait avancer le déroulé de 5 min d'effort — un fractionné mis en pause pour traverser une route se déroulerait à l'arrêt. La propriété qui exclut réellement les pauses est `HKWorkoutBuilder.elapsedTime(at:)` : « The duration of a workout doesn't include intervals between pause and resume events. » Les deux textes d'Apple se contredisent frontalement ; le choix de la source de temps reste à faire avant le câblage. Le moteur lui-même reste correct : il n'intègre que ce qu'on lui pousse. Aucun comportement modifié, 57 tests Swift toujours verts. COWORK gagne l'analyse complète du câblage (3 couches, le serveur sait déjà produire les étapes via _blocks_from_session) pour reprise à froid. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
53
COWORK.md
53
COWORK.md
@@ -129,6 +129,59 @@ armer `allowsBackgroundLocationUpdates` sans elle termine l'app. Un garde-fou
|
||||
la vérifie au démarrage, mais si elle disparaissait du build, le suivi
|
||||
retomberait silencieusement au premier plan seul.
|
||||
|
||||
## 🔜 Câbler IntervalEngine — analyse du 2026-08-20 (rien de codé)
|
||||
|
||||
`IntervalEngine` **compile sur device** (build validé le 20/08, l'app tourne),
|
||||
mais **aucune vue ne l'appelle** : le moteur est un guide sans itinéraire.
|
||||
|
||||
### Le chaînon manquant
|
||||
|
||||
Le moteur attend un `CoachSessionPlan` (liste d'étapes : durée, zone, bornes
|
||||
bpm). **Rien ne le lui fournit** — `ConnectivityManager` reçoit les zones, le
|
||||
`CoachWidgetSnapshot` et la routine, mais aucun plan structuré. Vérifié par
|
||||
lecture du fichier, pas supposé.
|
||||
|
||||
En revanche **le serveur sait déjà produire ces étapes** :
|
||||
`coach_sportif/web/fitness_export.py::_blocks_from_session` déplie une séance
|
||||
en blocs chronométrés, répétitions comprises (un bug de prod du 12/08 avait
|
||||
fait disparaître un 7×(1'C/1'M) : les `repeat` sont désormais dépliés), et
|
||||
`_zone_bpm(zone, hr_zones)` convertit une zone en bornes bpm. Ces briques
|
||||
servent déjà à l'export TCX Workout.
|
||||
|
||||
Indice que le chemin était prévu : les `CodingKeys` de `CoachPlanStep` sont en
|
||||
snake_case (`duration_sec`, `hr_zone`, `hr_bpm_min`…) — le type a été écrit
|
||||
pour décoder du JSON venant du serveur.
|
||||
|
||||
### Les trois couches, dans l'ordre
|
||||
|
||||
1. **Serveur (Python, testable sans Mac)** — une route rendant la séance du
|
||||
jour au format `CoachSessionPlan`, en réutilisant `_blocks_from_session` et
|
||||
`app.current_zones()` (règle 9 du CLAUDE.md : jamais un % de FCmax
|
||||
générique). ✅ Commencer par là : le JSON se juge dans un navigateur avant
|
||||
qu'une ligne de Swift n'en dépende.
|
||||
2. **iPhone** — pousser ce plan vers la montre par `WCSession`, à côté de ce
|
||||
qui part déjà.
|
||||
3. **Montre** — `ConnectivityManager` publie un `sessionPlan` ; une vue appelle
|
||||
`engine.update(elapsed:distance:)` à chaque tick et joue une haptique sur
|
||||
`events.transitions`.
|
||||
|
||||
### ⚠️ Le piège à trancher AVANT de câbler
|
||||
|
||||
L'en-tête d'`IntervalEngine.swift` affirmait que
|
||||
`HKLiveWorkoutBuilder.elapsedTime` « exclut déjà les pauses ». **La doc Apple
|
||||
dit l'inverse**, vérifié à la source le 20/08 : *« The elapsed time for the
|
||||
workout based on the builder's current contents, including pauses. »*
|
||||
|
||||
Câbler le moteur dessus telle quelle ferait avancer le déroulé **pendant les
|
||||
pauses** — un fractionné mis en pause pour traverser une route se déroulerait
|
||||
à l'arrêt. La propriété qui exclut réellement les pauses est
|
||||
`HKWorkoutBuilder.elapsedTime(at:)`. Les deux textes d'Apple se contredisent
|
||||
frontalement ; le commentaire du fichier a été corrigé, **le choix de la source
|
||||
de temps reste à faire**.
|
||||
|
||||
⚠️ Et jamais un `Timer` de vue SwiftUI : il ne tourne pas écran éteint, donc
|
||||
pendant l'essentiel d'une séance (même famille de piège que `VmaTestView`).
|
||||
|
||||
## 👉 À reprendre
|
||||
- ✅ **Phase 4 login — FAIT & DÉPLOYÉ** (révocation Apple à la suppression de compte) : code complet côté backend `coach_sportif` (commit `5ae6e2d`) + clé `.p8` déployée sur le VPS prod (vérifié 2026-06-26). Rien à coder. Détails : `coach_sportif/COWORK.md`.
|
||||
- **iOS — bloqué Mac** : builder + uploader TestFlight le natif accumulé (login Apple+Google natif, watchOS live, HeartRateRangeAlert). Sur le Mac : `cd ~/coach-ios && git pull && npm install && npx cap sync ios && open ios/App/App.xcodeproj` → Clean Build Folder → Archive → Upload.
|
||||
|
||||
Reference in New Issue
Block a user