Le contrat porte désormais la règle : tout horodatage publié est en UTC avec son
marqueur, ou en epoch. Trois champs, deux formats, rien ne l'exigeait.
`instantDeLaBox` (lib/models/box_instant.dart) devient l'unique lecteur pour ce
que la box publie — epoch ou ISO, marqué ou nu — et requalifie la forme nue en
UTC avant de rendre l'heure du lecteur. Politique valable pour la BOX seule :
`Installation.lastSeen` est écrite en local sans marqueur et relue pareil, donc
la lire en UTC la décalerait. Deux héritages opposés sous une même forme, d'où
l'absence délibérée d'un « parser une date » unique.
Le `.toLocal()` posé hier dans telemetry_text est retiré : le modèle est seul
propriétaire de la conversion. Le rejouer serait sans effet mais laisserait
croire qu'elle peut manquer ailleurs.
CORRECTION. J'avais écrit que le défaut avait survécu « parce que box et
téléphone partageaient l'heure ». C'est faux, et la fausseté est utile : l'écart
est entre UTC et l'APPAREIL, donc visible sur tout téléphone hors UTC+0 quel que
soit le fuseau de la box. Mesuré ce matin avec les deux en Europe/Paris — la box
publie 04:33:28Z, l'APK d'hier affiche « 04:33 », il fallait lire 06:33. La
bascule en Europe/London n'a pas donné la visibilité, elle a donné le MOTIF de
regarder. La version fausse fait conclure « les fuseaux coïncident, donc c'est
réglé » et laisse le défaut en place.
`GetVariableLoadState` n'existe pas sur .75 (absente d'Introspect) et l'app ne
lit aucun `since` : rien à corriger de ce côté. Le champ existe en revanche dans
GetLoadTelemetry — `loads[].command {divergent, expectedW, observedW, since}` —
et il porte bien le Z, vérifié à la sonde. Aucun écran ne le consomme encore.
Contrôle négatif de la ligne d'horloge : même binaire qu'hier, box repassée en
Europe/Paris, la ligne a disparu sous le champ d'échéance.
docs/captures/2026-09-07_fuseau-box-paris-ligne-absente.png
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
Europe/Berlin et Europe/Paris ne divergeront jamais : la ligne d'échéance restera
muette, et à raison — elle qualifie une horloge, et deux fuseaux au même décalage
donnent la même heure. Avertir parce que les NOMS diffèrent alors que les HEURES
coïncident serait le bruit que la condition existe pour éviter.
Mais une plage tarifaire suit le FOURNISSEUR, pas la box : « même décalage, autre
autorité » y reste une divergence réelle, et le jour où l'un des deux change de
règle d'heure d'été, la plage bouge sans que la box ait bougé. Le lot tarifaire
aura donc besoin d'une comparaison de provenance et d'un fuseau de référence
publié avec la configuration tarifaire.
Noté dans la doc du getter, là où quelqu'un ira le réutiliser.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
« 12:00 heure de la box (Europe/London) — pas celle de cet appareil », et non
« Fuseau : Europe/Paris » : sous un champ, un intitulé de réglage laisse croire
qu'on choisit le fuseau DE CETTE échéance. Il n'y en a qu'un, il est système, et
il déplace d'un coup toutes les heures murales de l'installation — échéances,
frontière de la journée de reporting, et demain les plages tarifaires
(LM-1005-b-iii).
Affichage CONDITIONNEL : seulement quand les deux horloges divergent. C'est la
règle déjà appliquée deux fois cette semaine — ligne des ratios instantanés,
avertissement « partiel » du bilan — et sa raison tient en une phrase : un texte
permanent cesse d'être lu le jour exact où il devient vrai.
La divergence se DÉDUIT de ce que la box publie, sans base de fuseaux :
`periodStartedAt` est minuit de l'installation en epoch, donc rendu dans le
fuseau de l'appareil il tombe sur 00:00 si et seulement si les deux partagent le
même décalage. Exact pour l'instant présent, y compris les jours à 23 ou 25
heures — et c'est justement pourquoi nous avions demandé cette frontière plutôt
qu'un nom IANA.
Quatre silences testés : fuseaux identiques, échéance vide, box qui ne publie pas
la date, et l'intitulé « Fuseau : » qui ne doit jamais apparaître.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
Sondé avant de câbler (`+etm56`) : `periodStartedAt` = 1788562800 = 00:00 Londres
= 01:00 Paris, `measuredSince` = 07:04 Londres, `timeZone` = Europe/London. Sept
heures d'écart entre les deux bornes.
- `EnergyRatiosSnapshot` — les deux instants et le fuseau. `baselineRepriseEnJournee`
dit quand les ratios de la box ne parlent que depuis un redémarrage : c'est le
silence que `measuredSince` existe pour fermer, et quand les deux coïncident —
le cas normal — il n'y a rien à dire de plus ;
- `fetchEnergyRatios()`, et `fetchDailyBalance()` qui prend désormais la frontière
publiée. Repli sur minuit local pour une box antérieure, écrit comme tel.
Et un effet de bord attrapé avant qu'il ne parte : `startsLate` comparait à minuit
du TÉLÉPHONE. Avec la frontière de la box, il aurait crié « partiel » tous les
jours sur un bilan complet — un avertissement permanent cesse d'être lu. Il se
compare maintenant à `periodStart`, porté par le bilan, et un test fige le piège.
Les taux journaliers de `DailyBalance` sont donc corrigés du même geste : ils se
calculent déjà par différence de compteurs sur la fenêtre, c'était la fenêtre qui
était fausse.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw