docs(optimiseur): INTERFACE.md (état, réglage, plan publié), protocole §4/§7/§8 (brief 4 T4)

- INTERFACE.md : GetOptimizerStatus, SetOptimizerEndpoint, SetOptimizerToken, GetPlan,
  OptimizerStatusChanged, permissions, UpdateLearned ignoré ; ce que nymea journalise des
  paramètres d'un appel ; comment distinguer « pas d'optimiseur » de « pas de plan ce cycle ».
- OPTIMIZER_PROTOCOL.md : tier retiré (E23), « deux requêtes consécutives » (E17), §8 état 1.1.
- AGENTS.md invariant 6 : tier retiré.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Patrick Schurig 2026-10-17 09:34:39 +02:00
parent c1ce67942c
commit 7a32961b23

View File

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