+etm23 rend à chaque borne détectée une entrée GetLoadConfig, et l'invariant loads[] ⊆ GetLoadConfig est rétabli. Sur .75 : 2 entrées → 4. L'app s'appuyait déjà sur cet invariant pour résoudre libellé, domaine et rang de toute charge publiée. Vérifié sur machine avant d'écrire quoi que ce soit : - l'aller-retour verbatim reste NEUTRE avec les quatre entrées (loadconfig_roundtrip.dart, verdict IDENTIQUE) ; - une entrée evcharger porte id/label/domain/priority/enabled, mode dynamic, et AUCUNE charge utile de mécanisme. Trois défauts que ce contrat révèle côté app : 1. isVariableLoad était défini par défaut (« ni relais ni sg-ready »), donc une borne y tombait. L'écran de mécanisme lui proposait une puissance nominale, des paliers et des temporisations — des réglages qui n'existent pas pour elle et dont l'écriture partirait quand même. Pire, le sélecteur offrait de la basculer en routeur de relais : une bascule que basculerMecanisme() sait construire et qu'aucun écran ne sait défaire. Une borne a maintenant sa section, en lecture seule, qui dit pourquoi il n'y a rien à régler. 2. BorneSection existait pour rattraper des bornes qui n'apparaissaient nulle part. Elles apparaissent maintenant dans leur domaine : la section les afficherait DEUX fois, en affirmant qu'elles n'ont « ni rang ni domaine » et qu'elles ne passent pas par SetLoadConfig. Trois affirmations devenues fausses. Retirée ; son contenu de runtime vit désormais dans l'écran de mécanisme, où il a un sens. 3. Le rang par défaut d'une borne est un ARTEFACT, et l'écran le disait comme un réglage. À la création le plugin donne « le plus petit rang existant moins un, borné à 1 » ; le chauffe-eau occupant déjà le rang 1, l'intention « en tête » dégénère en égalité — trois charges à 1 sur le banc. Le tri reste total (l'id départage), donc l'ordre est reproductible, et c'est précisément ce qui le rend crédible : l'installateur lit un classement plausible et n'y touche pas, validant un ordre que personne n'a posé. Une note le nomme, et disparaît dès le premier vrai réglage. Le glissement, lui, n'a demandé aucun cas particulier — c'était tout l'intérêt d'avoir une seule liste. Vérifié par test, y compris l'inversion borne / charge pilotée. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016vrTVifar2GN5rtUh89Wkq
4.0 KiB
Prompt agent plugin — 3g-2 : l'arbitre commande seul
À coller tel quel dans l'agent
powersync-plugin. Contexte :.75en1.15.2+etm22, seuil de réserve batterie à 0,4.
3g-2 — l'arbitre commande seul.
Aujourd'hui adjustEvChargers() re-décide après le waterfall : l'arbitre refuse, la ligne
suivante commande 6 A. La transplantation ne commande donc rien, et si la Terra AC n'avait pas
été hors ligne, l'ordre serait parti sur du matériel réel.
La règle à établir : une charge, un commandeur. Pour une borne arbitrée par le waterfall,
adjustEvChargers() ne doit plus émettre d'action de surplus. Ce qui lui reste, et qui doit
être délimité explicitement : les actions financées au réseau — marché de gros, échéance de
départ — puisque l'échéance est restée au proxy par décision assumée. Le champ funding que tu
viens d'ajouter est le discriminant naturel.
Deux pièges à ne pas laisser ouverts.
Le trou de commande : si le waterfall alloue et que le proxy ne commande plus, vérifie que
quelqu'un commande. Le pire résultat serait une borne qui n'obéit à personne — l'arbitre
croit avoir servi, rien ne se passe, et le budget est perdu comme dans le cas evFloorW.
La transition : une borne qui charge sous l'ancien régime au moment du déploiement ne doit pas rester bloquée dans un état commandé par un chemin qui n'existe plus. Même précaution qu'à la suppression du bloc SG-Ready codé en dur — passer par l'état sûr.
Traite evFloorW() dans le même lot. acquisitionTolerance est un seuil de déclenchement,
pas un plancher : 2 070 W publiés là où 4 140 W sont exigés, donc 2 828 W retirés du budget et
donnés à personne. Un plancher faux est pire qu'un plancher absent — le waterfall croit avoir
servi. Et le plancher publié doit correspondre au nombre de phases visé, pas au courant du
moment.
Et le rang d'une borne doit devenir configurable — priority = 100 en dur, std::sort non
stable, donc le test d'inversion est impossible tel quel. Sans lui, LM-1204-b reste hors
d'atteinte même avec deux bornes en ligne.
Vérification : .75 est à +etm22, seuil 0,4, la wallbox simulée répond, la Terra AC est hors
ligne (192.168.1.132:502, ThingErrorTimeout) — à regarder avant, c'est le seul obstacle
matériel restant à LM-1204-b.
Ton brief est commité en local dans le dépôt app (e84f59d) mais non poussé, faute
d'identifiants HTTPS. L'agent app pousse en SSH ; signale-le-lui plutôt que de le laisser
dormir.
Rappels d'état, au cas où la session redémarre à froid
Banc .75 |
1.15.2+etm22, seuil réserve batterie 0,4 (délibéré — 0,9 gèle tout à 50 % de SoC) |
| Plugin SunSpec | 1.15.2+etm11 — la batterie déclare enfin energystorage, signe vérifié dans les 3 états |
Banc .131 |
six conteneurs sur la même source, deploy.sh --check-only sort 0 |
| Terra AC | hors ligne, 192.168.1.132:502, ThingErrorTimeout — seul obstacle matériel à LM-1204-b |
| Déploiement | toujours etm-powersync-deploy/deploy.sh, jamais dpkg -i |
| Accès banc | ssh etm@192.168.1.75 (ni root ni nymea) · journal journalctl -u nymead |
Non franchi : LM-1204-b — jamais exercé, c'est le critère qui justifie tout le lot.
Pour l'agent app, en attente dans docs/BRIEF_depuis_plugin.md : SetChargingInfo
substitue silencieusement targetPercentage = 80 à un champ absent · loads[].funding
(surplus/grid) et l'entrée des bornes dans la télémétrie · kCodesReserveBatterie vide alors
que BATTERY_RESERVE publie socPercent/reservePercent/withheldW · et la mise en garde :
pour une borne, allocatedW et son motif sont la décision de l'arbitre, pas l'état de la
borne, tant que 3g-2 n'est pas livré.
Côté app, origin est en HTTPS sans credential helper — d'où des origin/… périmés qui font
croire à des commits manquants. À basculer en SSH :
git remote set-url origin gitea-lan:pakutz79/etm-powersync-app.git