diff --git a/CLAUDE.md b/CLAUDE.md index 5245e62..b49fc70 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -264,8 +264,16 @@ surplus, même cycle — et c'est pourquoi le champ a dû descendre d'un cran ** L'identité vérifiable devient : *somme des `targetW` des niveaux financés au surplus == `budget.allocatedW`*. Vérifiée à la sonde sur `.75` le 2026-08-30 (`+etm30`) : -3 500 + 3 000 == 6 500, puis 1 500 == 1 500 au cycle suivant. Une charge financée au réseau -vit dans `budget.evReservedW`. Omis en mode dégradé — sans plan, pas de financement. +3 500 + 3 000 == 6 500, puis 1 500 == 1 500 au cycle suivant. Omis en mode dégradé — sans +plan, pas de financement. + +> 🔴 **Et il n'y a d'identité que de ce côté-là.** Une charge financée au réseau ne vit +> **nulle part** : `budget.evReservedW` n'est pas un registre d'allocation mais un **terme de +> correction** du budget, qui mêle la correction « commandé non encore mesuré » à la part +> réseau d'`EV_GRID_START` — une borne servie au réseau qui tire déjà ce qu'on lui a commandé +> y contribue **0** alors que son `targetW` vaut 7 000 W. Constaté par le moteur le +> 2026-08-30 en câblant R3. Les watts achetés n'auront de registre qu'avec +> `draw.committedW`, préalable à R3. **Ne réconcilier aucun total sur `evReservedW`.** Le niveau publié est `"comfort"` et ce **n'est pas un rebaptisage** : c'est bien la passe qui, au §10, servira le confort depuis le surplus. Un niveau à `targetW: 0` est une passe @@ -339,7 +347,8 @@ Et **deux pièges de lecture**, tous deux au contrat : **3. `EV_GRID_START` partage une allocation entre les DEUX compteurs du budget.** C'est le seul motif qui le fasse : `budgetW` vient du surplus et entre dans `budget.allocatedW`, -`gridW` est acheté au réseau et entre dans `budget.evReservedW`, avec +`gridW` est acheté au réseau — et **n'entre dans aucun registre** (cf. §1 : `evReservedW` +est une correction, pas une destination), avec `budgetW + gridW == allocatedW`. Toute réconciliation doit traiter cette ligne à part — cf. `LoadTelemetryEntry.surplusShareW`. Motif **jamais vu sur machine** au 2026-08-27 : la clé est prête, rien n'est bâti autour. diff --git a/docs/BRIEF_plugin_depuis_maquettes.md b/docs/BRIEF_plugin_depuis_maquettes.md index 451754b..d42983c 100644 --- a/docs/BRIEF_plugin_depuis_maquettes.md +++ b/docs/BRIEF_plugin_depuis_maquettes.md @@ -2,6 +2,69 @@ --- +## 2026-08-30 (suite) — `draw.committedW` en préalable : OUI, sans réserve + +**Et le refus de livrer `counts` sur `budget.evReservedW` est le bon appel.** Une identité +*dépendante du temps* est pire que pas d'identité : vraie au premier cycle après un +changement, fausse après convergence, elle passerait tous les tests — qui portent sur des +cycles isolés — et **certifierait** un total faux chez les clients. R3 existe pour empêcher +une réconciliation qui pourrit sans se voir ; la livrer sur un terme tantôt registre tantôt +correction aurait fabriqué exactement ça, avec en plus le sceau d'une identité publiée. + +### Les trois destinations, et ce que l'app peut en dire + +| Destination | Nature | Réconciliable ? | +|---|---|---| +| `budget.allocatedW` | **registre d'allocation** (surplus) | **oui, aujourd'hui** — mesuré sur `.75` | +| `budget.evReservedW` | **terme de correction** du budget, deux natures mêlées | **non, et jamais** | +| `draw.committedW` | **registre** des watts achetés | oui, dès qu'il existe | + +Conséquence, à dire telle quelle : **il n'existe aujourd'hui qu'une identité vérifiable, et +elle ne couvre qu'un côté.** `Σ targetW(surplus) == budget.allocatedW` — vérifiée à la sonde +le 2026-08-30 (06:10 et 06:14). Côté réseau : **rien**. Pas « à vérifier plus tard », pas +« approximativement `evReservedW` » : rien, jusqu'à `draw.committedW`. + +### Nous portions la fausse affirmation, et elle part aujourd'hui + +Elle est écrite chez nous en cinq endroits — « une charge financée au réseau vit dans +`budget.evReservedW` » (`CLAUDE.md` ×2, le modèle ×3, la description ARB de la mention +« servie au réseau »). Retirée dans le même lot, sans changement de comportement. + +> **Et la distinction avec notre discipline de la semaine, parce qu'elle a l'air de la +> contredire.** L'exception `EV_GRID_START` décrit un **comportement de la box** : on ne la +> retire qu'au vu de la sonde. « `evReservedW` est la destination des watts achetés » est une +> **affirmation sur le sens d'un champ**, et elle est fausse *maintenant*, sur la box +> d'aujourd'hui. Attendre une livraison pour corriger ce qu'on a compris de travers serait +> laisser une doc mentir en connaissance de cause. **La sonde arbitre ce que fait la box, pas +> ce que nous en avons cru.** + +### Trois demandes sur `draw.committedW` + +**a. Par cycle, en watts, dans la même trame que `budget`.** Sinon on compare deux instants, +et l'identité redevient dépendante du temps par un autre chemin — celui-là même qu'on vient +d'éviter. + +**b. Ne fabriquez pas le reste de l'objet `draw`.** Notre maquette lui donne aussi +`authorisedW`, `remainingW`, `binding`, `perPhaseBound` (§10). Publier +`draw: { "committedW": 1400 }` **seul** est parfait. Publier `authorisedW: 0` ou +`binding: "connection"` par défaut ferait afficher à l'écran « ordre de service » un +**plafond de soutirage qui n'existe pas, avec sa source** — un chiffre crédible et faux, et +la faute exacte que ce champ est censé rendre impossible. Absent, jamais forgé : l'écran 2 +n'apparaîtra qu'avec l'objet complet. + +**c. Une phrase de définition pour `evReservedW`.** Nous l'affichons sous le libellé +**« Réservé au véhicule »** (`_BudgetTable`), qui affirme une réservation là où il y a une +correction. Nous ne le renommerons pas au jugé — donnez la définition, nous écrirons le +libellé. C'est le seul geste que cette découverte laisse en suspens côté écran. + +### Ce qui ne bouge pas + +`counts` reste retenu tel qu'arbitré ce matin : la **forme** ne change pas, seul son préalable +apparaît. Et l'exception `EV_GRID_START` reste dans le code et dans `CLAUDE.md` — elle tiendra +plus longtemps que prévu, et c'est très bien ainsi. + +--- + ## 2026-08-30 — R3 : `counts` est retenu, et `funding` sort de la réconciliation **Réponse à la question du moteur sur le niveau mixte.** La forme proposée est prise telle diff --git a/docs/mockups/deux_passes_eco_confort_mockup.html b/docs/mockups/deux_passes_eco_confort_mockup.html index f92a057..4b9e80d 100644 --- a/docs/mockups/deux_passes_eco_confort_mockup.html +++ b/docs/mockups/deux_passes_eco_confort_mockup.html @@ -239,7 +239,7 @@
■Passe 2 — surplus disponible
Surplus0
-
Réservé VE0
+
Réservé VE *0
Recrédité0
Alloué0
Reliquat0
@@ -422,6 +422,10 @@ 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.
  • +
  • * « Réservé VE » n'est pas une destination — c'est un terme de correction du budget + (constaté par le moteur le 2026-08-30). Il est affiché parce que la box le publie, jamais sommé, et + son libellé actuel affirme une réservation qui n'a pas lieu : il attend une définition du moteur pour + être réécrit. Les watts achetés, eux, n'ont de registre qu'avec draw.committedW.
  • Le bandeau ◆ n'apparaît que si au moins une charge porte une obligation éco. Sans obligation, il n'y a qu'une passe utile et la phrase serait du bruit (LM-1007).
  • @@ -663,7 +667,12 @@ // et, une fois par cycle, à côté de "budget" : "draw": { "authorisedW": 4000, "committedW": 4000, "remainingW": 0, - "binding": "gridOperator", "perPhaseBound": false } + "binding": "gridOperator", "perPhaseBound": false } + +// ⚠ committedW part SEUL, et AVANT counts (2026-08-30) : c'est le registre des watts +// achetés, et il n'en existe aucun aujourd'hui. draw: {"committedW": 1400} tout court +// est la bonne première livraison — les quatre autres champs ABSENTS, jamais à 0 : +// un authorisedW forgé afficherait un plafond de soutirage qui n'existe pas.

    Huit exigences, et chacune tient un endroit précis de la maquette

    @@ -703,6 +712,13 @@ ni "mixed" publié : une troisième valeur tomberait dans la branche par défaut de tout client — « surplus » — donc reproduirait la panne de l'omission, et elle serait dérivable de counts, donc supprimée un jour à juste titre.

    +

    Et il a un préalable, trouvé en le câblant (2026-08-30) : draw.committedW. + budget.evReservedW n'est pas un registre d'allocation mais un terme de correction du + budget — 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. Les watts achetés n'ont aucun registre aujourd'hui — d'où une seule identité + vérifiable, du côté surplus, et rien de l'autre côté tant que committedW n'est pas publié.

    Ce que l'app promet en échange : les clés de counts sont traitées comme des identifiants opaques, jamais comme des chemins. Une clé inconnue d'une version ancienne n'est pas perdue : l'identité Σ counts == targetW reste vérifiable sans connaître le sens des clés, et diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 12296ee..602fb90 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -155,7 +155,7 @@ }, "telemetryFundedByGrid": "Financée au réseau (échéance ou tarif dynamique) — hors budget de surplus", "@telemetryFundedByGrid": { - "description": "funding == « grid » : l'allocation vit dans budget.evReservedW, pas dans budget.allocatedW. Sans cette mention, l'utilisateur voit une charge servie alors que le surplus est nul et croit à un défaut." + "description": "funding == « grid » : l'allocation est hors de budget.allocatedW, et sans registre où la retrouver (evReservedW est une correction du budget, pas une destination — constaté 2026-08-30). Sans cette mention, l'utilisateur voit une charge servie alors que le surplus est nul et croit à un défaut." }, "telemetryNotArbitrated": "Non arbitrée — absente du dernier cycle publié", "@telemetryNotArbitrated": { diff --git a/lib/models/load_telemetry.dart b/lib/models/load_telemetry.dart index 9ce9d8a..cfddb1d 100644 --- a/lib/models/load_telemetry.dart +++ b/lib/models/load_telemetry.dart @@ -441,7 +441,11 @@ class LoadTelemetryEntry { /// /// - `"surplus"` — la cascade PV. L'allocation est comptée dans `budget.allocatedW`. /// - `"grid"` — le proxy (échéance de départ, tarif dynamique) qui **soutire au - /// réseau**. Elle vit dans `budget.evReservedW`, PAS dans `budget.allocatedW`. + /// réseau**. Elle n'est PAS dans `budget.allocatedW` — et elle n'est nulle part + /// ailleurs non plus : `budget.evReservedW` est un **terme de correction** du budget, + /// pas un registre d'allocation (constaté par le moteur le 2026-08-30 en câblant R3 — + /// une borne au réseau déjà mesurée y contribue 0 pour un `targetW` de 7 000 W). Les + /// watts achetés n'auront de registre qu'avec `draw.committedW`. /// /// **Sommer les `allocatedW` sans filtrer donne un écart avec `budget.allocatedW` que /// rien ne permet d'interpréter** : défaut du moteur, ou borne servie au réseau ? Cf. @@ -541,7 +545,7 @@ class LoadTelemetryEntry { } /// Vrai quand **tout** ce qui est servi à cette charge est acheté au réseau — donc - /// compté dans `budget.evReservedW` et non dans `budget.allocatedW`. + /// **hors** de `budget.allocatedW`, et sans registre où le retrouver (voir [funding]). /// /// Volontairement faux sur `'mixed'` : la mention « servie au réseau » serait alors une /// demi-vérité, et c'est un écran à deux niveaux qui la remplacera (R1, R3 à R8). @@ -681,9 +685,12 @@ class LoadTelemetry { /// Somme des allocations **financées par le surplus**. /// - /// C'est le seul terme comparable à `budget.allocatedW` : une borne servie au réseau - /// est comptée dans `budget.evReservedW`, et l'inclure ici creuserait un écart que rien - /// ne permettrait d'interpréter — défaut du moteur, ou borne au réseau ? + /// C'est le seul terme comparable à `budget.allocatedW` : une charge servie au réseau + /// n'entre pas dans ce compteur, et l'inclure ici creuserait un écart que rien ne + /// permettrait d'interpréter — défaut du moteur, ou charge au réseau ? + /// + /// **Et c'est la seule identité qui existe** : il n'y en a aucune du côté réseau tant que + /// `draw.committedW` n'est pas publié. `budget.evReservedW` ne peut pas en tenir lieu. /// /// Somme des [LoadTelemetryEntry.surplusShareW], et non des `allocatedW` filtrés : le /// démarrage soutiré (`EV_GRID_START`) partage une même allocation entre les deux