diff --git a/docs/BRIEF_plugin_depuis_maquettes.md b/docs/BRIEF_plugin_depuis_maquettes.md index f6a0c0c..18d3549 100644 --- a/docs/BRIEF_plugin_depuis_maquettes.md +++ b/docs/BRIEF_plugin_depuis_maquettes.md @@ -2,6 +2,67 @@ --- +## 2026-09-01 — §10 vu à la sonde : les six champs, et une trajectoire à trancher + +**Obligation déclarée sur le banc puis retirée** — `chauffe-eau`, `needs {dailyDeadline: "12:00", +minEnergyWhPerDay: 4000}`, sept cycles, `+etm43`. Capture sur disque avant la première écriture, +restauration **depuis le fichier**, comparaison clé par clé : *« 0 écart »*. + +### La forme est celle qui était annoncée, et elle porte plus que le motif + +```jsonc +{ "level": "eco", "funding": "grid", "targetW": 766.813994355397, + "counts": { "draw.committedW": 766.813994355397 }, + "progress": { "regime": "unmeasurable", "targetWh": 4000 }, + "decision": { "code": "ECO_FLOOR_GRID", "params": { + "gridW": 767, "remainingWh": 4000, "targetWh": 4000, + "remainingS": 18779, "regime": "unmeasurable", "atMaximum": false } } } +``` + +`decision` et `progress` **au niveau**, `deliveredWh` **absent** sous `unmeasurable`, `counts` qui +tombe sur `draw.committedW`, et le motif racine qui porte `"level": "comfort"`. R1, R5 et R7 sont +vérifiés sur le fil. Les deux identités tiennent à chaque cycle. + +### Le dernier cycle est le cas que la maquette visait, et il valide R7 durement + +À 05:47 le surplus passe à **−922 W** : le niveau `comfort` tombe à `targetW: 0` avec +`SURPLUS_INSUFFICIENT` et `counts {"budget.allocatedW": 0}` — destination publiée **à zéro**, comme +demandé — pendant que le niveau `eco` **achète 767 W au réseau**. + +Le motif racine de cette charge vaut alors `SURPLUS_INSUFFICIENT`. **Un client d'avant `levels[]` lit +donc « surplus insuffisant, rien fait » sur une charge en train d'acheter 767 W.** Ce n'est pas une +vue incomplète, c'est une vue **fausse** — et c'est l'argument le plus dur en faveur de +`decision.level` et des deux lignes à l'écran. + +### La trajectoire, mesurée — et la question qu'elle pose + +| cycle | `remainingWh` | `remainingS` | `gridW` | +|---|---|---|---| +| 05:42 | 4 000 | 19 079 | 755 | +| 05:45 | 4 000 | 18 899 | 762 | +| 05:47 | 4 000 | 18 779 | 767 | + +Sous `unmeasurable`, rien n'est soustrait : **le plancher ne peut jamais se refermer**, donc l'achat +s'accélère mécaniquement jusqu'à l'échéance et finit en `ECO_FLOOR_MISSED`. Ce n'est pas un cas +limite du régime, c'est sa trajectoire garantie. La maquette l'affiche désormais — *reste* et +*temps*, pas seulement les watts de l'instant. + +**Et le point qui mérite votre arbitrage** : cette charge **a un compteur**. `ECS-Meter` publie +`currentPower: 1500` **et `totalEnergyConsumed: 10`** — une énergie, la grandeur exacte qui manque. +Le régime sort quand même `unmeasurable`. Si c'est `LoadContextTelemetry::sessionWh` toujours +déclaré et jamais rempli hors borne, alors **aujourd'hui toute obligation éco achète à l'aveugle et +accélère, y compris sur une charge instrumentée**. Deux questions, et elles ne sont pas d'écran : +faut-il remplir `sessionWh` depuis le compteur de charge, et faut-il acheter du tout quand on ne +peut pas vérifier ? Notre écran montrera la trajectoire ; il ne la corrigera pas. + +### Un détail à confirmer + +`gridW: 767` (entier) et `targetW: 766.813994355397` (double) portent le même fait, et `counts` +s'accorde avec `targetW`. Nous prenons donc **`targetW`/`counts` pour l'arithmétique** et `gridW` +**pour la phrase**. Confirmez si c'est l'intention. + +--- + ## 2026-08-30 (soir, lien rétabli) — relevé frais : deux confirmations et une correction ### `chargingState` figé : confirmé sur lien VIVANT, ce n'est pas de la péremption diff --git a/docs/mockups/deux_passes_eco_confort_mockup.html b/docs/mockups/deux_passes_eco_confort_mockup.html index 27fb8bc..0471a85 100644 --- a/docs/mockups/deux_passes_eco_confort_mockup.html +++ b/docs/mockups/deux_passes_eco_confort_mockup.html @@ -338,10 +338,11 @@ ÉCO
Plancher servi — 2 600 W achetés au réseau - Avancement non mesurable : cette borne ne publie pas d'énergie de session - — c'est le cas de `wallboxNoMeter` et d'une des deux classes `wallbox` du banc. + Avancement non mesurable : cette borne ne publie pas d'énergie de session. NON MESURABLE
+ Reste 4,0 kWh à livrer en 5 h 13 — et ce taux ne peut que monter : rien + n'est soustrait de ce qui reste, donc l'achat s'accélère jusqu'à l'échéance. L'obligation est servie ; elle ne pourra jamais être annoncée tenue.
@@ -423,6 +424,11 @@ setpointW, currentA), qui existe déjà aujourd'hui.
  • Et il ne se répartit pas non plus. L'écart appartient à la charge, pas à un niveau : l'adaptateur arrondit une consigne unique, il ne sait pas de quel besoin elle venait.
  • +
  • Sous unmeasurable, le plancher ne peut pas se refermer — mesuré le + 2026-09-01 sur quatre cycles : remainingWh figé à 4 000, remainingS qui + descend, gridW qui monte 755 → 767. Ce n'est pas un cas limite, c'est la + trajectoire garantie du régime : l'écran doit montrer reste et temps, pas + seulement les watts de l'instant, sans quoi « 767 W achetés » ne laisse pas deviner le mur.
  • * « Commandé, pas encore mesuré » — et ce n'est pas une destination. Le champ budget.evReservedW est un terme de correction : la latence entre l'ordre et sa lecture au compteur. Il est affiché parce que la box le publie, jamais sommé. Son ancien @@ -654,16 +660,15 @@ // L'appliqué vit dans "mechanism" ; le mesuré dans "measurement". "levels": [ // AJOUT — un élément par passe RÉELLEMENT parcourue - { "level": "eco", - "targetW": 1400, // la part de ce décidé qui revient à ce niveau - "funding": "grid", // L'ORIGINE — « ces watts sont achetés ». Livré en +etm30. - "counts": { "draw.committedW": 1400 }, // LE REGISTRE — « ils sont comptés ici ». - // Σ counts == targetW, toujours. Publié même à une seule - // destination, et même à zéro, avec sa destination. - "decision": { "code": "ECO_FLOOR_GRID", - "params": { "deliveredWh": 2100, "targetWh": 3000, "gridW": 1400 } }, - "progress": { "regime": "measured", // measured | estimated | unmeasurable - "deliveredWh": 2100, "targetWh": 3000 } }, // deliveredWh ABSENT si unmeasurable + { "level": "eco", // RELEVÉ sur `.75` le 2026-09-01, +etm43 + "targetW": 766.813994355397, // le décidé, NON arrondi + "funding": "grid", + "counts": { "draw.committedW": 766.813994355397 }, + "progress": { "regime": "unmeasurable", "targetWh": 4000 }, + // deliveredWh ABSENT sous unmeasurable — jamais 0 + "decision": { "code": "ECO_FLOOR_GRID", "params": { + "gridW": 767, "remainingWh": 4000, "targetWh": 4000, + "remainingS": 18779, "regime": "unmeasurable", "atMaximum": false } } }, { "level": "comfort", "targetW": 0, "decision": { "code": "SURPLUS_INSUFFICIENT", "params": { "requiredW": 900, "availableW": 0 } } } @@ -751,7 +756,16 @@ pendant que l'installation en tire 1 000 — d'où le bloc « trois nombres » de l'écran 3, qui empêche de lire cet écart comme une erreur de comptage.

    -
    R5Le régime de LM-1009 est porté par le NIVEAU éco, pas par la charge +
    R5Le régime est porté par le NIVEAU — ✔ en ligne +

    Vérifié à la sonde le 2026-09-01 : progress et decision descendent au + niveau, et deliveredWh est bien absent sous unmeasurable.

    +

    Et le motif publie remainingWh, pas deliveredWh — accepté. Ce n'est pas + « une source par fait » qui tranche (on aurait pu retirer deliveredWh de progress) + mais ceci : remainingWh n'est pas dérivable sous unmeasurable, et c'est + exactement le régime où l'on achète. Un champ qui n'existe que là où on peut le calculer ferait taire + l'écran dans le cas qui coûte de l'argent. Sous unmeasurable, + remainingWh == targetWh : « 4 000 sur 4 000 » se lit « rien de mesurable », jamais + « rien livré ».

    progress.regime ∈ measured | estimated | unmeasurable, et deliveredWh absent sous unmeasurable — jamais 0. C'est la même règle que measurement.source = "none", qui nous a déjà servis : un régime publié sépare « pas mesurable »