102 lines
4.8 KiB
Markdown
102 lines
4.8 KiB
Markdown
---
|
|
issueRef: "#173"
|
|
version: 2
|
|
updatedBy: {"kind":"agent","agent_id":"57695b92-24d0-4876-837c-76116e70a6ae"}
|
|
updatedAt: 1785272880037
|
|
---
|
|
|
|
## #173 — Cadrage Main (2026-07-28)
|
|
|
|
### Décision produit
|
|
La direction proposée est retenue :
|
|
- **le téléphone décide** qu'un chrono arrive à 3, 2, 1, 0 ;
|
|
- **la montre ne dérive pas seule** un événement métier "chrono terminé" ;
|
|
- la montre reçoit une alerte à jouer et exécute l'haptique localement, même écran éteint si possible.
|
|
|
|
### Périmètre exact
|
|
Ce ticket ne remplace pas `#164`, il le complète architecturalement.
|
|
|
|
Il faut cadrer :
|
|
- le contrat téléphone -> montre d'alerte chrono ;
|
|
- la robustesse quand l'écran montre est éteint / ambient ;
|
|
- la force/pattern haptique suffisant pour activité physique réelle ;
|
|
- l'absence de doublon agressif ou de logique divergente entre téléphone et montre.
|
|
|
|
### Recommandation cible
|
|
- téléphone : source des événements `countdownTick(3|2|1)` et `countdownFinished` ;
|
|
- montre : simple exécution d'un pattern reçu, idempotent et court ;
|
|
- support minimal hors écran : foreground/ongoing/session state suffisamment vivant pour que la montre puisse encore vibrer ;
|
|
- si une alerte est ratée faute de connectivité, la projection confirmée doit rester cohérente et ne pas faire vibrer en retard plusieurs secondes après.
|
|
|
|
### Risques à cadrer
|
|
- latence si l'on transporte chaque tick individuellement ;
|
|
- duplication si la montre déclenche aussi localement ;
|
|
- vibration faible selon OEM si on reste sur un impact standard ;
|
|
- absence de vibration écran éteint si le process n'est pas au bon niveau de foreground/ongoing.
|
|
|
|
### Attendu suite
|
|
Créer ensuite le lot d'architecture/implémentation qui tranche :
|
|
- événements instantanés vs petits batches d'alertes planifiées ;
|
|
- pattern haptique fort mais court ;
|
|
- comportement dégradé sans connexion ;
|
|
- QA sur montre réelle en mouvement.
|
|
|
|
## Cadrage Architect (2026-07-28)
|
|
|
|
Statut : **cadrage exploitable, prêt pour découpage dev**.
|
|
|
|
### Architecture cible minimale
|
|
- Le téléphone reste l'autorité unique des événements d'alerte chrono.
|
|
- La montre n'infère plus seule une fin de chrono pour décider une vibration ; elle exécute une alerte explicite reçue du téléphone.
|
|
- La projection d'état actuelle est conservée pour l'affichage, avec un **flux séparé phone -> watch d'alertes éphémères**.
|
|
- Côté téléphone, une façade `WatchAlertPublisher` suffit au point où la logique chrono sait déjà qu'un `3/2/1/0/fin` se produit.
|
|
|
|
### Répartition téléphone / montre
|
|
- Téléphone :
|
|
- détecte `3`, `2`, `1`, `0`, `fin chrono`, `fin repos` si retenu ;
|
|
- joue le son téléphone ;
|
|
- publie une alerte structurée vers la montre ;
|
|
- décide si une alerte est encore pertinente ou périmée.
|
|
- Montre :
|
|
- reçoit l'alerte ;
|
|
- déclenche l'haptique locale forte ;
|
|
- peut réveiller brièvement l'écran si faisable natif Wear ;
|
|
- ne décide jamais seule qu'un `0` est atteint.
|
|
|
|
### Contrat phone -> watch recommandé
|
|
- Nouveau DTO `WatchAlertEnvelope`, `schemaVersion = 5`, transporté via `MessageClient` sur un path type `/gametime/phone/alert`.
|
|
- Champs clés : `alertId`, `sessionId`, `revision`, `kind`, `timerKind`, position courante, `scheduledForEpochMs`, `expiresAtEpochMs`, `pattern`.
|
|
- `alertId` sert à la déduplication.
|
|
- `scheduledForEpochMs` + `expiresAtEpochMs` servent à ignorer une alerte arrivée trop tard.
|
|
|
|
### Latence / duplication / retard
|
|
- Envoi au moment de l'événement métier, pas à intervalle fixe.
|
|
- La montre ignore :
|
|
- tout `alertId` déjà joué ;
|
|
- tout `sessionId` non cohérent avec la séance projetée courante ;
|
|
- toute alerte reçue après son expiration.
|
|
- TTL recommandé :
|
|
- `3/2/1` : ~700 ms ;
|
|
- `0/fin` : ~2000 ms.
|
|
- Pas d'ACK obligatoire en v1 : une alerte manquée n'est pas rejouée après resync.
|
|
|
|
### Foreground / ambient / ongoing
|
|
- S'appuyer sur l'existant :
|
|
- `WatchOngoingActivityController` ;
|
|
- `WatchHeartRateForegroundService` pendant `running`.
|
|
- Ne pas créer un second service d'alerte.
|
|
- Si un réveil écran bref est faisable, le réserver à `timerZero|timerFinished`, jamais à `3/2/1`.
|
|
- En ambient, l'alerte doit rester haptique-first.
|
|
|
|
### Articulation avec #164
|
|
- `#164` reste le ticket observable audio/alertes chrono.
|
|
- `#173` ajoute la prolongation architecturale vers la montre.
|
|
- Le haptique montre actuel basé sur transition de projection devient au mieux un fallback transitoire ; la cible propre est le nouveau flux d'alertes explicites.
|
|
|
|
### Lots recommandés
|
|
1. `B1 [DevBackend] Contrat bridge alertes chrono + publisher téléphone`
|
|
2. `B2 [DevBackend] Déduplication / TTL / filtrage session`
|
|
3. `F1 [DevFrontend] Exécution locale alerte montre`
|
|
4. `F2 [DevFrontend] Intégration foreground/ambient`
|
|
5. `QA1 [QA] Validation alertes chrono phone/watch`
|