docs: la journée de reporting suit l'installation — et l'app prend celle du téléphone

+etm55 vérifié (posé le 04/09 18:21:08). Le taux constant est en ligne : la
maquette porte le bon chiffrage — ×4,75 sur une fenêtre quotidienne, facteur
ln(T·P/E) + 1 — et les deux interdits du régime `unmeasurable` : ni annoncer que
l'achat va s'intensifier, ni lire `atMaximum: false` comme « tout va bien », qui
signifie qu'il n'y a aucun étalement, donc rien qui puisse cesser.

La troisième nature d'heure murale touche du code livré : `fetchDailyBalance()`
et la baseline des ratios prennent minuit du TÉLÉPHONE, alors qu'une journée de
reporting suit l'installation. Sur `.75` en Europe/London vue d'un téléphone
français, entre minuit et 1 h l'app compte une journée que la box compte encore
dans la précédente.

L'app ne peut pas le corriger seule : `System.GetTime` publie un nom IANA, et un
décalage ne s'en déduit pas sans base de fuseaux — qu'il faudrait embarquer pour
recalculer une frontière que la box connaît, et qui resterait fausse les jours de
changement d'heure. Demandé au moteur : publier le DÉBUT de la journée de
reporting en cours, en epoch, à côté du fuseau. La divergence est écrite aux deux
endroits du code en attendant.

Noté sans conclure : le banc n'a aucune charge `unmeasurable`, donc la loi est
déployée mais pas exerçable de bout en bout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
This commit is contained in:
Patrick Schurig 2026-09-05 07:40:26 +02:00
parent 0524e5f7cd
commit cd8dd02989
4 changed files with 77 additions and 9 deletions

View File

@ -2,6 +2,48 @@
---
## 2026-09-05 — le début de journée doit être PUBLIÉ, pas recalculé
`+etm55` vérifié sur la box (posé le 04/09 à 18:21:08). Le taux constant est en ligne, la maquette
porte le bon chiffrage — **×4,75** sur une fenêtre quotidienne, `ln(T·P/E) + 1` — et les deux
interdits sont écrits à côté : sous `unmeasurable`, l'écran ne dira ni que l'achat va s'intensifier,
ni que `atMaximum: false` signifie que tout va bien. Il signifie qu'il n'y a **aucun étalement**,
donc rien qui puisse cesser.
### Votre troisième nature d'heure touche du code déjà livré, et il ne peut pas se corriger seul
La journée de reporting suit l'installation — d'accord, et c'est bien la bonne réponse. Mais nos
deux calculs journaliers prennent **minuit du téléphone** : `fetchDailyBalance()` par
`DateTime(y, m, d)`, et la baseline des ratios par un index de jour local. Sur `.75` en
`Europe/London` vue d'un téléphone français, **entre minuit et 1 h l'app compte une journée que la
box compte encore dans la précédente.**
**Et l'app ne peut pas le corriger avec ce qui est publié.** `System.GetTime` donne le fuseau par
**nom IANA** ; un décalage ne s'en déduit pas sans base de données de fuseaux. Embarquer cette base
pour recalculer une frontière que la box connaît déjà serait le mauvais geste — et il resterait
faux les jours de changement d'heure, où la journée fait 23 ou 25 heures.
**Ce qu'on demande, et c'est un champ** : le **début de la journée de reporting en cours**, en
epoch, publié à côté du fuseau. L'app soustrait alors deux points de log sur la bonne fenêtre sans
rien dériver. C'est la même règle que `counts` a réglée pour les compteurs : *publier la frontière,
ne pas la faire recalculer par chaque client* — trois clients la recalculeraient de trois façons,
et la seule qui compte est la vôtre.
> Un décalage UTC seul suffirait presque, mais pas les jours de bascule. Le début de journée, lui,
> est juste par construction.
D'ici là la divergence est **écrite dans le code**, aux deux endroits, pour que personne ne lise
« minuit du téléphone » comme un choix — et elle est bornée à une heure sur ce banc.
### Noté sans conclure
Le banc n'a aucune charge `unmeasurable` : la loi du taux constant est déployée mais pas exerçable
de bout en bout, et elle tient sur votre test unitaire et sa contre-épreuve. **Je ne conclurai donc
rien de son absence à l'écran** — c'est encore l'homogénéité du banc, et c'est exactement le cas
où une mesure manquante ressemble à une mesure réussie.
---
## 2026-09-04 (soir) — deux natures d'heure murale : c'est une règle de STOCKAGE, pas d'affichage
La décision « publier le fuseau, ni imposer ni déclarer forfait » est prise, et le `Changed` avec —

View File

