LA QUESTION QUE NI L'UN NI L'AUTRE N'AVAIT POSÉE : que fait la dérogation ENTRE le figement de sessionEnergy et l'échéance de durée ? Elle achète au maximum sur une mesure morte, et sur un lien qui perd 40 % de ses trames « au bout » peut vouloir dire des heures. POSITION RETENUE : une dérogation dont la cible cesse d'être mesurable CESSE. Elle n'attend pas sa durée. C'est R6 transposée — là-bas « servie oui, tenue jamais » ; ici « active oui, vérifiable non, donc on s'arrête ». Une dérogation est une commande qui ACHÈTE, et la maintenir sans savoir où elle en est, c'est acheter à l'aveugle. L'instrument existe déjà : measurement.source et le régime de LM-1009, qui le disent au cycle même. QUATRE FINS, et le motif dit laquelle a mordu : targetReached, unplugged, measurementLost, durationElapsed. Les quatre appellent des gestes différents — et une dérogation qui se terminerait sans dire laquelle laisserait l'utilisateur relancer un boost que le lien empêchera encore. L'ASYMÉTRIE, reprise du plugin V2C. La confirmation de débranchement existe (k_absencesPourClore polls) et porte une propriété qu'il faut garder : SEULS LES POLLS RÉUSSIS font avancer le compteur d'absences. Une coupure réseau le gèle au lieu de le faire progresser — un lien mort ne peut donc pas fabriquer un faux débranchement. Et les deux erreurs ne coûtent pas la même chose : terminer à tort rend la main, continuer à tort achète au maximum sur une mesure morte. D'où la règle, gravée dans AGENTS.md : un mécanisme qui achète s'arrête dans le doute, et ses seuils de confirmation sont asymétriques par conception — prompts à conclure la fin, lents à conclure la poursuite. C'est l'inverse du réglage qu'on choisirait pour un mode. La durée devient le FILET DU FILET : la perte de mesure attrape le cas où l'instrument se tait et se signale ; la durée attrape le cas où même le régime ne se signale pas. Deux filets parce que le premier repose lui-même sur un instrument.
215 lines
11 KiB
Markdown
215 lines
11 KiB
Markdown
# Dérogations — le boost n'est pas un mode
|
||
|
||
> Ouvert le 2026-09-07. **Design avant code, rien d'implémenté.**
|
||
> Cadrage donné par Patrick, et il vaut au-delà du VE.
|
||
|
||
## 1. La distinction qui structure tout le lot
|
||
|
||
| | mode | **dérogation** |
|
||
|---|---|---|
|
||
| se choisit | **une fois** | pour un **besoin ponctuel** |
|
||
| vaut | jusqu'au prochain choix | **jusqu'à ce que le besoin cesse** |
|
||
| se termine | jamais tout seul | **toujours tout seul** |
|
||
|
||
> **Un boost encore actif après la fin est un mode qu'on a oublié de quitter. Un boost qui rend
|
||
> la main est une dérogation terminée.**
|
||
|
||
C'est le même geste que forcer un chauffe-eau parce qu'on veut plus d'eau chaude : on ne
|
||
reconfigure pas l'installation, on demande quelque chose **maintenant**.
|
||
|
||
**Conséquence de conception** : ce n'est ni un `ChargingMode` de plus, ni une demande dans
|
||
`needs`. Une dérogation se **superpose** au mode courant et s'efface. Elle n'a ni cible d'énergie,
|
||
ni échéance, ni cadence — les trois supposent un besoin qui dure.
|
||
|
||
## 2. Ce qui la borne : la sûreté, et rien d'autre
|
||
|
||
Les trois comportements se distinguent par **ce qui les borne** :
|
||
|
||
| | borné par |
|
||
|---|---|
|
||
| PV | le **surplus** |
|
||
| Min+PV | un **plancher** + le surplus |
|
||
| **Boost** | la **sûreté seule** — `DRAW_CAP` et le délestage |
|
||
|
||
Et c'est cette dernière ligne qui le rend sûr : les plafonds deviennent la seule limite, **donc
|
||
une limite obligatoire**. Un boost sur un branchement 3×30 A sans `phasePowerLimit` ferait
|
||
disjoncter — ce n'est plus une hypothèse depuis le 2026-09-07, où l'on a découvert des semaines
|
||
de fonctionnement à `0`.
|
||
|
||
**Le boost prend la tête de la passe éco ; il ne surplombe pas la sûreté.** Si `DRAW_CAP` mord, il
|
||
est servi le premier **dans ce qui reste**, pas au-delà. Sans cette précision on retomberait sur
|
||
le second chemin d'achat refusé pour le minimum (`DESIGN_MIN_RESEAU.md` §3).
|
||
|
||
### Le rang
|
||
|
||
Le boost passe **devant**, y compris devant une charge mieux rangée. `LM-1002` dit que le rang est
|
||
ce que l'**installateur** décide ; elle ne dit rien d'une **action ponctuelle de l'utilisateur**.
|
||
Prendre la tête ne contredit donc pas la règle : cela passe par une porte qu'elle ne ferme pas.
|
||
Un boost servi après une autre charge contredirait « tout de suite », qui est sa définition.
|
||
|
||
## 3. Précaution 1 — le mode précédent se MÉMORISE, il ne se déduit pas
|
||
|
||
À la fin de la dérogation, la charge revient **au mode qu'elle avait**, relu depuis ce qui a été
|
||
stocké au déclenchement. Min+PV redevient Min+PV, PV redevient PV.
|
||
|
||
**Revenir à un défaut serait un défaut.** Retomber sur `Normal` sortirait la borne de l'arbitrage
|
||
— l'inverse exact du but, et une dérogation qui laisse l'installation moins pilotée qu'avant.
|
||
C'est la même famille que le repli d'échéance qui réécrivait `EcoWithMinCurrent` en `Eco` :
|
||
un état détruit en silence par un mécanisme qui croyait bien faire.
|
||
|
||
## 4. Précaution 2 — « terminé » se définit PAR MÉCANISME
|
||
|
||
Le moteur ne peut pas deviner ce qui met fin à une dérogation : cela dépend de ce qu'on déroge.
|
||
|
||
| charge | fins possibles |
|
||
|---|---|
|
||
| borne VE | **débranchement**, **cible en ÉNERGIE** (`sessionEnergy`), durée |
|
||
| chauffe-eau | **température** atteinte (si sonde), durée |
|
||
| batterie | cible en énergie, durée |
|
||
|
||
### La cible se dit en ÉNERGIE, jamais en SOC — et ce n'est pas un pis-aller
|
||
|
||
**Il n'y a pas de communication véhicule**, et il n'y en aura pas : aucun plugin constructeur
|
||
n'est prévu, et une intégration cloud Skoda/VW serait contraire au **100 % local**, fragile, et
|
||
rafraîchie à la minute au mieux.
|
||
|
||
Mais surtout, l'énergie est la **bonne** grandeur, indépendamment de cette contrainte :
|
||
|
||
| | ce qu'il faut savoir pour l'affirmer |
|
||
|---|---|
|
||
| « 20 kWh puis tu t'arrêtes » | `sessionEnergy`, que le plugin V2C construit depuis le 2026-08-29 |
|
||
| « jusqu'à 80 % » | la **capacité**, l'**état de santé** et le **rendement** de charge |
|
||
|
||
C'est exactement ce que `LM-1009` a établi pour l'obligation éco : **on mesure de l'énergie parce
|
||
que c'est ce qu'on sait mesurer.** Un SoC demanderait trois inconnues pour dire la même chose en
|
||
moins sûr.
|
||
|
||
> **La fin par SOC ne figure donc pas dans ce design**, et son absence n'est pas un manque à
|
||
> combler plus tard : c'est une décision. L'écrire comme un manque aurait laissé quelqu'un
|
||
> l'ouvrir comme un lot.
|
||
|
||
### Et `sessionEnergy` a un silence connu, qui justifie le filet
|
||
|
||
`LM-1012-d`, mesuré sur la V2C le 2026-08-30 : à la **perte du lien**, `currentPower` tombe à 0
|
||
et les booléens à `false`, mais **`sessionEnergy` reste à sa dernière valeur**.
|
||
|
||
Une dérogation « 20 kWh puis stop » dont le compteur se fige à 12 kWh **n'atteindra jamais sa
|
||
cible**. Elle achèterait au maximum jusqu'à ce que quelqu'un s'en aperçoive — sauf que la durée
|
||
est là. Ce n'est pas un cas d'école : c'est le comportement documenté de la borne installée.
|
||
|
||
**Chaque mécanisme déclare ce qui termine sa dérogation.** C'est un ajout à `ILoadAdapter`, au
|
||
même titre que `commandSettleS()` : une propriété du mécanisme, pas une constante du moteur.
|
||
|
||
## 5. LA RÈGLE — une dérogation qui ne sait pas dire quand elle finit ne devrait pas exister
|
||
|
||
C'est la règle centrale du lot, et elle se teste.
|
||
|
||
Sur un chauffe-eau **sans sonde**, « jusqu'à ce que ce soit chaud » n'est **pas mesurable**. La
|
||
fin doit alors être une **durée**, explicitement — et **l'app doit le dire à la saisie**, au
|
||
moment où l'utilisateur croit demander une température.
|
||
|
||
C'est exactement le raisonnement de `progressMeasurable` : une capacité absente se **dit** à la
|
||
saisie, parce que l'écran de résultat parle trop tard. Une dérogation dont la fin n'est pas
|
||
observable est une dérogation qui ne finira pas.
|
||
|
||
### La question qui manquait : que fait-elle ENTRE le figement et l'échéance ?
|
||
|
||
La durée arrêtera la dérogation — **au bout**. Entre-temps, elle achète au maximum sur une mesure
|
||
morte. Sur un lien qui perd 40 % de ses trames, « au bout » peut vouloir dire des heures.
|
||
|
||
**Position retenue : une dérogation dont la cible cesse d'être MESURABLE cesse.** Elle n'attend
|
||
pas sa durée.
|
||
|
||
C'est `R6` transposée. Là-bas : *servie oui, tenue jamais* — on ne conclut pas « tenue » sur un
|
||
avancement qu'on ne mesure pas. Ici : **active oui, vérifiable non, donc on s'arrête.** Une
|
||
dérogation est une commande qui **achète** ; la maintenir sans pouvoir dire où elle en est, c'est
|
||
acheter à l'aveugle.
|
||
|
||
**Et l'instrument existe déjà** : `measurement.source` et le régime de `LM-1009`. Quand le régime
|
||
d'une charge en dérogation cesse d'être mesuré, la condition de fin est perdue — et cela se sait
|
||
au cycle même, pas au bout de la durée.
|
||
|
||
### QUATRE fins, et le motif dit laquelle a mordu
|
||
|
||
| fin | ce qu'elle dit à l'utilisateur | geste |
|
||
|---|---|---|
|
||
| `targetReached` | la cible en énergie est atteinte | aucun — c'est le succès |
|
||
| `unplugged` | le véhicule est parti | aucun |
|
||
| **`measurementLost`** | on ne sait plus où en est la charge | **regarder le lien / le compteur** |
|
||
| `durationElapsed` | le temps imparti est écoulé | relancer si besoin |
|
||
|
||
Les quatre appellent des gestes différents, et une dérogation qui se terminerait sans dire
|
||
laquelle a mordu laisserait l'utilisateur relancer un boost que le lien empêchera encore.
|
||
|
||
### L'asymétrie, et la règle qu'elle donne
|
||
|
||
Le débranchement peut **clignoter** sur cette borne. Le plugin V2C a déjà la parade —
|
||
`k_absencesPourClore` polls consécutifs avant de clore une session — et elle porte une propriété
|
||
qu'il faut reprendre : **seuls les polls RÉUSSIS font avancer le compteur.** Une coupure réseau
|
||
le **gèle**, elle ne le fait pas progresser. Un lien mort ne peut donc pas fabriquer un faux
|
||
débranchement.
|
||
|
||
Cette confirmation vaut pour la dérogation aussi. Mais les deux erreurs ne coûtent pas la même
|
||
chose :
|
||
|
||
> **Terminer à tort** rend la main : la charge repasse à son mode mémorisé, et l'utilisateur
|
||
> relance s'il veut.
|
||
> **Continuer à tort** achète au maximum sur une mesure morte.
|
||
|
||
D'où la règle : **dans le doute, une dérogation s'arrête.** Les seuils de confirmation sont donc
|
||
asymétriques par conception — prompts à conclure la fin, lents à conclure la poursuite. C'est
|
||
l'inverse du réglage qu'on choisirait pour un mode, et c'est parce qu'une dérogation achète.
|
||
|
||
### Corollaire — la DURÉE est un filet, pas une option
|
||
|
||
Toute dérogation porte une durée maximale, **même quand elle a une meilleure condition de fin**.
|
||
|
||
Raison : la condition de fin repose sur un **instrument**, et un instrument peut se taire. Une
|
||
cible de charge qui ne remonte plus, une sonde qui tombe, un compteur qui se fige — et la
|
||
dérogation ne se termine jamais, en tirant le maximum. C'est « l'instrument dont le silence
|
||
ressemble à un résultat », appliqué à une commande qui achète.
|
||
|
||
**Donc : jamais « jusqu'à annulation ».** Quatre fins, et la durée est toujours l'une d'elles.
|
||
|
||
La durée est désormais **le filet du filet** : la perte de mesure attrape le cas où l'instrument
|
||
se tait ET se signale ; la durée attrape le cas où **même le régime ne se signale pas**. Deux
|
||
filets parce que le premier repose lui-même sur un instrument.
|
||
|
||
Cela rejoint ce que la maquette batterie demande pour son propre boost.
|
||
|
||
## 6. Ce que ça publie
|
||
|
||
Une dérogation active **se voit**, et sa fin **se lit** :
|
||
|
||
- un motif dédié, qui dit que la charge est en dérogation et **ce qui y mettra fin** ;
|
||
- l'instant de fin prévu, pour que l'écran affiche un compte à rebours plutôt qu'un état sans
|
||
horizon ;
|
||
- l'instant est **absolu, ancré à la capture** (`toUTC()`), jamais une heure murale — cf. la
|
||
dérive mesurée le 2026-09-06.
|
||
|
||
**Et la fin est un ÉVÉNEMENT**, publié le cycle où elle survient. Sans lui, l'écran ne peut pas
|
||
distinguer « la dérogation s'est terminée normalement » de « quelqu'un l'a annulée ».
|
||
|
||
## 7. Étapes, à comportement constant d'abord
|
||
|
||
**A** — le type et sa publication, sans qu'aucune dérogation ne puisse être posée. Le champ
|
||
existe, il ne décide de rien.
|
||
**B** — la déclaration des fins par mécanisme (`ILoadAdapter`), avec la durée obligatoire.
|
||
**C** — la pose, la mémorisation du mode précédent, et le retour automatique.
|
||
**D** — le service en tête de passe éco, borné par `DRAW_CAP` et le délestage.
|
||
|
||
Le pas **D** est le seul qui change ce qui est commandé, et il arrive quand tout le reste est
|
||
déjà vérifiable.
|
||
|
||
## 8. Ce que le banc ne prouvera pas
|
||
|
||
**Les trois fins du VE sont exerçables sans véhicule communicant** : débranchement, cible en
|
||
énergie via `sessionEnergy`, et durée. C'est ce qui rend ce lot éprouvable sur le banc réel, là
|
||
où une fin par SoC ne l'aurait jamais été.
|
||
|
||
Reste hors de portée : la fin par **température**, qui demande la sonde du §12 — elle n'existe
|
||
qu'en mock, et c'est le sixième manque de `INVENTAIRE_MOCK.md` sous un autre angle.
|
||
|
||
**La durée, elle, s'éprouve partout** — une raison de plus d'en faire le filet plutôt qu'un
|
||
recours.
|