diff --git a/docs/DESIGN_MIN_GARANTI.md b/docs/DESIGN_MIN_RESEAU.md similarity index 50% rename from docs/DESIGN_MIN_GARANTI.md rename to docs/DESIGN_MIN_RESEAU.md index 6e9e476..7603961 100644 --- a/docs/DESIGN_MIN_GARANTI.md +++ b/docs/DESIGN_MIN_RESEAU.md @@ -1,12 +1,12 @@ -# Minimum garanti — design +# Minimum réseau — design -> Ouvert le 2026-09-06. **Option 2 retenue** : livrer le minimum garanti maintenant, avec la +> Ouvert le 2026-09-06. **Option 2 retenue** : livrer le minimum réseau maintenant, avec la > machinerie du §10 ; le renommage l'accompagne. L'arbitrage au prix (option 3) reste l'horizon, > il demande une source tarifaire et une prévision. ## 1. Le constat, et il est double -**Le mode `ChargingModeEcoWithMinCurrent` n'a jamais eu de minimum garanti** — non pas parce que +**Le mode `ChargingModeEcoWithMinCurrent` n'a jamais eu de minimum réseau** — non pas parce que le code manquait, mais parce qu'il n'a jamais été atteint. Établi dans `DESIGN_3g.md` §5 : mort par réécriture chez l'amont, puis mort par exclusion depuis 3g-2. @@ -28,7 +28,7 @@ Chiffrage retenu, tarif de rachat récent à **0,01 €/kWh** : | charger en journée, 30 % au réseau | **0,073 €/kWh** | | charger la nuit, 100 % au réseau | **0,180 €/kWh** | -Sur ces installations — **la majorité du parc neuf** — le minimum garanti en journée est +Sur ces installations — **la majorité du parc neuf** — le minimum réseau en journée est simplement le bon choix, et **aucun arbitrage n'est nécessaire pour le savoir**. Le prix ne devient décisif que sur les anciens contrats à **0,1296 €**, où l'écart tombe à deux centimes et **s'inverse sous 62 % de couverture solaire**. @@ -40,7 +40,7 @@ elle ne ferme pas la porte : un arbitrage au prix choisira plus tard *s'il faut* ## 3. Condition 1 — la machinerie du §10, pas un second chemin d'achat -Le minimum garanti **passe par la passe éco**, celle qui achète déjà : +Le minimum réseau **passe par la passe éco**, celle qui achète déjà : - **borné par l'autorisation de soutirage** (`DrawCap` / `DrawMargin`, trois sources) — comme tout achat ; @@ -64,19 +64,32 @@ Un champ de plus **dans `needs`**, frère de `minEnergyWhPerDay` — pas une str needs : { minEnergyWhPerDay : Uint, // énergie, avec échéance dailyDeadline : String, - guaranteedPowerW : Uint // NOUVEAU — puissance, permanente + minPowerWAlways : Uint // NOUVEAU — puissance, tant que la charge est là } ``` -**À ne pas confondre avec `minPowerW`** (`LM-1201`), et la différence est de nature : +**À ne pas confondre avec `minPowerW`** (`LM-1201`) : | | ce que ça dit | |---|---| | `minPowerW` | **SI** on sert cette charge, au moins ceci. Un plancher de **modulation**. | -| `needs.guaranteedPowerW` | On sert cette charge au moins ceci, **TOUJOURS** — surplus ou non. Une obligation de **présence**. | +| `needs.minPowerWAlways` | On sert cette charge au moins ceci, **tant qu'elle est là**. Une **demande**, pas un plancher. | -Le premier borne une consigne ; le second en crée une. Les deux peuvent coexister sur la même -charge sans se contredire. +Le premier borne une consigne ; le second en crée une. Les deux coexistent sans se contredire. + +### POURQUOI une puissance ici, et une énergie ailleurs — et ce n'est PAS la modulation + +L'ECS multi-paliers module aussi. Ce qui sépare vraiment les deux cas : + +> **On ne sait pas combien de temps la voiture reste branchée.** + +Une obligation en énergie **suppose une échéance** — c'est ce qui donne un dénominateur à la +cadence. Une borne n'en a aucune tant que personne n'en déclare. **« 4 140 W tant qu'elle est +là » est la seule formulation qui ne suppose rien.** + +Un chauffe-eau, lui, a une échéance naturelle et une capacité finie : l'énergie y est la bonne +grandeur, et l'obligation éco la sert déjà. La différence est de **nature du besoin**, pas de +capacité technique de la charge. ### La composition dans la passe éco @@ -84,24 +97,41 @@ charge sans se contredire. le **maximum des deux** : ``` -watts = max( cadenceObligation , guaranteedPowerW ) +watts = max( cadenceObligation , minPowerWAlways ) ``` Quatre invariants, et chacun ferme un silence : -1. **La garantie ne se « tient » JAMAIS.** `tenue` ne décrit que l'obligation en énergie ; une - puissance permanente n'a pas de cible et ne se complète pas. Donc quand l'obligation est - tenue, `watts` retombe sur la garantie — **pas sur zéro**. C'est exactement la différence de +1. **Le minimum ne se « tient » JAMAIS.** `tenue` ne décrit que l'obligation en énergie ; une + puissance demandée en permanence n'a pas de cible et ne se complète pas. Donc quand + l'obligation est tenue, `watts` retombe sur le minimum — **pas sur zéro**. C'est exactement la différence de nature, et c'est là qu'elle se voit dans le code. -2. **`progress` ne décrit que l'obligation.** Sur une charge à garantie seule, `progress` est +2. **`progress` ne décrit que l'obligation.** Sur une charge à minimum seul, `progress` est **absent** — jamais à zéro : un avancement nul se lirait « rien livré », alors qu'il n'y a rien à avancer. 3. **Le motif dit LEQUEL DES DEUX MORD.** Sans ça, l'écran affiche un nombre qu'il ne peut pas expliquer — et deux causes différentes produiraient le même chiffre. Le motif gagne - `guaranteedW` et une marque de ce qui borne. -4. **Une garantie non honorée se DIT.** Si l'autorisation de soutirage ne la permet pas, elle - n'est pas servie — et c'est `DRAW_CAP` qui le dit, en nommant la garantie. Le silence ici - ferait croire à une garantie tenue. + `minAlwaysW` et une marque de ce qui borne. +4. **Un minimum non servi se DIT.** Si l'autorisation de soutirage ne le permet pas, il n'est + pas servi — et c'est `DRAW_CAP` qui le dit, en le nommant. Le silence ici ferait croire à un + minimum honoré, ce qui est précisément la promesse qu'on refuse de faire. + +## 4-bis. Le RANG et la PRÉCÉDENCE — ce que le minimum ne bouscule pas + +**Le minimum est servi à SON rang, il ne le contourne pas.** Un minimum déclassé par une charge +mieux rangée est le comportement voulu, et il découle de `LM-1002` : **le rang est ce que +l'installateur décide.** Le contredire par un mécanisme serait exactement le doublon qu'on refuse +partout — deux autorités sur le même ordre. Si le client veut sa voiture avant l'ECS, **il la +range avant**. + +> Nuance à connaître, parce qu'elle décide du mot au §5-bis : la hiérarchie éco/confort +> **surplombe** le rang — « un confort de rang 1 passe après un éco de rang 3 » +> (`rulebasedscheduler.cpp` l. 243-246). Un minimum passe donc avant **tout** le confort, mais +> le rang le départage face à un **autre besoin éco**. + +**`DRAW_CAP` et la réserve batterie PRIMENT.** Un minimum qui passerait outre un plafond de +branchement ferait disjoncter l'installation. C'est un **besoin**, pas une exception aux plafonds +— et quand un plafond l'empêche, c'est `DRAW_CAP` qui le dit en le nommant (invariant 4 du §4). ## 5. Condition 3 — nommer les trois modes pour ce qu'ils font @@ -113,35 +143,71 @@ contrat** — c'est là que vit le mensonge, et c'est de là que l'app tire ses |---|---|---| | `ChargingModeNormal` | « Recharge immédiate au maximum disponible » | **MANUEL.** La borne sort de l'arbitrage — *« l'utilisateur pilote, l'arbitre s'abstient »*. Le moteur ne commande **rien**. Seule la protection de surcharge la touche encore. | | `ChargingModeEco` | « Recharge sur surplus solaire uniquement » | exact | -| `ChargingModeEcoWithMinCurrent` | « Eco + courant minimum garanti (6 A) si pas de surplus » | **rien** — le chemin n'est pas atteint | +| `ChargingModeEcoWithMinCurrent` | « Eco + courant minimum réseau (6 A) si pas de surplus » | **rien** — le chemin n'est pas atteint | **`Normal` n'est pas un « boost ».** Un boost commanderait le maximum ; celui-ci ne commande pas. La seule chose que le moteur y fasse encore est de délester en surcharge — ce qui doit rester, et doit être **dit** : un mode « manuel » qui coupe quand même mérite de l'annoncer. +## 5-bis. LE MOT — et ni « garanti » ni « prioritaire » ne tiennent + +La question est la bonne, et elle est la même que celle qu'on est en train de corriger : **un nom +de mode qui promet autre chose que ce que le code fait.** Les deux candidats échouent au même +test, dans deux registres différents. + +| mot | vrai quand | FAUX quand | verdict | +|---|---|---|---| +| **garanti** | jamais entièrement | plafond de soutirage atteint, réserve batterie, ou un autre éco mieux rangé épuise l'autorisation | **promet une certitude que rien ne tient** | +| **prioritaire** | face à **tout** le confort — la passe éco surplombe le rang | face à un **autre besoin éco** mieux rangé | **vrai en régime normal, faux exactement dans le cas d'échec** | + +**« Prioritaire » est le moindre mensonge, et c'est ce qui le rend pire ici** : il est vrai 95 % +du temps, donc il ne se fait jamais démentir — sauf le jour où la voiture ne charge pas, où il +dit précisément l'inverse de ce qui s'est passé. Un mot qui ne se trompe que dans le cas +intéressant est un mot qui ne sera pas relu. Et il contredirait `LM-1002` dans le libellé : il +laisse croire que le mode réordonne, alors que **c'est l'installateur qui range**. + +### Le mot retenu : on nomme le FINANCEMENT + +C'est la seule propriété qui tienne **toujours**, et c'est aussi la vraie différence avec `Eco` : + +> **`Eco` dépense le surplus. Ce mode-ci ACHÈTE le complément.** + +- **Libellé du mode : « Surplus + minimum réseau ».** Il dit ce que le moteur fera — servir sur + surplus, et acheter le reste jusqu'au minimum — et **ne promet rien sur le résultat**, qui + dépend du rang et des plafonds. +- **Nom du champ : `minPowerWAlways`.** Grammaire de son frère `minEnergyWhPerDay` : les deux + **déclarent une demande**, aucun ne promet une livraison. Personne ne lit + `minEnergyWhPerDay` comme une garantie ; ce champ-ci doit se lire pareil. +- **Mots bannis dans le code, le contrat et l'app : « garanti », « prioritaire ».** Y compris + dans les commentaires — c'est là que les promesses se réintroduisent. + +**Ce qui dit le résultat, c'est le motif, pas le nom.** `ECO_FLOOR_GRID` chiffre ce qui est +acheté ; `DRAW_CAP` nomme le plafond qui a empêché. Le nom déclare l'intention, le motif rapporte +les faits — et c'est la séparation qu'on tient partout ailleurs. + ## 6. Les étapes, à comportement constant d'abord **Étape A — corriger le contrat.** Les trois descriptions ci-dessus, plus la note sur `MinCurrent` qui nomme l'exigence de la borne. **Aucun code.** Comportement constant par construction, et c'est le pas qui rend la suite lisible. -**Étape B — porter `guaranteedPowerW` dans `LoadNeeds`, le persister, le publier**, sans que la +**Étape B — porter `minPowerWAlways` dans `LoadNeeds`, le persister, le publier**, sans que la passe éco s'en serve. Aller-retour `Get`/`SetLoadConfig`, schéma déclaré une fois. Comportement constant : le champ existe et ne décide de rien. **Étape C — la passe éco le prend en compte.** Le seul pas qui change le comportement, et il arrive quand tout le reste est déjà en place et vérifiable. Avec les quatre invariants du §4, le -motif enrichi, et le `DRAW_CAP` qui nomme la garantie. +motif enrichi, et le `DRAW_CAP` qui nomme le minimum. **Étape D — le mode s'y branche.** `ChargingModeEcoWithMinCurrent` posé sur une borne écrit -`guaranteedPowerW = plancher de la borne`. C'est le pas qui rend la promesse du nom vraie — et il +`minPowerWAlways = plancher de la borne`. C'est le pas qui rend le mode opérant — et il vient en dernier, parce qu'il n'a de sens qu'une fois C livrée. ## 7. Ce qu'on ne saura pas prouver au banc, et il faut le dire -L'installation de `.75` produit **2 kWc** contre un plancher de borne triphasée à **4 140 W**. Une -garantie sur cette borne serait donc **toujours** financée au réseau, jamais au surplus — le banc -ne peut pas exercer le cas mixte, celui où la garantie complète un surplus partiel. +L'installation de `.75` produit **2 kWc** contre un plancher de borne triphasée à **4 140 W**. Un +minimum sur cette borne serait donc **toujours** financé au réseau, jamais au surplus — le banc +ne peut pas exercer le cas mixte, celui où le minimum complète un surplus partiel. Il l'exercera en revanche très bien sur une charge en watts — le chauffe-eau — dès qu'elle aura un compteur réel (`TEST_TERRAIN.md` §12). **C'est la même précondition que pour l'étape 4 de la