Files
coach-ios/docs/siri-et-widget-watch-runbook-mac.md
Sylvain Bettinelli 98b1cd0c89 Siri connaît enfin l'app, et la montre sait noter un verre
Demandé par Sylvain : des widgets, puis « comment lier Siri à mon appli ».
Constat avant de commencer :

  App Intents déclarés      : 1  (LogDrinkIntent)
  AppShortcutsProvider      : 0  -> Siri n'avait AUCUNE phrase à écouter
  Saisie depuis la montre   : 0  -> complications d'affichage seulement

Et la cause commune : `LogDrinkIntent` vivait dans `CoachQuickWidget.swift`,
qui n'appartient qu'à l'extension widget iPhone. Ni l'app (d'où Siri découvre
les raccourcis), ni la cible Watch ne pouvaient le voir.

Ce qui est ajouté
------------------
- `CoachIntents.swift` — les intents, partagés entre les TROIS cibles.
  `LogDrinkIntent` y est déplacé (pas dupliqué : deux définitions du même
  symbole dans une cible qui compile les deux fichiers casseraient le build),
  plus `HydrationStatusIntent` et `TodaySessionIntent`.
- `CoachAppShortcuts.swift` — 5 raccourcis, 16 phrases françaises. Cible App
  UNIQUEMENT : Apple attend un seul AppShortcutsProvider par application.
- `CoachWatchHydration.swift` — widget Smart Stack de la montre : total du
  jour, jauge, et deux boutons +cl. Le geste se fait au poignet.

Choix qui méritent d'être dits
-------------------------------
⛔ Pas de saisie des repas sur la montre. Pas de caméra, pas de scanner, pas de
saisie de texte confortable : le bouton ne ferait que renvoyer vers l'iPhone.
Tranché avec Sylvain.

⛔ Pas de volume libre dans les phrases Siri. Un intent paramétré oblige Siri à
poser une question — plus long que de sortir le téléphone, et le raccourci perd
sa raison d'être. Volumes fixés : 250 ml, 500 ml, café 60 ml.

⛔ Aucune borne en bpm dans les réponses vocales. `TodaySession` n'en porte pas
(vérifié : sport, title, subtitle, done) 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. Siri annonce QUOI ; l'app dit COMMENT.

Deux boutons et pas trois sur la montre : sur 160 pt, un troisième descend les
cibles sous le seuil tactile, pour un geste qu'on fait en marchant.

⚠️ RIEN DE CE CODE N'EST COMPILÉ
---------------------------------
AppIntents, WidgetKit et SwiftUI sont absents de Swift pour Linux. Ce qui a été
vérifié à la place, par lecture croisée des sources : que chaque symbole appelé
existe, et qu'aucun n'est déclaré deux fois. Deux erreurs ont d'ailleurs été
trouvées ainsi avant commit — `asOf()` ne rend pas un optionnel, et
`TodaySession` n'a pas de `durationMin`. Les erreurs de type, de concurrence et
d'API n'apparaîtront qu'au build.

`docs/siri-et-widget-watch-runbook-mac.md` porte les étapes Xcode, le tableau
de Target Membership, les cinq vérifications à faire sur l'appareil, et les
trois questions que seul le build tranchera — dont celle-ci : une complication
de cadran accepte-t-elle un bouton interactif, ou est-ce réservé à la Smart
Stack ? Par prudence, le cadran n'est ici qu'un affichage.

91 tests Swift Linux au vert (non-régression CoachQuickLog / snapshot).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-25 06:58:11 +00:00

5.2 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.

⛔ Rien de ce code n'a été compilé. AppIntents, WidgetKit et SwiftUI sont 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 le WidgetBundle.

É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 CoachWatchWidgets
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 CoachWatchWidgets, 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 CoachWatchWidgets. 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

  1. Siri — dire « Note un verre d'eau dans Coach ». Attendu : « Noté. X,XX L d'eau aujourd'hui », sans que l'app s'ouvre.
  2. Raccourcis — l'app Raccourcis doit lister les 5 actions sous « Coach ».
  3. 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.
  4. Synchro — ouvrir l'app iPhone, vérifier que la saisie faite au poignet remonte sur coach.hypnotruck.ch.
  5. 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

  1. 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, .accessoryCircular n'est ici qu'un affichage ; si le cadran accepte l'interactivité, on pourra l'enrichir.
  2. 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.
  3. ProvidesDialog sur watchOS. Les intents rendent some IntentResult & ProvidesDialog pour 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. TodaySession n'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.