+etm55 vérifié (posé le 04/09 18:21:08). Le taux constant est en ligne : la
maquette porte le bon chiffrage — ×4,75 sur une fenêtre quotidienne, facteur
ln(T·P/E) + 1 — et les deux interdits du régime `unmeasurable` : ni annoncer que
l'achat va s'intensifier, ni lire `atMaximum: false` comme « tout va bien », qui
signifie qu'il n'y a aucun étalement, donc rien qui puisse cesser.
La troisième nature d'heure murale touche du code livré : `fetchDailyBalance()`
et la baseline des ratios prennent minuit du TÉLÉPHONE, alors qu'une journée de
reporting suit l'installation. Sur `.75` en Europe/London vue d'un téléphone
français, entre minuit et 1 h l'app compte une journée que la box compte encore
dans la précédente.
L'app ne peut pas le corriger seule : `System.GetTime` publie un nom IANA, et un
décalage ne s'en déduit pas sans base de fuseaux — qu'il faudrait embarquer pour
recalculer une frontière que la box connaît, et qui resterait fausse les jours de
changement d'heure. Demandé au moteur : publier le DÉBUT de la journée de
reporting en cours, en epoch, à côté du fuseau. La divergence est écrite aux deux
endroits du code en attendant.
Noté sans conclure : le banc n'a aucune charge `unmeasurable`, donc la loi est
déployée mais pas exerçable de bout en bout.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
Sonde en LECTURE SEULE — l'obligation est celle du moteur, rien n'a été écrit.
Le critère positif est atteint : `deliveredWh` +25 Wh/min (1 500 W, ce que le
compteur ECS annonce), `remainingWh` qui descend d'autant, `gridW` 466 → 463.
Décroissance, pas absence de mur.
Deux invariants tiennent, et l'écran les vérifiera à chaque trame :
- `deliveredWh + remainingWh == targetWh` — et c'est sous `measured` qu'elle
mord, là où elle n'est plus le corollaire trivial d'`unmeasurable` ;
- `gridW == remainingWh / remainingS` — 466 == 466 puis 463 == 463, donc la loi
d'étalement est vérifiable de l'extérieur, sans lire le code.
Fuseau : `remainingS` le confirme de notre côté (18 719 s à 06:48 heure box
mènent à 12:00 heure box), et `System.GetTime` publie `timeZone` — l'app peut
donc être honnête sans attendre l'arbitrage. Règle écrite dans CLAUDE.md et dans
la maquette : dire l'horloge au lieu de la choisir, fuseau de la box affiché à
côté du champ et divergence signalée. Ce que le lot moteur doit trancher reste
entier : d'où vient le fuseau, et ce qu'il fait quand il diverge.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
Obligation déclarée sur le banc puis retirée (`chauffe-eau`, 4 000 Wh avant
12:00, +etm43, sept cycles). Capture sur disque avant la première écriture,
restauration DEPUIS le fichier, comparaison clé par clé : 0 écart.
La forme est celle annoncée, et elle porte plus que le motif : `decision` et
`progress` descendent au niveau, `deliveredWh` est absent sous `unmeasurable`,
`counts` tombe sur `draw.committedW`, et le motif racine porte `level`.
R1, R5 et R7 vérifiés sur le fil ; les deux identités tiennent à chaque cycle.
Deux choses que la mesure apprend, et qu'aucune lecture de code n'aurait données :
- au cycle 05:47 le surplus passe à −922 W : `comfort` tombe à 0 avec
`SURPLUS_INSUFFICIENT` pendant que `eco` achète 767 W au réseau. Le motif
RACINE vaut alors `SURPLUS_INSUFFICIENT` — un client d'avant `levels[]` lit
donc « rien fait » sur une charge qui achète. Vue fausse, pas incomplète ;
- sous `unmeasurable`, `remainingWh` ne bouge pas et `remainingS` descend, donc
`gridW` monte (755 → 767 en quatre cycles). Le plancher ne peut jamais se
refermer : l'accélération jusqu'au mur est la trajectoire GARANTIE du régime,
pas son cas limite. La maquette affiche désormais reste + temps, et pas
seulement les watts de l'instant.
Question posée au moteur : la charge a un compteur (`totalEnergyConsumed: 10`)
et le régime sort quand même `unmeasurable`. Faut-il remplir `sessionWh` depuis
le compteur, et faut-il acheter quand on ne peut pas vérifier ?
`remainingWh` plutôt que `deliveredWh` est accepté, et R5 porte l'argument :
`remainingWh` n'est pas dérivable sous `unmeasurable`, qui est justement le
régime où l'on achète.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
Lien Modbus rétabli, Skoda en charge, valeurs en mouvement.
- `sessionEnergy` : notre doc était EN RETARD, pas contredite. La V2C la publie
depuis le plugin +etm13 et elle bouge (15,8015 → 15,8405 kWh). L'écart avec
`chargeEnergy` vaut 7,2044 kWh aux deux échantillons pris à deux heures
d'écart — constant au dix-millième : c'est l'accumulateur du plugin, et il
prouve l'accumulation que le code seul ne montrait pas. LM-1009 C1 reste vraie
pour les bornes sans cet état ; la V2C n'en fait plus partie. La maquette ne la
nomme donc plus dans l'exemple « non mesurable ».
- `chargingState` reste `Idle` sur un lien VIVANT, pendant que la borne tire
4 372 W : ce n'est pas de la péremption, personne ne maintient le champ.
Et un constat qui n'est pas dû au WiFi : la box a journalisé « Restoring manual
values of false 6 A » trois secondes après la coupure ; la borne est restée à
`power: true`, 7 A, et le lien est revenu sans que rien ne réapplique. En mode
manuel personne ne commande, donc l'écart est permanent — 4,4 kW tirés,
`draw.committedW` à 0. Question posée au moteur.
Aucun avancement n'est affiché pour autant : c'est une décision (D1), pas une
mesure qui manquerait.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
Le moteur a livré la définition d'`evReservedW`, et il ne pouvait pas l'écrire
avant d'en avoir sorti la part réseau d'`EV_GRID_START` : un champ à deux natures
ne se documente pas. Le libellé tranché est le sien, parce qu'il dit la chose —
la latence entre l'ordre et sa lecture au compteur.
« Réservé au véhicule » affirmait deux faussetés : que c'est réservé, et que ça
regarde le véhicule plutôt que la latence de sa mesure.
La clé ARB garde le nom du champ de la box (`budgetEvReserved`), pas celui de
l'ancienne affirmation. Et la consigne qui compte reste écrite à côté : ce n'est
pas un registre, on ne réconcilie rien dessus — la nature du champ l'interdit,
pas son état de livraison.
`draw.committedW` : annoncé livré en +etm31, NON vérifié à la sonde. La box porte
`powersync-energy-plugin-nymea 1.15.2+etm30` au 2026-08-30 et ne publie aucune
clé `draw`. L'exception `EV_GRID_START` reste donc dans `surplusShareW` : c'est
la sonde qui autorise le retrait, pas l'annonce.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
Le moteur l'a trouvé en câblant `counts` : `budget.evReservedW` est un terme de
CORRECTION du budget, pas un registre d'allocation. Il mêle la correction
« commandé non encore mesuré » à la part réseau d'`EV_GRID_START`, et une borne
servie au réseau qui tire déjà ce qu'on lui a commandé y contribue 0 pour un
`targetW` de 7 000 W. `Σ counts == targetW` y serait vraie au premier cycle après
un changement et fausse ensuite : une identité dépendante du temps, qui passe
tous les tests et certifie un total faux. Ne pas livrer était le bon appel.
Réponse : `draw.committedW` en préalable, oui, sans réserve — et trois demandes :
par cycle, en watts, dans la même trame que `budget` ; publié SEUL, les quatre
autres champs de `draw` absents et jamais à 0 (un `authorisedW` forgé afficherait
un plafond de soutirage qui n'existe pas) ; et une définition d'`evReservedW`,
que nous affichons sous « Réservé au véhicule » — un libellé qui affirme une
réservation là où il y a une correction, et que nous ne renommerons pas au jugé.
Nous portions la fausse affirmation en cinq endroits (`CLAUDE.md` ×2, le modèle
×3, la description ARB) : retirée ici, sans changement de comportement. Elle ne
relève pas de la discipline « attendre la sonde » — celle-ci arbitre ce que fait
la box, pas ce que nous en avions cru, et la phrase est fausse aujourd'hui.
Il n'existe donc qu'UNE identité vérifiable, et elle ne couvre qu'un côté :
Σ targetW(surplus) == budget.allocatedW. Côté réseau, rien — pas « à vérifier
plus tard », rien, jusqu'à `draw.committedW`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
Arbitrage rendu au moteur avant qu'il n'écrive R3. La forme proposée est prise
telle quelle : `funding` reste, `counts` s'ajoute, `Σ counts == targetW`
toujours, publié même à une seule destination. L'exception `EV_GRID_START`
disparaît du contrat, remplacée par une règle vérifiable par niveau.
Trois apports de notre côté :
- « approximation » est le mauvais mot et coûterait le champ : quelqu'un
voudrait le rendre exact, et un libellé par part dominante basculerait d'un
cycle à l'autre sur 900/480. Règle demandée : **`grid` l'emporte dès qu'un
watt est acheté** — déterministe, et vraie sans nouvelle décision pour le
plancher éco du §10 ;
- `"mixed"` publié est refusé, et c'est notre propre code qui le dit : une
troisième valeur tombe dans la branche par défaut de tout client — « surplus »
— donc reproduit la panne de l'omission, avec un champ présent en plus pour
faire croire le contraire. Et il serait dérivable de `counts`, donc supprimé
un jour à juste titre. Notre `mixed` reste dérivé, local, jamais transporté ;
- ce que l'app promet : clés de `counts` traitées comme identifiants opaques,
une clé inconnue dit « destination inconnue de cette version », jamais zéro.
Contrat, pas feuille de route : `CLAUDE.md` et `surplusShareW` gardent
l'exception écrite tant que la sonde ne l'a pas vue disparaître de la box.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
La maquette `docs/mockups/deux_passes_eco_confort_mockup.html` répond aux trois
questions du brief plugin §9 (= DESIGN_10 8.5), et sert de contrat au moteur.
- la liste reste ordonnée par RANG : l'ordre de service n'est pas une propriété
de la configuration — il change d'un cycle à l'autre selon les planchers déjà
atteints, donc une liste triée par lui bougerait sous le doigt ;
- une entrée par charge, deux lignes dans la carte : on dédouble là où l'objet
affiché est la SÉQUENCE, jamais là où c'est la CHARGE — d'où un second écran,
« ordre de service du cycle », en lecture seule ;
- « éco servi / confort non » s'affiche en deux états NOMMÉS : en fraction, le
régime nominal se lirait comme une dégradation permanente.
Huit exigences pour `GetLoadTelemetry`, dont R2 (`funding` descend au niveau) et
R4, dont la prémisse a été corrigée par le moteur : `allocatedW` publie le
DÉCIDÉ, donc `Σ targetW == allocatedW` est une identité, et l'écart à afficher
vit entre le décidé et `mechanism.*` (appliqué). D'où le bloc « trois nombres ».
Contrat, pas feuille de route : aucun écran ne se construit avant `levels[]`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
Trois corrections de Patrick sur la section batterie, plus le brief séparé.
1. LE BOOST CHANGE DE NATURE, et ce n'est pas un détail de libellé. Ce n'est pas « vider la
batterie dans la voiture » : c'est charger la voiture plus vite que l'abonnement ne le
permet. Un client en 6 kVA veut 7,5 ; le réseau donne 6, la batterie comble l'écart, le
disjoncteur ne saute pas.
Le réglage devient donc une PUISSANCE DE CHARGE VISÉE, pas une cible de SOC batterie, et
la première des trois fins devient « la voiture a atteint sa cible » — le plancher
batterie reste, mais comme garde-fou et non comme objectif. On ne cherche pas à vider la
batterie, on cherche à finir la charge plus tôt.
Ma réserve « le boost pourrait acheter en cachette » tombe, et elle tombe à l'envers : ce
mécanisme existe précisément pour NE PAS dépasser ce qu'on a le droit de soutirer.
Écrit dans la note : ce bloc appartient au délestage de LM-1006-1 vu par l'autre bout —
au lieu de réduire les charges pour tenir sous le plafond, on complète par la batterie.
Même objet, pas un mécanisme parallèle. Et c'est un argument de vente réel, donc il est
dit à l'écran : recharger plus vite sans passer de 6 à 9 kVA.
2. L'INTERRUPTEUR DE DÉCHARGE PROMETTAIT CE QUE LE MÉCANISME NE TIENT PAS. Il disait « la
maison continue d'être servie ; seule la voiture ne l'est pas ». enableDischarging est
binaire et l'onduleur ne voit qu'une consommation nette : coupé, le réfrigérateur passe au
réseau comme la voiture. Reformulé en « geler la batterie », avec le mécanisme expliqué.
La version modulée — plafonner dischargingRate sur la consommation hors borne, recalculé
à chaque cycle — part au brief comme question, pas à l'écran comme réglage.
C'est exactement la classe de défaut traquée depuis trois jours, et je l'avais écrite
moi-même.
3. LA RÉSERVE ADAPTATIVE DEVIENT UN PLANCHER DE SECOURS. Mon avertissement sur Battery Life
était juste mais incomplet : il disait ce que le bloc n'est pas sans dire ce qu'il est.
Combien d'autonomie garder pour une coupure est une préférence de RISQUE — elle dépend du
congélateur, du télétravail, de la fiabilité du réseau local. Héos ne pourra jamais la
décider à la place du client, ce qui la qualifie exactement selon le critère qui a fait
sortir les quatre autres blocs.
Deux détails de cohérence : la batterie est la seule charge sans compteur dédié possible —
elle publie currentPower elle-même — et c'est DIT plutôt qu'omis en silence comme dans les
cinq autres écrans. Et chargingRate trouve sa place : plafond de soutirage sur la charge
réseau, même motif que la recharge accélérée à l'envers.
Le brief moteur est à part, dans BRIEF_plugin_depuis_maquettes.md : les trois questions de
mécanisme (interdit actif, bail qui expire, controlHealthy), plus quatre que la recharge
accélérée soulève — la boucle à la minute contre un disjoncteur en secondes, la marge
dimensionnée contre le pire démarrage non piloté, le filet qui est la BORNE et non la
batterie, et la latence du Fronius à mesurer sur le banc. Avec la conséquence honnête écrite
noir sur blanc : en 6 kVA le gain réel est d'un à deux kilowatts, pas de 1,5 garanti.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016vrTVifar2GN5rtUh89Wkq
Quatrième passe, même logique que la précédente : ce qui demande un calcul revient à Héos,
pas à un formulaire. Démarrer assez tard pour arriver à 100 % juste avant la pointe suppose
de savoir ce que le soleil va faire — sans prévision ça ne marche pas, et une heure saisie à
la main serait un pari présenté comme un réglage.
Le gain reste écrit dans la note, parce qu'il justifie que le moteur s'en occupe : pic PV de
midi libéré pour l'ECS et la voiture, moins de temps passé à 100 % donc moins de
vieillissement calendaire, et aucun kWh sacrifié — la même énergie, stockée plus tard.
La frise du point de non-retour n'est PAS supprimée : elle remonte dans l'encart du motif
commun, où elle illustre ce que les trois cas partagent au lieu d'illustrer un réglage. C'est
même sa vraie place — une prévision n'engage personne, un point de non-retour si.
Et l'encart gagne une distinction qui manquait : quels paramètres sont calculés (charge
différée → Héos) et lesquels sont saisis (charge réseau, échéance véhicule). Le motif tient
dans les deux cas, ce qui renforce l'argument : le moteur porte la forme, Héos ou
l'utilisateur la remplit.
L'écran de configuration batterie ne garde donc que quatre blocs : le nom, le rang en lecture,
la décharge pendant recharge VE, la réserve adaptative, et la charge réseau manuelle. Quatre
passes, quatre retraits.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016vrTVifar2GN5rtUh89Wkq
Troisième passe de Patrick, et elle enlève encore. Le tableau « qui peut être servi par la
batterie » n'a pas lieu d'être : décider en général qui mérite d'être servi n'est pas un
réglage d'installateur, c'est un arbitrage — et il reviendra à Héos (l'optimiseur MILP) ou à
une décision par le prix, quand l'un ou l'autre existera. Offrir la question à la main
aujourd'hui figerait dans un écran ce qui doit se calculer.
Reste UN interrupteur : bloquer la décharge pendant la recharge du véhicule. C'est le seul
cas qu'aucun rang ne peut exprimer — la nuit il n'y a pas de surplus à répartir, donc aucune
position dans une file ne dit « ne vide pas la batterie dans la voiture ».
Le CSS des lignes de permission est retiré avec elles, plutôt que laissé mort dans la
feuille.
Trois passes, et l'écran n'a fait que rétrécir : un stepper de rang qui doublonnait la liste,
une colonne de permission qui doublonnait le rang, puis le tableau entier. Ce qui reste est
ce qu'aucun autre mécanisme ne sait dire.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016vrTVifar2GN5rtUh89Wkq
Deux corrections de Patrick, dont une qui rattrape une incohérence de ma part.
1. LE RANG N'A RIEN À FAIRE SUR CET ÉCRAN. J'y avais mis un stepper « Position −/+ ». Aucun
des six autres écrans de mécanisme n'en porte : le rang se règle par glisser-déposer dans
la liste des charges, et l'écran réel (load_mechanism_screen.dart) ne fait qu'« Inclure
dans l'arbitrage ». Deux réglages de rang auraient fini par diverger.
Il devient une ligne de lecture, qui rappelle le défaut — batterie en première position de
charge — et où il se règle vraiment.
2. « QUI A LE DROIT AVANT LA BATTERIE » N'EST PAS UN RÉGLAGE : c'est le rang. Mon tableau
avait deux colonnes, Solaire et Batterie ; la première disait exactement ce que la
position dit déjà. Retirée.
Ce qui reste est d'une autre nature, et c'est le seul cas qu'aucun rang ne peut exprimer :
la nuit, il n'y a pas de surplus à répartir, donc « ne vide pas la batterie dans la
voiture » n'est pas une position dans une file, c'est une permission de source. Un seul
interrupteur par charge : peut être servi PAR la batterie, ou non.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016vrTVifar2GN5rtUh89Wkq
La batterie devient une charge du waterfall, donc son bouton Configurer ouvre un écran de
mécanisme comme les cinq autres. Ajouté à la planche existante plutôt qu'à part : c'est
précisément la comparaison côte à côte qui avait révélé « six écrans, trois contrats » avant
qu'une ligne ne soit écrite.
RIEN DE CET ÉCRAN N'EXISTE. Ni BatteryAdapter, ni entrée LoadConfig pour le stockage, ni
prévision PV. Les seuls leviers réels de .75 sont les cinq actions de la classe SunSpec
Storage, et l'état réel affiché se limite à ce que le Thing publie — tout le reste porte un
badge « à créer », y compris là où ça alourdit la maquette.
Le rang par défaut est la batterie EN PREMIER, et ce n'est pas un choix de conception : c'est
la reproduction du comportement actuel. Une mise à jour ne change jamais l'arbitrage sans
geste ; la nouveauté est qu'il devient réglable.
Quatre blocs dans Configurer, dont deux qui ont demandé à être reformulés avant d'être
dessinés :
- Les blocages ne sont PAS une question de rang mais de SOURCE. « Ne pas vider la batterie
dans la voiture la nuit » ne s'exprime pas par un ordre de priorité — la nuit il n'y a pas
de surplus à répartir. La formulation juste est « quelles charges ont le droit d'être
servies par la batterie », réglée charge par charge. Le contrat porte déjà
Source { Solar, GridSource } ; il manque le troisième terme et le droit de le refuser.
- La réserve adaptative est montrée AVEC sa réserve : Victron a conçu Battery Life pour du
plomb, et sur du LFP le problème traité — la sulfatation — n'existe quasiment pas. Si le
mécanisme est repris, ce sera pour un motif à nommer, pas par mimétisme.
- La charge différée montre le POINT DE NON-RETOUR, pas la prévision. C'est lui qui garantit
qu'une prévision fausse ne coûte rien.
- La charge réseau pose le mécanisme seul. Ni prix, ni Tempo, ni marché de gros : le jour où
une source tarifaire existera, elle remplacera le doigt de l'utilisateur sans que le bloc
ne change.
Le boost vers le véhicule est HORS Configurer, sur la carte du tableau de bord : c'est le
seul cas où la batterie est une source et non une charge, et c'est un geste immédiat, pas une
intention durable. Trois fins possibles, toutes obligatoires — une action qui ne sait pas
s'arrêter n'a pas sa place sur un écran client.
Et le motif que la planche fait ressortir : charge différée, charge réseau et échéance
véhicule (LM-1009) ont la MÊME forme — une cible, une échéance, un point de non-retour. Trois
colonnes côte à côte le montrent ; le moteur peut l'implémenter une fois.
Trois questions écrites pour le moteur, pas résolues ici : bloquer demande un interdit ACTIF
et non une allocation à zéro, puisque la batterie agit d'elle-même · cet interdit doit
EXPIRER, sinon un HEMS qui tombe laisse la batterie inerte · et controlHealthy == false doit
sortir la batterie de l'arbitrage, comme available == false pour une charge en défaut.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016vrTVifar2GN5rtUh89Wkq
Le miroir INTERFACE_etmvariableload.md est passé en rév. 3 pendant la session (corps
identique au canonique du dépôt plugin, vérifié). Son §10 s'adresse nommément à l'agent
app — et il RATIFIE les maquettes dessinées aujourd'hui : relays[] = {thingId, powerW}
pour l'ECS relais, maxPowerW seul pour le continu, powerLevels absents de la config et
dérivés par le routeur.
Trois recalages :
- Le picker de relais filtre sur l'interface nymea « power » et présente les things par
NOM — nommé dans la maquette, il ne l'était pas.
- Le point 4 du brief plugin est tranché par la rév. 3 : la duplication de la
combinatoire est voulue (l'app dérive pour montrer, le routeur pour exécuter). La
demande devient donc un moyen de détecter la divergence — la télémétrie publie déjà
maxStageW, l'app peut y confronter le maximum de sa propre liste.
- En-tête du pont VM Service, que le commit précédent avait laissé dans sa forme brute.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPUo3RMr8SzK6qbFtfBm8H
Trois maquettes, neuf écrans, après le passage sur appareil qui a montré que
/energy/setup décrit autre chose que l'installation.
- charges_pilotables_mockup.html : la liste à deux niveaux, avec le bandeau
d'arbitrage hérité de /energy/loads (qui disparaît) et la télémétrie sur la carte
de chaque charge.
- configurer_mecanismes_mockup.html : les six « Configurer » — routeur de relais,
modulable, SG-Ready, borne, zones HVAC, sélecteur d'appareils.
- raccordement_reseau_mockup.html : compteur réseau et protection de surcharge.
Décisions de conception que les images ne portent pas seules : les paliers
n'existent que chez le routeur de relais et y sont DÉDUITS des combinaisons ; le
mode fixed d'etmvariableload (legacy) n'est plus proposé mais reste lisible, parce
qu'ouvrir un écran ne doit pas convertir une config déployée ; SG1/SG2 sont une
convention d'app retrouvée par l'encodage standard, la box ne stocke qu'une liste
de relais par état ; le compteur par charge est dessiné inactif avec sa raison ; la
borne règle un mode par DÉFAUT, pas une commande.
CLAUDE.md corrigé contre JSONRPC.Introspect (plugin 1.15.2+etm15) :
- Energy.SetChargingMode n'existe pas — le « bug critique » décrivait un appel
impossible. Energy.* n'a que cinq méthodes.
- Le namespace EnergyPlugin.* n'existe pas : c'est NymeaEnergy.*, 20 méthodes et
14 notifications, toutes listées.
- ChargingInfo : chargingMode / targetPercentage / endDateTime (Uint), et non
mode / targetSoc / endTime. minCurrent n'existe nulle part.
- phasePowerLimit est en AMPÈRES par phase, et 0 coupe toute la recharge
intelligente.
- AirConditioning expose 8 méthodes, pas 3.
Toutes les méthodes citées ont été revérifiées une par une : aucune introuvable.
Règle ajoutée : contrôler ce fichier contre Introspect avant chaque lot — trois
fois aujourd'hui il a envoyé un agent dans le vide.
Et docs/BRIEF_plugin_depuis_maquettes.md : les six points que les maquettes
remontent vers le moteur, dont un seul blocage dur (pas de champ de courant
minimum pour le mode Min+PV).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPUo3RMr8SzK6qbFtfBm8H