Vérifié dans project.pbxproj avant d'envoyer Sylvain dans Xcode : les quatre cibles réelles sont App, CoachLiveActivity, CoachWatch et CoachWatchWidgetsExtension. Le runbook donnait le nom du DOSSIER (CoachWatchWidgets) pour celui de la cible — il aurait cherché un intitulé inexistant dans l'inspecteur de Target Membership, à l'étape précisément décrite comme celle qui décide de tout. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5.5 KiB
Runbook Mac — Siri + widget Hydratation de la montre
Écrit le 25/09/2026, depuis Linux. Le code Swift est committé ; il reste les étapes Xcode, qui ne peuvent pas se faire d'ici.
⚠️ Nom des cibles, vérifié le 25/09 : la cible watchOS s'appelle
CoachWatchWidgetsExtension— le DOSSIER, lui, s'appelleCoachWatchWidgets. Ce runbook disait d'abord le nom du dossier ; corrigé. Les quatre cibles réelles :App,CoachLiveActivity,CoachWatch,CoachWatchWidgetsExtension.
⛔ Rien de ce code n'a été compilé.
AppIntents,WidgetKitetSwiftUIsont des frameworks Apple, absents de Swift pour Linux — le CLAUDE.md de ce dépôt le dit. Ce qui a été vérifié à la place, par lecture croisée des sources : que chaque symbole appelé existe (CoachQuickLog.append,todayTotal,pending,CoachWidgetStore.load,nextMidnight,fallbackQuickDrinks,resolvedQuickDrinks,waterMlToday,waterGoalMl,asOf), et qu'aucun symbole n'est déclaré deux fois. Les erreurs de type, de concurrence et d'API n'apparaîtront qu'au build.
Ce que ça apporte
| Avant | Après | |
|---|---|---|
| Siri | rien — aucun AppShortcutsProvider |
5 raccourcis, 16 phrases |
| Montre | complications d'affichage | widget Smart Stack qui note un verre |
| Intents | 1, enfermé dans l'extension iPhone | 3, partagés entre 3 cibles |
Fichiers ajoutés / modifiés
ios/App/App/CoachIntents.swift(nouveau) —LogDrinkIntent(déplacé),HydrationStatusIntent,TodaySessionIntent,CoachQuickError.ios/App/App/CoachAppShortcuts.swift(nouveau) — les phrases Siri.ios/App/CoachWatchWidgets/CoachWatchHydration.swift(nouveau) — widget Smart Stack de la montre.ios/App/CoachLiveActivity/CoachQuickWidget.swift— l'intent en a été retiré (il vivait là, invisible des deux autres cibles).ios/App/CoachWatchWidgets/CoachWatchComplications.swift— le widget rejoint leWidgetBundle.
Étapes Xcode
⚠️ Quitter Xcode puis git pull d'abord (règle COWORK : jamais de pull
Xcode ouvert).
1. Target Membership — c'est l'étape qui décide de tout
| Fichier | App | CoachLiveActivity | CoachWatchWidgetsExtension |
|---|---|---|---|
CoachIntents.swift |
✅ | ✅ | ✅ |
CoachAppShortcuts.swift |
✅ | ❌ | ❌ |
CoachWatchHydration.swift |
❌ | ❌ | ✅ |
CoachQuickLog.swift |
✅ | ✅ | ✅ (à vérifier) |
CoachWidgetSnapshot.swift |
✅ | ✅ | ✅ (déjà le cas) |
⚠️ CoachAppShortcuts.swift dans la cible App UNIQUEMENT. Apple attend un
seul AppShortcutsProvider par application ; un second dans une extension
produirait au mieux un doublon.
⚠️ CoachQuickLog.swift doit être dans CoachWatchWidgetsExtension, sinon le widget
de la montre compile mais n'écrit nulle part. Son en-tête le réclamait déjà.
2. Vérifier l'App Group sur la cible Watch
group.ch.hypnotruck.coach sur CoachWatch ET CoachWatchWidgetsExtension.
Vérifié depuis Linux le 25/09 : les quatre .entitlements le portent et les
CODE_SIGN_ENTITLEMENTS sont câblés. À reconfirmer dans Signing & Capabilities.
3. Build, puis les vérifications qui comptent
- Siri — dire « Note un verre d'eau dans Coach ». Attendu : « Noté. X,XX L d'eau aujourd'hui », sans que l'app s'ouvre.
- Raccourcis — l'app Raccourcis doit lister les 5 actions sous « Coach ».
- Smart Stack — ajouter le widget Hydratation, toucher « +25 cl », vérifier que le total monte et que le badge des saisies en attente s'incrémente.
- Synchro — ouvrir l'app iPhone, vérifier que la saisie faite au poignet
remonte sur
coach.hypnotruck.ch. - Minuit — le total doit repartir de zéro (c'est
asOf(_:)qui l'assure, pas le réveil de la timeline : le piège a déjà été payé côté iPhone).
Les trois questions que seul le build tranchera
- Une complication de CADRAN accepte-t-elle un bouton d'App Intent, ou est-ce
réservé à la Smart Stack ? La doc Apple n'était pas récupérable depuis
Linux. Par prudence,
.accessoryCircularn'est ici qu'un affichage ; si le cadran accepte l'interactivité, on pourra l'enrichir. - Les phrases Siri passent-elles la validation ? Chaque phrase contient
\(.applicationName), comme Apple l'exige, et le nom supposé est « Coach » (CFBundleDisplayName). Si le nom affiché diffère, les phrases ne se déclencheront pas — c'est silencieux. ProvidesDialogsur watchOS. Les intents rendentsome IntentResult & ProvidesDialogpour que Siri réponde à voix haute. À confirmer que la cible watchOS l'accepte sans ajustement.
Ce qui a été volontairement écarté
- ⛔ Saisie des repas depuis la montre. Pas de caméra, pas de scanner de code-barres, pas de saisie de texte confortable : un bouton « repas » au poignet ne ferait que renvoyer vers l'iPhone. Décidé avec Sylvain le 25/09.
- ⛔ Un paramètre libre de volume dans les phrases Siri. Un intent paramétré oblige Siri à poser une question — ce qui coûte plus de temps que de sortir le téléphone, et vide le raccourci de son intérêt. Les volumes sont donc fixés (250 ml, 500 ml, café 60 ml).
- ⛔ Toute borne en bpm dans les réponses de Siri.
TodaySessionn'en porte pas, et il ne faut pas en ajouter : une fourchette cardiaque annoncée par haut-parleur, hors de la recommandation du jour et de ses réserves, reviendrait à prescrire une intensité à un post-infarctus.