4.7 KiB
4.7 KiB
issueRef, version, updatedBy, updatedAt
| issueRef | version | updatedBy | updatedAt | ||
|---|---|---|---|---|---|
| #175 | 4 |
|
1785315994252 |
#175 — Cadrage Main (2026-07-28)
Symptôme utilisateur
Si l'utilisateur tue l'app téléphone sans quitter d'abord la séance, la montre conserve une séance active apparente et continue d'ouvrir l'ancien écran de séance.
Gravité
Critique côté cohérence :
- la montre affirme un état actif sans source de vérité confirmée ;
- l'utilisateur peut croire que la séance continue alors que le téléphone a disparu du cycle ;
- cela contredit le principe "logique métier côté téléphone".
Décision de cadrage
La montre ne doit pas garder indéfiniment un état "séance active" orphelin.
Comportement cible à trancher techniquement :
- soit le téléphone envoie explicitement un état terminal/deconnexion avant extinction contrôlée ;
- soit la montre invalide l'état de séance après une fenêtre d'absence de heartbeat/projection ;
- soit combinaison des deux, avec dégradation vers un état clair "Téléphone indisponible" ou retour hors séance.
Garde-fous
- ne pas perdre une vraie séance lors d'une micro-coupure normale ;
- ne pas laisser une séance fantôme persister après fermeture forcée ;
- distinguer reconnexion brève et disparition durable du téléphone ;
- l'écran montre doit refléter un état confirmé ou explicitement dégradé, jamais un faux "tout va bien".
Attendu suite
Ticket d'architecture/implémentation à sortir de celui-ci :
- stratégie heartbeat / TTL projection ;
- comportement UI montre si la source téléphone disparaît ;
- tests kill téléphone / reprise / relance app.
Cadrage Architect (2026-07-28)
Statut : cadrage exploitable, prêt pour découpage dev.
Diagnostic
Le bug vient du mécanisme de reprise montre : au démarrage ou à la reconnexion, la montre relit le dernier DataItem de projection et continue de l'afficher même si le téléphone a disparu. Le WatchSessionViewModel peut marquer la projection stale puis connectionLost, mais n'invalide jamais la projection elle-même.
Décision d'architecture
- Le téléphone reste l'unique source de vérité.
- La projection montre doit être traitée comme un cache temporaire, jamais comme une preuve durable qu'une séance est encore active.
- Une projection phone -> watch devient expirable.
- Sans rafraîchissement explicite du téléphone dans une fenêtre courte, la montre doit considérer la projection invalide et revenir à un état
téléphone indisponible / aucune séance confirmée.
Mécanisme recommandé
- Étendre
WatchSessionProjectionavec un TTL explicite, par exempleexpiresAtEpochMs. - À chaque projection publiée, le téléphone renseigne
expiresAtEpochMs = now + ttl. - Recommandation : TTL de
12s, cohérent avec le refresh périodique existant toutes les2s. - Si l'app téléphone est killée, le heartbeat s'arrête ; la montre laisse expirer la projection.
- Si le téléphone sait explicitement qu'il n'y a plus de séance, il publie
phase = noActiveSessionimmédiatement comme aujourd'hui ; le TTL couvre le cas brutal.
Comportement montre attendu
- Avant expiration : garder l'écran courant, avec l'état
staleexistant si utile. - Après expiration durable :
- remplacer localement la projection active par une projection synthétique
noActiveSession; - vider
sensorSample, commandes pending, score optimiste ; - arrêter ongoing / foreground liés à la séance ;
- afficher un état type
Téléphone indisponible / rouvre GameTime sur le téléphone, pas l'ancienne séance.
- remplacer localement la projection active par une projection synthétique
- Si le téléphone republie ensuite une projection valide, la montre se recale normalement.
Garde-fous micro-coupures
- Ne pas invalider sur simple
connectionLostcapability. - Invalider seulement quand aucune projection fraîche n'est reçue au-delà du TTL et qu'aucun ack/commande retour ne prouve une communication en cours.
- Fenêtres recommandées :
- refresh téléphone :
2sinchangé ; - seuil
stale:6sactuel conservé ; - expiration dure :
12sà15s.
- refresh téléphone :
Impacts
- Contrat :
WatchSessionProjectiongagneexpiresAtEpochMs,schemaVersionincrémentée. - Téléphone : renseigne ce champ à chaque publish.
- Bridge natif watch : pas de refonte structurelle ; la lecture du dernier
DataItempeut rester, mais ce snapshot sera auto-invalidé par TTL. - UI montre : ajouter l'invalidation locale dans
_syncFreshnessState(); injecter une projection synthétiquenoActiveSessionaprès expiration.
Lots recommandés
B1 [DevBackend] Projection expirable côté téléphoneF1 [DevFrontend] Invalidation locale montre sur TTL expiréF2 [DevFrontend] Ajustements natifs reprise/ongoingQA1 [QA] Validation disparition source téléphone