diff --git a/debian-qt5/changelog b/debian-qt5/changelog index 3440444..0325662 100644 --- a/debian-qt5/changelog +++ b/debian-qt5/changelog @@ -1,3 +1,18 @@ +powersync-energy-plugin-nymea (1.15.2+etm9) trixie; urgency=medium + + * Corrige le va-et-vient JSON-RPC cassé par l'union LM-300. GetLoadConfig sérialise + une charge via le méta-objet, donc toutes les propriétés déclarées — y compris un + « sgReady » VIDE sur une charge qui n'est pas SG-Ready. Le schéma SetLoadConfig + exigeant « states » dès que la clé est présente, nymea rejetait la requête AVANT le + handler : lire puis réécrire une configuration relay-router était impossible. + « states » et « minStateHoldS » passent en optionnels ; l'exigence réelle (states + non vide, état 2 présent) reste tenue par LoadConfig::isValid(). + * Constaté au banc à la première tentative réelle de SetLoadConfig. Aucun test ne + rejouait le geste de l'app — lire, modifier un champ, réécrire. C'est désormais le + cas (testLoadConfigRpc §3bis, vérifié échouant sans le correctif). + + -- Patrick Schurig Mon, 10 Aug 2026 09:00:00 +0200 + powersync-energy-plugin-nymea (1.15.2+etm8) trixie; urgency=medium * ECS-110-b — un Thing n'appartient qu'à UNE charge active. Le cas général n'était diff --git a/specs/spec_ecs.md b/specs/spec_ecs.md index f3341ec..b3f4111 100644 --- a/specs/spec_ecs.md +++ b/specs/spec_ecs.md @@ -671,6 +671,7 @@ mécanique reste **L0**. Perte de sonde → mode sans sonde, pas arrêt d'urgenc | ECS-411 | simulation | `testEcsRestartRecovery` | | ECS-413 | simulation | `testEcsDisableLeavesSafeState` — + cas négatif : un rebuild sans désactivation ne coupe pas | | ECS-414 | simulation | `testSgReadyPartialFailure` — plancher = état 2, atomicité du repli, contact injoignable | +| LM-302 (frontière RPC) | simulation | `testLoadConfigRpc` §3bis — va-et-vient Get → Set réinjecté tel quel (vérifié : le test échoue sans le correctif) | | ECS-110-b | simulation | `testThingOwnershipIsExclusive` — conflit entre charges (3 mécanismes), formes d'uuid, id dupliqué, doublons intra-charge, tolérance d'une charge désactivée | | ECS-110 (SG-Ready) / LM-300 | simulation | `testSgReadyFromConfig` — refus sans état 2, refus de charges utiles mélangées, round-trip, pilotage, désactivation → état 2 | | ECS-110, ECS-111 | unitaire | `testEcsConfigValidation` — DOIT s'exécuter aussi en build release (`QT_NO_DEBUG`), sinon il ne prouve rien du binaire livré | @@ -743,6 +744,7 @@ protocole dans le même lot.** | 2026-08-08 | **Étape 1 OUVERTE** — trois exigences : ECS-306, ECS-411, ECS-412 | | 2026-08-08 | ECS-412 : au démarrage à froid, le verrou est **ARMÉ** (défaut sûr), jamais purgé | | 2026-08-09 | ECS-412 précisé : cet armement est **TRANSITOIRE** et posé paresseusement au premier `now`. Défaut de blocage circulaire constaté **au banc**, corrigé, couvert par `testEcsColdStartLockExpires` | +| 2026-08-10 | **Va-et-vient RPC cassé par LM-300** — `GetLoadConfig` sérialise via le méta-objet, donc un `sgReady` VIDE sur toute charge non SG-Ready ; le schéma SET exigeait `states` dès la clé présente, et nymea rejetait avant le handler. Constaté au banc à la première tentative réelle de `SetLoadConfig` : aucun test ne rejouait le geste de l'app (lire, modifier, réécrire). Corrigé en `o:states` — c'est le mur documenté en LM-302, la validation réelle restant dans `isValid()` | | 2026-08-09 | **ECS-110-b créé et FAIT** — un Thing n'appartient qu'à une charge active. Trou trouvé en répondant à la question « le cas général est-il couvert ? » : il ne l'était pas du tout. `LoadConfigStore::validateSet()` ; doublons intra-charge également refusés | | 2026-08-09 | **SG-Ready configurable (LM-300)** — union discriminée par mécanisme ; les deux `Q_ASSERT` de `sgreadyadapter.cpp` retirés au profit d'un refus `isValid()` + drapeau `m_usable` (ECS-110 tenu hors `Q_ASSERT`) ; principe général porté en LM-104, hors ECS | | 2026-08-09 | **ECS-414 FAIT** — échelle généralisée à SgReady et EtmVariableLoad ; plancher = état 2 pour la PAC ; repli soumis au même `transientHarm` que l'aller ; contact injoignable supposé fermé mais toujours commandé | diff --git a/specs/spec_loadmodel.md b/specs/spec_loadmodel.md index b0c1910..3f35e96 100644 --- a/specs/spec_loadmodel.md +++ b/specs/spec_loadmodel.md @@ -145,7 +145,14 @@ les paramètres *avant* le handler, si bien que deux formes exclusives obligent marquer tous les champs spécifiques en optionnel (`"o:"`), faute de quoi l'une des deux serait rejetée en amont. La contrainte est déjà documentée dans `nymeaenergyjsonhandler.cpp:155-160` pour deux mécanismes ; elle s'aggrave à -quatre. À la frontière RPC, la validation reste donc **à l'exécution** +quatre. **Le mur a été touché le 2026-08-10**, exactement où ce paragraphe l'annonçait, et d'une +façon qu'il n'avait pas anticipée : ce n'est pas seulement que deux formes exclusives +obligent à marquer les champs `"o:"`, c'est que `pack()` sérialise **toutes** +les propriétés déclarées — une charge `relay-router` sort donc de `GetLoadConfig` avec un +`sgReady` vide. Exiger une clé **à l'intérieur** d'une charge utile optionnelle casse +alors le va-et-vient de l'app sur les charges des **autres** mécanismes. Corollaire pour +tout mécanisme futur : les clés internes d'une charge utile se marquent `"o:"` elles +aussi. À la frontière RPC, la validation reste donc **à l'exécution** (`LoadConfig::isValid()`). Ne pas tenter un schéma RPC strict : c'est un mur connu.