chore(release): 1.15.2+etm23

Entrée de changelog du lot 3g-2, des quatre correctifs de 3g-1 qui
l'accompagnent et des deux [upstream-fix] du même passage.

Rien n'est construit ni déployé : le banc .75 tourne encore +etm22. La
construction arm64 et le déploiement restent à faire, et docs/RECAP_3g2.md §7
donne l'ordre de vérification au banc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017TVywtayEeoRJ2yWUW4iZj
This commit is contained in:
Patrick Schurig 2026-08-27 10:44:02 +02:00
parent 2ca9f1e228
commit e3f11b114d

View File

@ -1,3 +1,85 @@
powersync-energy-plugin-nymea (1.15.2+etm23) trixie; urgency=medium
* 3g-2 — UNE CHARGE, UN COMMANDEUR. C'est le défaut le plus grave qu'avait révélé le passage
machine du 2026-08-26 : adjustEvChargers() re-décidait le surplus APRÈS le waterfall et
passait outre le refus de l'arbitre. La décision de l'arbitre n'atteignait donc RIEN — elle
était publiée, juste, et une milliseconde plus tard le proxy commandait autre chose. Corrigé
des deux côtés : les actions EV du waterfall sont dispatchées vers EvAdapter::applyAction()
(elles ne l'étaient pas du tout), et les bornes ainsi commandées sortent du chemin proxy par
deux crochets virtuels posés dans l'amont. Le jeu des bornes commandées est NOMMÉ par le
scheduler (Plan::waterfallEvIds), jamais redéduit d'un motif ou d'un financement.
* evFloorW() ne multiplie plus par acquisitionTolerance. Ce sont deux grandeurs différentes,
confondues en écrivant la fonction : le plancher est ce que la borne EXIGE pour démarrer, la
tolérance est la part de ce plancher qu'on accepte de ne pas couvrir. Le banc a montré le
coût de la confusion : 2 070 W annoncés pour une borne qui en exige 4 140, waterfall qui
alloue 2 828 W, adaptateur qui refuse d'enclencher sous 6 A, et 2 828 W retirés du budget
pour personne.
* NOUVEAU MOTIF EV_GRID_START {budgetW, floorW, gridW} — la tolérance devient VISIBLE. Une
borne peut démarrer en soutirant au réseau ; le comportement existe depuis toujours chez le
proxy, où rien ne le nommait. L'action porte funding=Grid et sa comptabilité se PARTAGE :
budgetW dans budget.allocatedW, gridW dans budget.evReservedW, budgetW + gridW ==
allocatedW. Brèche assumée dans le financement réseau que DESIGN_3g §3.1 déférait à 3f, et
bornée par construction : surplus réel exigé, au plus UNE borne par cycle, sous le plafond
de la protection de surcharge. Détail : docs/DESIGN_3g.md §3.1-bis.
* NOUVEAU MOTIF PHASE_LIMIT {limitW, requiredW} — quand c'est la limite de phase qui interdit
et non le budget. Les deux phrases envoient l'installateur vers des gestes opposés.
* LE RANG D'UNE BORNE EST CONFIGURABLE, et il vit là où vivent tous les rangs :
LoadConfig.priority (LM-1206/LM-1207). Pas de second système de priorité — un classement
propre aux bornes ne saurait pas exprimer « VE1 > ECS > VE2 ». Toute borne détectée reçoit
d'office une entrée LoadConfig de mécanisme « evcharger », portant le rang et RIEN d'autre :
ses limites viennent du Thing et changent avec la voiture branchée. Création journalisée,
une ligne par borne, à la création seulement.
* CORRIGE UNE RUPTURE D'INVARIANT DE +etm21/+etm22, non signalée à l'époque : en faisant
entrer les bornes dans loads[], 3g-1 publiait des charges qui ne figuraient dans AUCUNE
GetLoadConfig. C'est exactement la charge fantôme que le lot B-bis avait supprimée,
réapparue par l'autre bout — et l'app s'appuie sur « loads[] ⊆ GetLoadConfig » pour résoudre
libellé, domaine et rang. L'auto-provisionnement le rétablit par construction.
* L'entrée de configuration d'une borne SURVIT à la disparition de son Thing : borne
remplacée, ThingId changé, appareil déposé. Elle reste publiée available: false /
faultCode: THING_MISSING / motif LOAD_UNAVAILABLE, et ne retient aucun budget. La supprimer
d'office rendrait « borne remplacée » indistinguable de « borne jamais configurée ».
* Tri du waterfall rendu TOTAL : à rang égal, l'identifiant départage. Deux bornes à
priority = 100 partageaient la même clé et std::sort n'est pas stable — laquelle démarrait
n'était pas reproductible d'un cycle à l'autre.
* CHANGEMENT DE COMPORTEMENT — la réserve de stockage ne mordait que sur les AUGMENTATIONS.
Le recrédit anti-clignotement rendait à chaque charge sa propre consommation, y compris sous
la réserve : une charge en marche le restait, pendant que le motif publiait « aucune charge
n'est servie ». Sous la réserve le budget est une décision de retenir, pas une mesure : le
recrédit y est supprimé (LM-1203-b, « annulé, pas réduit »), et withheldW chiffre désormais
les deux termes retenus — le surplus annulé ET la consommation propre de la charge.
* Le nombre de phases visé est décidé avec la voiture branchée. canSetPhaseCount() ne dit que
« la borne porte l'état desiredPhaseCount » ; la vraie question est tranchée par le manager
(canSwitchPhaseCount, min/maxPossiblePhaseCount). Les deux avaient divergé en 3g-1, et une
borne monophasée se voyait viser 3 phases — plancher publié triplé, et sous surcharge 3 × 6 A
commandés là où le proxy commandait 1 × 6 A. La référence de la bascule redevient aussi le
courant POSSIBLE (courant tiré + surplus) et non le courant tiré.
* L'écrêtage par la limite de phase, perdu en 3g-1 avec planSurplusCharging(), est rétabli —
et DÉCLARÉ, dans LoadContext.declared.maxPowerW : le waterfall ne peut plus allouer au-delà
de ce que le branchement supporte. Il ne descend jamais sous le plancher de la borne, parce
que couper est le geste de la couche L4 et non celui de la stratégie.
* [upstream-fix] SetChargingInfo annonçait « Only given properties will be set, others will be
untouched ». C'est FAUX : l'objet remplace le stocké, et un champ writable omis retombe sur
son défaut — targetPercentage à 80, repeatDays vide, endDateTime absent — sous
EnergyErrorNoError. Constaté sur le banc le 2026-08-26. La description dit désormais la
vérité, avec la liste des défauts et le geste correct (lire, modifier, renvoyer complet), et
un test épingle le comportement qu'elle annonce.
* [upstream-fix] prepareInformation() repliait sur ChargingModeEco tout mode sans échéance
valide, alors que le repli ne concerne que les modes qui en EXIGENT une. Deux conséquences :
ChargingModeEcoWithMinCurrent était réécrit et persisté au cycle suivant — le mode « éco +
courant minimum garanti » ne survivait jamais, et la branche d'adjustEvChargers() qui
l'applique était morte ; et ChargingModeEco était « replié » sur lui-même à chaque cycle,
avec écriture disque et notification chargingInfoChanged sans qu'aucune valeur ne change.
* Tests : la suite de simulation ne COMPILAIT plus depuis 639689b (constructeur
EtmVariableLoadAdapter, paramètre minPowerW non répercuté sur cinq sites d'appel) — donc
plus personne ne l'exécutait. Réparée, puis étendue. Le catalogue de motifs avait dérivé au
passage : BATTERY_RESERVE et BELOW_MIN_POWER étaient entrés sans ligne de rendu attendue,
donc leur TEXTE — celui sur lequel le banc s'appuie — n'était éprouvé par rien.
* Suite complète verte : simulation 27/27 (dont les 16 scénarios `run`), charging 16/16,
loadmodel 16/16, spotmarket 7/7. Build amd64 0 erreur / 0 warning. RIEN N'A TOURNÉ SUR
MACHINE : voir docs/RECAP_3g2.md pour ce qui reste à éprouver au banc.
-- Patrick Schurig <etm.schurig@gmail.com> Thu, 27 Aug 2026 11:00:00 +0200
powersync-energy-plugin-nymea (1.15.2+etm22) trixie; urgency=medium
* 3g-1, CE QUI MANQUAIT — les bornes étaient bien arbitrées, mais elles ne franchissaient