docs(spec §10): LM-1009 — les trois arbitrages tranchés, et deux conditions de livraison

Décisions de Patrick, écrites dans la spec et portées à l'agent app qui avait
remonté la question.

D1 — l'avancement s'affiche en ÉNERGIE LIVRÉE, jamais en pourcentage. « 8,4 kWh
livrés depuis le branchement » est vérifiable ; « 62 % » suppose une capacité
que personne ne connaît et se lit comme une lecture du véhicule. Le pourcentage
reste dans la saisie de l'intention, il sort de l'affichage de l'avancement.

D2 — obligation par SESSION d'abord. Elle ne demande que de lire un champ déjà
publié, c'est l'usage réel (on branche le soir pour partir le matin), et surtout
la remise à zéro de sessionEnergy au branchement CESSE d'être une réserve : pour
une obligation de session, c'est la bonne sémantique. Le texte est réécrit en
conséquence — le problème disparaît au lieu d'être contourné. L'obligation
quotidienne devient un lot à part, dépendant de l'historique du §11.

D3 — tant que le chemin carBatteryLevel survit, il est étiqueté à la
publication. Une valeur que le moteur a lui-même intégrée ne franchit pas la
frontière RPC sous le même nom qu'une mesure. Précédent de nommage déjà dans ce
document (estimatedPowerW), et même refus que le currentPowerStorage à zéro du
relevé 3g-1 : mieux vaut « estimé », ou rien, qu'un chiffre crédible et faux.

Les deux réserves deviennent des CONDITIONS DE LIVRAISON, pas des notes — ce
sont les deux façons dont le §10 peut mentir sans erreur visible :

  C1 — une borne sans sessionEnergy dégrade VISIBLEMENT. Mesuré : wallboxNoMeter
  et l'une des deux classes wallbox ne l'ont pas. Une échéance qui cesse
  silencieusement d'être mesurable est pire qu'une échéance absente, parce
  qu'elle continue de s'afficher. Et « pas mesurable » n'est pas « rien livré ».
  C2 — on doit pouvoir dire LEQUEL des deux régimes s'applique, dans le motif
  comme à l'écran. Un avancement mesuré et un avancement estimé ne se
  distinguent par aucune de leurs valeurs : les deux sont un nombre qui monte.

La distinction des deux régimes est conservée telle quelle : une obligation en
énergie peut annoncer son atteinte, une cible en pourcentage publie une
intention et un avancement estimé — jamais « tenue ».

Le brief app gagne un cinquième point : c'est celui qui change un écran.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017TVywtayEeoRJ2yWUW4iZj
This commit is contained in:
Patrick Schurig 2026-08-27 14:49:55 +02:00
parent d3013672a2
commit 9c4862eab0

View File

