« Fermer l'app Polar Flow » était un conseil faux, et mesuré tel dès le 31/08

Sylvain enchaîne un troisième envoi et reçoit « le canal est probablement
occupé » — notre propre message, déclenché par watchNotFound avec des montres
muettes : le service PsFTP est là, il ne répond pas.

La chronologie de ses trois envois explique tout. Le premier réussit, montre
fraîchement réinitialisée donc pas encore liée à Flow. Le deuxième renvoie 104
DIRECTORY_EXISTS, ce qui prouve que le canal était ENCORE libre. Le troisième
échoue : Flow a repris la main entre-temps. Le canal n'est donc pas ouvert ou
fermé en général — il y a une fenêtre, qui se referme dès que Flow se
reconnecte.

Le message conseillait de fermer complètement l'app Polar Flow. C'était faux, et
la mesure du 31/08 le disait déjà : la montre affichait « connexion impossible »
pendant que les réglages iOS la disaient toujours connectée à Flow. iOS maintient
le lien d'un accessoire appairé, app fermée ou non. Le message nomme maintenant
le geste qui libère réellement le canal — redémarrer la montre — précise que
fermer l'app n'y change rien, et rappelle que le câble est le chemin fiable.

Corrigé au passage le message des appareils sans PsFTP, qui présentait encore la
question comme « l'inconnue restante » alors qu'elle a été tranchée le 31/08 :
la montre expose bien PsFTP quand elle est connectée. Un test interdit désormais
de la rouvrir dans l'UI.

88 tests Linux verts, dont deux nouveaux qui verrouillent l'absence du conseil
inutile et la présence du geste utile.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sylvain Bettinelli
2026-09-01 08:30:48 +00:00
parent 7d68605e83
commit 422b6ac3e6
3 changed files with 76 additions and 8 deletions

View File

@@ -383,3 +383,33 @@ documentée et devra être mesurée.
**câble**.
[ancs]: https://developer.apple.com/library/archive/documentation/CoreBluetooth/Reference/AppleNotificationCenterServiceSpecification/Specification/Specification.html
### La séquence du 01/09, et ce qu'elle apprend sur la fenêtre
Trois envois consécutifs, trois résultats différents — c'est la chronologie qui
explique tout :
| # | résultat | lecture |
|---|---|---|
| 1 | **réussi** | montre fraîchement réinitialisée, **pas encore liée à Flow** : canal libre |
| 2 | **errorcode 104** `DIRECTORY_EXISTS` | canal **toujours** libre, la session s'ouvre — seul le `mkdir` bute sur un dossier déjà créé au 1ᵉʳ envoi |
| 3 | **« canal probablement occupé »** | Flow a repris la main entre-temps |
⇒ Le canal n'est pas ouvert ou fermé « en général » : il y a une **fenêtre**,
qui commence quand la montre n'est liée à personne et se referme dès que Flow
se reconnecte. C'est cohérent avec le 31/08 et avec l'USB, où il faut fermer
Flow.
⚠️ **Le message d'erreur du plugin conseillait « fermer complètement l'app Polar
Flow ». C'est faux, et ça l'était déjà le 31/08** : la montre affichait
« connexion impossible » pendant que les réglages iOS la disaient **toujours
connectée** à Flow. iOS maintient le lien d'un accessoire appairé, app fermée ou
non. Message corrigé le 01/09 — il nomme désormais le geste qui libère
réellement le canal (redémarrer la montre) et rappelle que le câble est le
chemin fiable.
**Hypothèse ouverte, non vérifiée** : redémarrer la montre puis écrire *dans la
foulée*, avant que Flow ne se reconnecte, pourrait suffire. Ça expliquerait les
envois 1 et 2. Ce n'est pas une méthode tant que ça n'a pas été reproduit
plusieurs fois — et ⛔ chaque essai a un coût matériel avéré (l'USB désactivé le
31/08). **Écrire la séance par câble AVANT tout essai.**

View File

