Les quatre constats restants, corrigés — dont deux sur le chemin qu'il fallait éviter

Sur demande explicite de Sylvain (« pour le reste vas-y »), après le § 1.2 buildé
et vérifié le matin. Les cinq constats de l'audit sont désormais traités.

⚠️ § 2.3 et § 2.4 touchent `WorkoutManager.swift` — la fin de séance du live
workout, que la consigne du 22/09 demandait de ne pas approcher. Fait en ne
changeant AUCUNE logique : les `try?` deviennent des `do/catch` qui journalisent,
et le chemin d'échec gagne la clôture qui lui manquait. La récupération par
`recentlySavedWorkout()` est intacte.

§ 1.3 — `CoachSleep` teste `authorizationStatus` : `.notDetermined` ne se
confond plus avec une nuit sans sommeil, et le serveur cessera d'enregistrer des
nuits vides sur lesquelles `sleep_score.py` calculait une régularité. Un refus
EXPLICITE reste indiscernable d'une absence de données — HealthKit ne le révèle
pas en lecture, par conception. L'en-tête du fichier dit maintenant ce que la
promesse couvre au lieu de promettre plus.

§ 2.3 — le `else` final distinguait deux situations opposées qui y tombaient
ensemble : montre verrouillée (la séance EST écrite) et `endCollection` qui a
levé (rien n'est écrit). Seule la seconde est une perte, et elle seule renseigne
`statusMessage` — annoncer une perte sur une montre verrouillée serait une
fausse alerte.

§ 2.4 — `stopTracking()` d'abord : c'est le seul geste qui réussit à coup sûr et
le seul dont l'omission se paie en batterie pendant des heures. Puis une
tentative de sauvegarde en best-effort, avec `recentlySavedWorkout()` en second
recours. `builder = nil` n'intervient plus qu'après les tentatives — il
détruisait jusqu'ici la seule référence, rendant la perte définitive dans
l'instruction qui l'ignorait.

§ 2.6 — `NSLock` sur le tampon GPS, comme aux quatre autres endroits du même
fichier. ⚠️ Invérifiable sans son déclencheur : un workout à plusieurs
HKWorkoutRoute. Sa correction ne se constatera pas plus que le défaut ne se
manifestait.

⛔ NON COMPILÉS. Le test qui comptera pour § 2.3 et § 2.4 n'est pas un log :
c'est une séance réelle menée jusqu'au bout, puis retrouvée dans Santé et dans
coach. Tant qu'elle n'a pas eu lieu, ce sont des intentions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sylvain Bettinelli
2026-09-24 08:27:17 +00:00
parent a794323314
commit 3b5b61268c
4 changed files with 191 additions and 7 deletions

View File

@@ -2,9 +2,17 @@
> ## ⚠️ § 1.2 A ÉTÉ CORRIGÉ le 24/09, après ce diagnostic
>
> Sylvain a levé le gel sur ce point précis (« tu attends quoi ? »). Le correctif
> est décrit en fin de document, § « Ce qui a été corrigé ». **Les quatre autres
> constats restent ouverts, et le gel tient pour eux.**
> Sylvain a levé le gel sur ce point précis (« tu attends quoi ? »), puis sur
> **les quatre autres** (« pour le reste vas-y »). Les cinq sont donc corrigés :
> § 1.2 buildé et vérifié sur l'appareil, § 1.3 / 2.3 / 2.4 / 2.6 écrits et
> vérifiés en syntaxe, **pas encore compilés**.
>
> ⚠️ **§ 2.3 et § 2.4 touchent `WorkoutManager.swift`**, c'est-à-dire le chemin
> de fin de séance du live workout — ce que la consigne du 22/09 demandait de ne
> pas approcher. Fait sur demande explicite, en ne changeant aucune logique :
> les `try?` deviennent des `do/catch` qui journalisent, et le chemin d'échec
> gagne la clôture qui lui manquait. **À éprouver en séance réelle avant de
> considérer que ça tient.**
>
> ✅ **BUILD FAIT ET VÉRIFIÉ SUR L'APPAREIL, le 24/09.** Le diagnostic de
> `/settings` (« Diagnostiquer et pousser ») affiche sur l'iPhone de Sylvain :
@@ -328,3 +336,69 @@ zones sans date. La doublure `HeartRateZonesStub.swift` est tenue à l'identique
désormais `watchPushed` / `watchReason` jusqu'au JS.
⏳ **Reste à voir au poignet** : que la montre affiche ces bornes pendant une
séance. L'envoi est accepté par iOS ; la livraison est asynchrone.
---
## Les quatre autres, corrigés le 24/09 (« pour le reste vas-y »)
⛔ **Aucun n'est compilé.** Syntaxe vérifiée (`swiftc -parse`), 91 tests du banc
Linux verts — mais ces fichiers importent HealthKit, WatchKit et Capacitor,
absents de Swift pour Linux. Le banc ne les couvre pas et ne peut pas les
couvrir.
### § 1.3 — `.notDetermined` n'est plus confondu avec une nuit vide
`CoachSleep.readSamples` teste désormais `authorizationStatus(for: sleepType)`
et rend `{available: false, reason: "authorization not determined"}`.
⚠️ **Ce qui n'est PAS corrigé, et ne peut pas l'être** : un refus *explicite*
reste indiscernable d'une absence de données. HealthKit ne le révèle pas en
lecture, par conception — c'est une protection de vie privée, pas un oubli
d'Apple. Seul `.notDetermined` est fiable, et c'est le cas fréquent
(réinstallation, permission jamais demandée). L'en-tête du fichier dit
maintenant exactement ce que la promesse couvre, au lieu de promettre plus.
### § 2.3 — « séance sauvée » et « rien de sauvé » ne se confondent plus
Les deux `try?` deviennent des `do/catch`. **La logique de récupération n'a pas
changé** — `recentlySavedWorkout()` reste le repli quand `finishWorkout()` rend
`nil` sur montre verrouillée. Ce qui change : un `endCollection` qui lève est
journalisé, et le `else` final distingue les deux cas, dont un seul est une
perte. Dans ce cas seulement, `statusMessage` le dit à l'écran — une montre
verrouillée n'est pas une perte, et l'annoncer serait une fausse alerte.
### § 2.4 — le GPS s'arrête, et la séance est sauvée si elle peut l'être
`didFailWithError` commence par `stopTracking()` : c'est le seul geste qui
réussit à coup sûr, et le seul dont l'omission se paie en batterie pendant des
heures. Puis une tentative de clôture en best-effort (`endCollection`,
`finishWorkout`), avec `recentlySavedWorkout()` en second recours — une session
qui a échoué refusera souvent de clore, mais ne pas essayer garantissait la
perte. `builder = nil` n'intervient plus qu'à la fin, après les tentatives.
Trois issues, trois messages distincts : « Séance interrompue, mais
enregistrée », « Séance perdue : … », ou le message d'erreur d'origine.
### § 2.6 — le tampon GPS est verrouillé
`collectLocations` protège `all` et `pluginErr` par un `NSLock`, comme les
quatre autres endroits du même fichier le faisaient déjà.
⚠️ **Invérifiable sans le déclencheur** : il faut un workout portant plusieurs
`HKWorkoutRoute` (multisport, reprise après interruption). Avec une seule route,
la boucle n'a qu'une itération — c'est pourquoi le défaut a pu vivre longtemps
sans se manifester, et pourquoi sa correction ne se constatera pas non plus.
### Ce qu'il faut regarder au prochain build
| Quoi | Où | Ce qui prouve |
|---|---|---|
| § 1.3 | `/settings` → synchro santé | Retirer « Sommeil » dans Réglages → Santé, réinstaller : la synchro doit dire « non autorisé », pas enregistrer des nuits vides |
| § 2.3 | Console, catégorie `workout` | Une séance normale ne doit RIEN journaliser de neuf. Les nouveaux logs ne sortent qu'en cas d'échec |
| § 2.4 | Batterie, après une séance interrompue | Le GPS ne doit plus tourner une fois l'écran de fin affiché |
| § 2.6 | — | Rien à voir : le correctif supprime une corruption qui ne se manifestait pas de façon lisible |
⚠️ **§ 2.3 et § 2.4 sont sur le chemin de fin de séance du live workout.** Le
test qui compte n'est pas un log, c'est **une séance réelle menée jusqu'au bout,
puis retrouvée dans Santé et dans coach**. Tant qu'elle n'a pas eu lieu, ces
deux correctifs sont des intentions.