@ -727,15 +727,12 @@ annonçait.
véhicule en reçoit moins. Ce n'est pas un défaut de la mesure — c'est le bon côté du compteur
pour une **obligation d'énergie** : celui qu'on paie. Mais la promesse doit se formuler
« livrer X kWh », jamais « mettre X kWh dans la batterie ».
2. **`sessionEnergy` se remet à zéro au branchement.** Parfait pour une obligation *par session*,
**inutilisable tel quel** pour un `minEnergyWhPerDay` : débrancher et rebrancher relance le
compteur, et l'obligation du jour se croirait à zéro. L'accumulation entre sessions est un
mécanisme distinct, et sa place naturelle est l'historique du §11.
3. **Toutes les bornes ne la publient pas** — mesuré : `wallboxNoMeter` et l'une des deux classes
`wallbox` ne l'ont pas. La dégradation doit être **VISIBLE** : une échéance qui cesse
silencieusement d'être mesurable est pire qu'une échéance absente, parce qu'elle continue de
s'afficher. Même exigence que `hasPowerMeter()`, qui est déjà testé avant d'estimer un SoC.
4. **Elle ne répondra JAMAIS à « la voiture sera-t-elle pleine ? »** Aucune énergie livrée ne dit
2. **`sessionEnergy` est une grandeur de SESSION** : elle se remet à zéro au branchement. Ce
n'est une réserve que si l'on vise une obligation *quotidienne* — et la décision D2 ci-dessous
ne la vise pas. Pour une obligation *par session*, la remise à zéro n'est pas un obstacle
contourné : c'est **exactement la bonne sémantique**, et le problème disparaît au lieu d'être
traité.
3. **Elle ne répondra JAMAIS à « la voiture sera-t-elle pleine ? »** Aucune énergie livrée ne dit
où en est une batterie dont on ne connaît ni l'état de départ ni la capacité réelle. Une cible
en énergie est vérifiable ; une cible en pourcentage ne l'est pas. Ce sont **deux objets
différents**, et le §10 ne doit pas les confondre sous le mot « échéance ».
@ -759,15 +756,45 @@ l'être. C'est la même exigence que celle qui sépare `BELOW_MIN_POWER` de `SUR
qu'elles n'appellent pas le même geste. Ici le geste diffère radicalement — « attends, ça
charge » contre « je ne peux pas savoir où tu en es ».
> **Ce que cette note NE tranche pas**, et qui demande une décision :
> — l'app garde-t-elle un écran en pourcentage, alimenté par l'estimation clairement étiquetée,
> ou bascule-t-elle en énergie livrée, qui est la seule chose que la box sait prouver ?
> — `minEnergyWhPerDay` exige-t-il l'accumulation inter-sessions du §11, ou le §10 se limite-t-il
> d'abord à une obligation **par session**, qui ne demande rien de plus que de lire un champ
> déjà publié ?
>
> La seconde est le vrai arbitrage de lot : l'obligation par session est faisable avec
> `sessionEnergy` seul, l'obligation quotidienne demande un historique.
### DÉCISIONS *(Patrick, 2026-08-27)*
**D1 — L'avancement s'affiche en ÉNERGIE LIVRÉE, jamais en pourcentage.** « 8,4 kWh livrés depuis
le branchement » est vérifiable ; « 62 % » suppose une capacité que personne ne connaît et **se
lira comme une lecture du véhicule**. Le pourcentage garde sa place dans la **saisie de
l'intention** — l'utilisateur pense sa voiture en pourcentage — mais **jamais dans l'affichage de
l'avancement**.
**D2 — Obligation par SESSION d'abord.** Le §10 lit `sessionEnergy` et s'arrête là. Trois raisons
qui vont dans le même sens : elle ne demande que de lire un champ **déjà publié** ; la remise à
zéro au branchement cesse d'être une réserve (voir ci-dessus) ; et c'est **l'usage réel** — on
branche le soir pour partir le matin. L'accumulation inter-sessions est un **lot à part**,
dépendant de l'historique du §11, et `minEnergyWhPerDay` ne sera honoré qu'avec lui.
**D3 — Tant que le chemin `carBatteryLevel` survit, il est ÉTIQUETÉ à la publication.** Une valeur
que le moteur a lui-même intégrée ne franchit pas la frontière RPC **sous le même nom qu'une
mesure**. Le précédent de nommage existe déjà dans ce document : `estimatedPowerW` porte
volontairement son préfixe (§3), parce qu'un nom doit porter le statut épistémique de ce qu'il
transporte. C'est aussi le refus opposé au `currentPowerStorage` à zéro du relevé 3g-1 : **mieux
vaut « estimé », ou rien, qu'un chiffre crédible et faux** — et c'est le corollaire de forme
d'`AGENTS.md` invariant 12, « un champ absent vaut mieux qu'un champ nul ou forgé ».
### CONDITIONS DE LIVRAISON — pas des recommandations
Elles s'écrivent avec le mécanisme, pas après. Ce sont les deux façons dont ce §10 peut mentir
sans erreur visible.
**C1 — Une borne qui ne publie pas `sessionEnergy` DÉGRADE VISIBLEMENT.** Mesuré sur le banc :
`wallboxNoMeter` et l'une des deux classes `wallbox` n'ont pas cet état. Sur ces bornes,
l'obligation n'est **pas mesurable** — et une échéance qui cesse silencieusement de l'être est
**pire qu'une échéance absente**, parce qu'elle continue de s'afficher comme si elle tenait. Le
moteur doit le dire, l'app doit le montrer, et la dégradation ne doit jamais se lire comme un
avancement nul. Même geste que `hasPowerMeter()`, déjà testé avant toute estimation de SoC.
**C2 — On doit pouvoir dire LEQUEL des deux régimes s'applique — dans le motif comme à l'écran.**
Un avancement mesuré et un avancement estimé ne se distinguent par aucune de leurs valeurs : les
deux sont un nombre qui monte. Si le régime ne se lit pas, le second se fait passer pour le
premier, et c'est précisément le défaut que cette note décrit. Le régime est donc une donnée
publiée, au même titre que la source d'un plafond en LM-1006-1 — **deux causes, deux phrases**.
---