# Runbook Mac — le build qui rend l'envoi vérifiable **Écrit le 03/09/2026, à suivre sur le Mac mini.** Compte 20 minutes, dont la moitié d'attente. Ce build ne change rien à ce que la montre reçoit : il rend l'app capable de **dire** ce qu'elle a fait, ce qu'elle ne savait pas faire. Le dossier complet — deux épisodes de « la montre ne dit plus rien », leur chronologie et ce qu'elle élimine — est dans `coach_sportif`, [`docs/GUIDE-MONTRE.md`](../../coach_sportif/docs/GUIDE-MONTRE.md) §5quater et §5quinquies. Ici : les gestes. ## Ce qui change Deux fichiers, **déjà déclarés dans la target App** — donc rien à ajouter dans Xcode, pas de Target Membership à cocher, pas de nouveau framework à lier (WorkoutKit était déjà importé par `CoachWorkoutKit.swift`) : - `ios/App/App/CoachWorkoutKit.swift` - `ios/App/App/CoachWorkoutObserver.swift` Branche : `feat/watch-outdoor`. Le côté serveur est **déjà en prod**, il attend juste que l'app l'appelle. ## 1. Récupérer et compiler ```bash cd ~/coach-ios # ou l'emplacement du clone sur le Mac git checkout feat/watch-outdoor git pull npx cap sync ios open ios/App/App.xcworkspace ``` Dans Xcode : cible **App**, ton iPhone connecté, ▶︎. Rien d'autre à toucher. ⚠️ **Ce code n'a jamais été compilé** — WorkoutKit et HealthKit n'existent pas dans Swift pour Linux, et `tests-linux/` ne couvre que ce qui n'importe que Foundation. Les signatures Apple ont été vérifiées une par une dans la doc DocC avant d'être écrites, mais si quelque chose casse, c'est là que ça cassera : | symptôme | où regarder | |---|---| | `value of type 'HKWorkout' has no member 'workoutPlan'` | l'extension vient de WorkoutKit : vérifier que `import WorkoutKit` est bien pris (il est sous `#if canImport`) | | erreur sur `case .custom(let custom)` | `WorkoutPlan.workout` est l'enum `WorkoutPlan.Workout` — cas `custom`, `goal`, `pacer`, `swimBikeRun` | | erreur de conversion sur `sw.date` | c'est un `DateComponents`, pas une `Date` — d'où le `Calendar.current.date(from:)` | ## 2. Vérifier sans courir (2 minutes, dans le canapé) 1. Ouvre **Programme**, la séance du jour, et appuie sur l'envoi Apple Watch. Le message doit maintenant **nommer la séance programmée** : « Programmée sur la montre : CDC · … ». - S'il dit « la montre ne la liste pas encore » : le scheduler n'a pas encore publié — regarde *Exercice → Programmées* au poignet avant de conclure. - S'il dit « Autorisation « Séances programmées » absente » : **c'est la réponse au silence**. Réglages iPhone → coach → autoriser, puis renvoyer. C'est exactement ce qu'une réinstallation de l'app remet à zéro, et l'ancienne version affichait « Envoyé » quand même. 2. Console Xcode (facultatif), filtre `CoachWorkoutKit` : `schedule OK`, `authorizationState`. ## 3. Après ta prochaine séance Le plugin remonte tout seul, en fin de séance, si elle venait de la séance programmée ou d'un départ à la main. Pour le lire : ```bash # sur nexus, là où vivent les données (node n'y est pas installé) venv/bin/python3 tools/watch_alert_check.py --dump /tmp/wac.json # puis en local, là où node existe python3 tools/watch_alert_check.py --from /tmp/wac.json ``` Trois réponses possibles, et une seule était disponible jusqu'ici : - **« Séance lancée depuis la séance programmée »** → les alertes comptées étaient bien dues. Si tu n'as rien entendu, le défaut est ailleurs que dans l'envoi et le lancement. - **« Séance lancée À LA MAIN »** → aucune alerte n'était possible, le silence est normal. C'est le cas que rien ne savait détecter, et qui devient plausible depuis que la Polar est la montre de sport. - **« Origine inconnue »** → séance antérieure au build, ou lecture en échec. Ce n'est **pas** un « non » : l'app préfère se taire qu'affirmer à tort.