@ -342,8 +342,8 @@
<span>Avancement <em>non mesurable</em> : cette borne ne publie pas d'énergie de session.
<span class="pill nm">NON MESURABLE</span></span>
<div class="bar dash"></div>
<span><b>Reste 4,0 kWh à livrer en 5 h 13</b> — et ce taux ne peut que <b>monter</b> : rien
n'est soustrait de ce qui reste, donc l'achat s'accélère jusqu'à l'échéance.</span>
<span><b>Reste 4,0 kWh à livrer</b> — taux <b>constant</b> (cible ÷ jour), il ne montera
pas et ne baissera pas : sans mesure, rien ne peut le corriger.</span>
<span>L'obligation est servie ; elle ne pourra jamais être annoncée <em>tenue</em>.</span>
</div>
</div>
@ -431,11 +431,16 @@
« 12:00 » vaut 13:00 sur une horloge française. Le fuseau se lit par
<code>System.GetTime</code> : l'écran l'affiche à côté du champ et signale la divergence,
plutôt que de choisir une horloge à la place de l'installateur.</li>
<li><b>Sous <code>unmeasurable</code>, le plancher ne peut pas se refermer</b> — mesuré le
2026-09-01 sur quatre cycles : <code>remainingWh</code> figé à 4 000, <code>remainingS</code> qui
descend, <code>gridW</code> qui monte 755 → 767. Ce n'est pas un cas limite, c'est la
<b>trajectoire garantie</b> du régime : l'écran doit montrer <em>reste</em> et <em>temps</em>, pas
seulement les watts de l'instant, sans quoi « 767 W achetés » ne laisse pas deviner le mur.</li>
<li><b>Sous <code>unmeasurable</code>, le taux est CONSTANT depuis <code>+etm55</code></b> —
cible ÷ <b>jour</b>, la fenêtre étant l'unité de la grandeur déclarée et non un réglage
(LM-1013-b-v). Le total acheté vaut alors exactement la cible. L'escalade mesurée le
2026-09-01 (<code>gridW</code> 755 → 767, <code>remainingWh</code> figé) achetait
<b>×4,75</b> l'obligation sur une fenêtre quotidienne — le facteur suit
<code>ln(T·P/E) + 1</code>, donc il grandit avec la fenêtre : une échéance lointaine coûtait
<em>plus</em>, l'inverse de l'intuition.
<br><b>Deux choses que l'écran ne peut donc plus dire</b> sous ce régime : ni que l'achat va
s'intensifier, ni que <code>atMaximum: false</code> veut dire que tout va bien — il veut dire
qu'il n'y a <b>aucun étalement</b>, donc rien qui puisse cesser.</li>
<li><b>* « Commandé, pas encore mesuré » — et ce n'est pas une destination.</b> Le champ
<code>budget.evReservedW</code> est un <b>terme de correction</b> : la latence entre l'ordre et sa
lecture au compteur. Il est affiché parce que la box le publie, <b>jamais sommé</b>. Son ancien

View File

@ -25,6 +25,12 @@ class EnergyRatios {
/// ```
class EnergyRatiosInterim {
// Baseline = cumuls au début de la période courante (minuit local / reseed).
//
// ⚠️ « local » = fuseau du TÉLÉPHONE, et une journée de reporting devrait suivre
// l'INSTALLATION (cf. `NymeaService.fetchDailyBalance`). Sur une box en `Europe/London`
// vue d'un téléphone français, la bascule de jour arrive une heure trop tôt. La cible
// Phase 2 — lire UN state de l'energymanager — fait disparaître le problème avec le
// calcul ; d'ici là, la divergence est connue et écrite.
double? _baseProduction;
double? _baseReturn;
double? _baseConsumption;

View File

@ -1001,8 +1001,23 @@ class NymeaService extends ChangeNotifier {
///
/// 1. **Minuit LOCAL, et via les logs.** `GetPowerBalance` ne rend que des totaux depuis
/// l'origine : il ne sait rien dire d'une journée. Seul `GetPowerBalanceLogs` permet
/// de prendre deux points et de les soustraire. `DateTime(y, m, d)` donne bien minuit
/// dans le fuseau du téléphone — pas UTC.
/// de prendre deux points et de les soustraire. `DateTime(y, m, d)` donne minuit dans
/// le fuseau **du téléphone** — pas UTC.
///
/// ⚠️ **Et c'est justement le fuseau qu'il ne faudrait PAS prendre.** Une journée de
/// reporting suit **l'installation**, pas l'appareil qui regarde : c'est la troisième
/// nature d'heure murale, ni habitude client ni calendrier fournisseur (`CLAUDE.md`,
/// « Échéances »). Sur `.75`, en `Europe/London`, les taux journaliers de la box se
/// remettent à zéro à **01:00 heure française** — donc entre minuit et 1 h, cette méthode
/// compte une journée que la box compte encore dans la précédente.
///
/// La correction ne peut pas se faire ici : le fuseau de la box est publié par nom IANA
/// (`System.GetTime`), et un décalage ne s'en **déduit pas** sans base de données de
/// fuseaux. Embarquer cette base pour recalculer une frontière que la box connaît déjà
/// serait le mauvais geste — c'est le **début de journée** qui doit être publié. Demandé
/// dans `docs/BRIEF_plugin_depuis_maquettes.md`. D'ici là, la divergence est **connue et
/// bornée à une heure sur ce banc**, et elle est écrite ici pour que personne ne lise
/// « minuit du téléphone » comme un choix.
/// 2. **Les entrées de log ne portent PAS le préfixe `currentPower`.** Elles s'appellent
/// `production`, `consumption`, `acquisition`, `storage`, à la différence de
/// `GetPowerBalance`. Se tromper de clés ne produit **aucune erreur** : tout tombe sur