diff --git a/docs/OPTIMIZER_PROTOCOL.md b/docs/OPTIMIZER_PROTOCOL.md index e1d1ff0..b2ae842 100644 --- a/docs/OPTIMIZER_PROTOCOL.md +++ b/docs/OPTIMIZER_PROTOCOL.md @@ -148,9 +148,10 @@ Réponse attendue : - Le plugin appelle `GetPlan` à chaque cycle d'optimisation (~1/min) **et** sur événement significatif — voir `trigger`, §5.1. - **Le heartbeat est implicite** : une réponse valide à `GetPlan` = optimiseur vivant. - Deux cycles consécutifs sans réponse valide (timeout par requête : 10 s) → - `optimizerAlive = false`, repli rule-based, notification de changement de capacités - (namespace publié actuel : `NymeaEnergy`). + Deux **requêtes** consécutives en échec (timeout par requête : 10 s, erreur, réponse + illisible, plan invalide) → `optimizerAlive = false`, repli rule-based, notification + `NymeaEnergy.OptimizerStatusChanged`. Le compte est **par requête, pas par cycle** : une + requête remplacée par une plus récente avant sa réponse n'est pas un échec. - L'optimiseur peut être lent à *calculer* (EOS : minutes) — il doit alors répondre vite avec son **dernier plan en cache** ou `abstain`, et recalculer en tâche de fond. Une requête n'attend jamais un calcul long. Le rythme de recalcul est libre @@ -478,21 +479,30 @@ stratégie rule-based **pour ce cycle**, sans considérer l'optimiseur comme mor | Situation | optimizerAlive | Stratégie active | |---|---|---| | Réponse plan valide | true | optimiseur | -| `abstain` | true | rules (ce cycle) | -| Plan expiré (`validUntil` dépassé) | true | rules jusqu'au prochain plan valide | -| Timeout / erreur / plan invalide ×2 | false | rules | +| `abstain` | inchangé | rules (ce cycle) | +| Plan expiré (`validUntil` dépassé) | inchangé | rules jusqu'au prochain plan valide | +| Timeout / erreur / plan invalide sur **deux requêtes consécutives** | false | rules | | Socket absent / fermé | false | rules | -| `optimizerExpected=false` (tier Community) | false | rules | +| `optimizerExpected=false` (aucun endpoint configuré) | false | rules | | Mode dégradé L2 (compteur muet > 90 s) | inchangé | **aucune** — planification suspendue, repli de sécurité | -L'objet capabilities exposé à l'app (`tier`, `optimizerExpected`, `optimizerAlive`, -`activeStrategy`) reflète cet état en continu ; tout changement émet une notification. +Retour à `optimizerAlive = true` au premier plan valide. Les échecs se comptent **par +requête** : une abstention ou un plan déjà expiré à la réception interrompent la série ; une +requête remplacée par une plus récente n'est pas un échec. Avant le premier plan valide, +`optimizerAlive` vaut `false`. Un plan invalide remplace le cache (l'ancien plan valide n'est +plus appliqué) et un socket fermé l'abandonne (E-T3-9). + +L'état exposé à l'app (`optimizerExpected`, `optimizerAlive`, `activeStrategy` ∈ +`optimizer` | `rules` | `none`) reflète cet état en continu ; chaque transition émet +`NymeaEnergy.OptimizerStatusChanged` (`INTERFACE.md`). Il n'y a pas de `tier` : l'app déduit ce +qu'elle affiche de ces trois champs. ## 8. Apprentissage et transparence - L'optimiseur peut renvoyer ses estimations (`learned` + `confidence`) dans une notification `UpdateLearned` (sans id, fire-and-forget) ; le plugin les persiste - et les retransmet dans les contextes suivants. + et les retransmet dans les contextes suivants. **État 1.1 du moteur** : reçue, journalisée + une fois, ignorée — la persistance est un lot ultérieur (`INTERFACE.md`). - Tant que `confidence < 0.7` (seuil indicatif), l'app peut afficher un badge « profil en apprentissage ». - Les données d'apprentissage restent **locales**. Rien ne quitte le site.