@@ -210,17 +210,37 @@ public enum PolarPftpError: Error, CustomStringConvertible, Equatable {
+ "la montre allumée et à portée."
case .watchNotFound(let seconds, let vues, _, let muettes) where muettes > 0:
// Le service est là mais ne répond pas : signature d'un canal déjà pris.
// Le service est là mais ne répond pas : canal déjà pris.
//
// Ce message conseillait « fermer l'app Polar Flow ». C'était
// faux, et mesuré comme tel le 31/08/2026 : la montre affichait
// « connexion impossible » pendant que les réglages iOS la
// disaient TOUJOURS connectée à Flow. iOS maintient le lien d'un
// accessoire appairé, app fermée ou non fermer l'app ne rend pas
// le canal.
//
// Ce qui l'a rendu, le 01/09 : une montre fraîchement
// réinitialisée, donc pas encore liée à Flow. Redémarrer la montre
// libère aussi son canal, mais Flow le reprend.
return "\(vues) appareil(s) vu(s), \(muettes) portant PsFTP mais sans "
+ "réponse en \(Int(seconds)) s. Le canal est probablement déjà "
+ "occupé : fermer complètement l'app Polar Flow (elle synchronise "
+ "en arrière-plan), puis réessayer."
+ "réponse en \(Int(seconds)) s. Le canal PsFTP de la Vantage "
+ "n'accepte qu'une session, et Polar Flow la détient tant que "
+ "la montre lui est appairée — fermer l'app n'y change rien, "
+ "iOS maintient le lien. Redémarrer la montre (appui long sur "
+ "OK) libère le canal ; il faut écrire dans la foulée, avant "
+ "que Flow ne le reprenne. Chemin fiable : le câble."
case .watchNotFound(let seconds, let vues, _, _):
// Des appareils, mais aucun ne porte le service.
// Ce message parlait d'« inconnue restante ». Elle a été levée le
// 31/08/2026 : la montre EST atteignable et expose bien PsFTP
// (« 12 appareils vus, 1 portant PsFTP ») quand elle est
// connectée. N'en voir aucun est donc autre chose : montre éteinte,
// hors de portée, ou pas encore connectée à l'iPhone.
return "\(vues) appareil(s) Bluetooth vu(s) en \(Int(seconds)) s, aucun "
+ "n'expose PsFTP. La Vantage n'annonce peut-être pas ce service "
+ "tant qu'elle est appairée à Flow — c'est l'inconnue restante."
+ "n'expose PsFTP. La Vantage expose bien ce service quand elle "
+ "est connectée (vérifié le 31/08) : la chercher plutôt du côté "
+ "de la montre — allumée, à portée, et reliée à l'iPhone."
}
}
}

View File

@@ -138,13 +138,31 @@ final class PolarPftpErrorTests: XCTestCase {
func testUneMontreMuettePointeVersFlow() {
let e = PolarPftpError.watchNotFound(30, vues: 3, sansPsFtp: 2, muettes: 1)
XCTAssertTrue(e.description.contains("Polar Flow"))
XCTAssertTrue(e.description.contains("occupé"))
}
func testDesAppareilsSansPsFtpNommentLInconnueRestante() {
/// Le message conseillait « fermer complètement l'app Polar Flow ».
/// Mesuré faux le 31/08/2026 : la montre affichait « connexion impossible »
/// pendant que les réglages iOS la disaient toujours connectée à Flow. iOS
/// maintient le lien d'un accessoire appairé, app fermée ou non.
func testLeMessageNeConseillePlusDeFermerLApp() {
let e = PolarPftpError.watchNotFound(30, vues: 3, sansPsFtp: 2, muettes: 1)
XCTAssertTrue(e.description.contains("fermer l'app n'y change rien"),
"le geste inutile doit être explicitement écarté")
XCTAssertTrue(e.description.contains("Redémarrer la montre"),
"le geste qui libère réellement le canal doit être donné")
XCTAssertTrue(e.description.contains("câble"),
"le chemin fiable doit être rappelé")
}
/// L'« inconnue restante » a été levée le 31/08 : la montre expose bien
/// PsFTP quand elle est connectée. Le message ne doit plus la présenter
/// comme une question ouverte.
func testDesAppareilsSansPsFtpNePresententPlusUneInconnue() {
let e = PolarPftpError.watchNotFound(30, vues: 4, sansPsFtp: 4, muettes: 0)
XCTAssertTrue(e.description.contains("n'expose PsFTP"))
XCTAssertTrue(e.description.contains("4 appareil"))
XCTAssertFalse(e.description.contains("inconnue"),
"la question a été tranchée, ne pas la rouvrir dans l'UI")
}
func testLesTroisMessagesSontDistincts() {