etm-powersync-energy-plugin.../docs/DESIGN_MIN_GARANTI.md
Patrick Schurig b5efcc6357 docs: design du minimum garanti — option 2, avec le renommage
Design avant code, comme pour le délestage et le §10. Rien d'implémenté.

LE CONSTAT EST DOUBLE. Le mode n'a jamais eu de minimum garanti — mort par
réécriture chez l'amont, puis mort par exclusion depuis 3g-2 (DESIGN_3g §5). Et
son nom promet l'inverse : `MinCurrent` désigne L'EXIGENCE DE LA BORNE, les 6 A
sous lesquels elle refuse de charger, pas une garantie du mode. Trois modes
annoncés, deux implémentés, et celui qui manque est celui que l'utilisateur
croyait utiliser — le défaut n'est pas qu'une fonction manque, c'est qu'elle est
annoncée.

POURQUOI MAINTENANT, sans attendre le prix. Rachat à 0,01 € : charger 30 % au
réseau en journée revient à 0,073 €/kWh contre 0,180 € la nuit. Sur la majorité du
parc neuf, aucun arbitrage n'est nécessaire pour savoir que c'est le bon choix. 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. L'option 3 reste
l'horizon ; elle choisira S'IL FAUT garantir, pas COMMENT.

CONDITION 1 — machinerie du §10 : passe éco, borné par DrawCap, funding Grid,
motif qui dit combien est acheté. Exclut explicitement EV_GRID_START, dont les
trois bornes dérivent du surplus et qui achète hors du registre d'autorisation.

CONDITION 2 — un champ de plus DANS needs, frère de minEnergyWhPerDay, pas une
structure parallèle : `guaranteedPowerW`. À ne pas confondre avec minPowerW
(LM-1201) : le premier borne une consigne SI on sert, le second en crée une
TOUJOURS. La passe éco rend max(cadenceObligation, guaranteedPowerW), avec quatre
invariants — la garantie ne se tient jamais (donc watts retombe sur elle quand
l'obligation est tenue, pas sur zéro) ; progress ne décrit que l'obligation et est
ABSENT sur une garantie seule ; le motif dit lequel des deux mord ; une garantie
non honorée se dit par DRAW_CAP qui la nomme.

CONDITION 3 — le fil ne peut pas être renommé sans casser les clients déployés.
Ce qui se corrige est la DESCRIPTION au contrat, d'où l'app tire ses libellés.
ChargingModeNormal n'est pas « recharge immédiate au maximum » : c'est MANUEL, la
borne sort de l'arbitrage et le moteur ne commande rien — seule la protection de
surcharge la touche encore, ce qui doit rester et doit être dit.

QUATRE ÉTAPES, à comportement constant d'abord : corriger le contrat (aucun code),
porter et publier le champ sans s'en servir, la passe éco le prend en compte, puis
le mode s'y branche.

ET CE QU'ON NE SAURA PAS PROUVER AU BANC : 2 kWc contre un plancher de 4 140 W,
donc une garantie toujours financée au réseau et jamais le cas mixte. Le
chauffe-eau l'exercera dès qu'il aura un compteur réel — quatrième nomination de
la même précondition.
2026-09-06 14:51:35 +02:00

7.8 KiB

Minimum garanti — design

Ouvert le 2026-09-06. Option 2 retenue : livrer le minimum garanti 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 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.

Et son nom promet l'inverse de ce qu'il fait. MinCurrent désigne l'exigence de la borne — les 6 A en dessous desquels elle refuse de charger — pas une garantie du mode. Un lecteur y voit « le mode maintient un courant minimum » ; le code, lui, ne fait que nommer un seuil matériel.

Trois modes annoncés, deux implémentés — et celui qui manque est celui que l'utilisateur croyait utiliser. C'est la formulation à retenir : le défaut n'est pas qu'une fonction manque, c'est qu'elle est annoncée.

2. Pourquoi livrer le minimum maintenant, sans attendre le prix

Chiffrage retenu, tarif de rachat récent à 0,01 €/kWh :

coût effectif
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 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.

Conclusion de conception : l'option 3 (comparer deux scénarios au prix) est le bon horizon, mais elle exige une source tarifaire et une prévision. L'option 2 livre l'utile aujourd'hui, et elle ne ferme pas la porte : un arbitrage au prix choisira plus tard s'il faut garantir, pas comment garantir.

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à :

  • borné par l'autorisation de soutirage (DrawCap / DrawMargin, trois sources) — comme tout achat ;
  • funding: Grid quand le surplus ne couvre pas ;
  • le motif dit combien est acheté, comme ECO_FLOOR_GRID le fait déjà.

Ce que cela EXCLUT explicitement : porter le minimum par EV_GRID_START. Ses trois bornes dérivent toutes du surplus (budgetW > 0, seuil proportionnel, consommation de tout le budget) ; un minimum permanent en est indépendant par définition, donc les lever revient à créer le second mécanisme. Et EV_GRID_START achète hors du registre d'autorisation — deux mécanismes dont un seul est borné, et c'est le second qui ferait disjoncter. Raisonnement complet dans DESIGN_3g.md §5.4.

4. Condition 2 — une puissance permanente, portée sans dupliquer needs

Le champ

Un champ de plus dans needs, frère de minEnergyWhPerDay — pas une structure parallèle :

needs : {
  minEnergyWhPerDay : Uint,   // énergie, avec échéance
  dailyDeadline     : String,
  guaranteedPowerW  : Uint    // NOUVEAU — puissance, permanente
}

À ne pas confondre avec minPowerW (LM-1201), et la différence est de nature :

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.

Le premier borne une consigne ; le second en crée une. Les deux peuvent coexister sur la même charge sans se contredire.

La composition dans la passe éco

computeEcoTarget() rend aujourd'hui une cadence dérivée de l'obligation en énergie. Elle rendra le maximum des deux :

watts = max( cadenceObligation , guaranteedPowerW )

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 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 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.

5. Condition 3 — nommer les trois modes pour ce qu'ils font

Le fil ne peut pas être renommé : ChargingMode est une énumération publiée, et changer ses identifiants casserait tout client déployé. Ce qui se corrige, c'est la description au contrat — c'est là que vit le mensonge, et c'est de là que l'app tire ses libellés.

valeur ce que le contrat dit AUJOURD'HUI ce que le code FAIT
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

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.

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 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.

É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 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.

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 commande perdue, et elle est maintenant nommée par un quatrième chemin.