docs(recap): la journée du 2026-08-27 — et le mot qui manquait : JOURNALIER
RECAP.md porte les neuf commits du jour et les trois défauts que seul l'appareil a montrés : deux cibles tactiles hors norme (26 px, 18 px), et une correction naïve laide que le test validait — c'est la capture qui a tranché, pas l'assertion. Ce qui manquait dans le suivi, et qui est écrit noir sur blanc : AUCUN BILAN JOURNALIER N'EXISTE DANS L'APP. Les quatre tuiles du tableau de bord mêlent deux natures de grandeur, et aucune n'est journalière — Autoconsommation et Autonomie sont des pourcentages instantanés, Vers réseau et Depuis réseau des kWh cumulés depuis l'origine. Les deux dernières portaient « aujourd'hui » : totalReturn n'est pas remis à zéro chaque nuit, d'où le « · cumulé ». Le bilan du jour reste à écrire, et le TODO porte les trois pièges de sa mise en œuvre — bornes à minuit local, clés de log SANS le préfixe currentPower, et les cumulés corrompus de .75. Et la question ouverte au moteur, telle qu'elle s'est posée : « ECS d'abord, batterie ensuite » n'est pas exprimable aujourd'hui, et batteryLevelConsideration fait l'inverse — il annule le budget SOUS le seuil, donc la batterie passe avant. La cause est structurelle : la batterie n'est dans aucun GetLoadConfig et le plugin ne la commande nulle part. Le levier existe pourtant, la classe SunSpec Storage de .75 déclare enableCharging, chargingRate et enableDischarging. Deux entrées du TODO étaient devenues fausses : kCodesReserveBatterie est fait, et « Zones — à ne pas entreprendre » est revu puisque le lot est cadré. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016vrTVifar2GN5rtUh89Wkq
This commit is contained in:
parent
2701a9c0b3
commit
b60c74d2e4
102
RECAP.md
102
RECAP.md
@ -1,8 +1,104 @@
|
||||
# RECAP — etm-powersync-app · reprise de session
|
||||
|
||||
> **Session 2026-08-26.** Branche **`feature/beta-add-config`**, **poussée** (`801ba15`).
|
||||
> La journée du **26** est en tête ci-dessous ; la soirée du **25** (lot C) suit ; la section
|
||||
> « État au 2026-06-30 » plus bas reste valable pour tout ce qu'elle décrit.
|
||||
> **Session 2026-08-27.** Branche **`feature/beta-add-config`**, **39 commits d'avance,
|
||||
> NON POUSSÉS** — la forge est à terre (`192.168.1.113` injoignable, front public en 503).
|
||||
> Bundle de secours vérifié :
|
||||
> `~/bundles/etm-powersync-app_feature-beta-add-config_2026-08-27.bundle`.
|
||||
> La journée du **27** est en tête ; celle du 26 suit.
|
||||
|
||||
---
|
||||
|
||||
## Journée 2026-08-27 — deux lots moteur, le premier passage écran, et trois défauts trouvés
|
||||
|
||||
La box est passée de `+etm22` à `+etm24` dans la journée. Fil conducteur : **ce que l'app
|
||||
affiche doit avoir été dit par la box** — et ce qu'aucun test unitaire ne peut voir, seul
|
||||
l'appareil le montre.
|
||||
|
||||
| Commit | Contenu |
|
||||
|---|---|
|
||||
| `a145529` | **3g-1** — `BATTERY_RESERVE` branché, `funding` lu, l'état d'une borne passe devant |
|
||||
| `a92e9b2` | `SetChargingInfo` n'est PAS une écriture partielle — lire-patcher-réécrire |
|
||||
| `a44d64d` | **3g-2** — les bornes sont des charges configurées, une seule liste, un seul rang |
|
||||
| `24822ce` | **3g-2** — la mise en garde borne tombe, sans devenir une certitude trop large |
|
||||
| `f7fd91e` | Le SOC véhicule inventé disparaît — la grandeur n'existe pas |
|
||||
| `f33b8c2` | Le rapport de bug pré-rempli, repoussé depuis le premier jour |
|
||||
| `da0c87e` | Le harnais d'appareil, et le cadrage des zones de clim |
|
||||
| `01fdad7` | **Les cibles tactiles étaient à 26 px** — trouvé au premier passage sur appareil |
|
||||
| `2701a9c` | L'arbitrage descend en bas, et les blocs se replient |
|
||||
|
||||
### Les trois défauts que seul l'appareil a montrés
|
||||
|
||||
1. **La poignée de glissement mesurait 26 × 27 px** (minimum Material : 48). Le `Container`
|
||||
transparent posé la veille avait supprimé la *bande morte*, jamais agrandi la *cible* :
|
||||
le geste accrochait quand on visait juste et ratait sinon.
|
||||
2. **Les flèches de rang mesuraient 18 × 18 px** — la taille de l'icône, sans marge de
|
||||
touche.
|
||||
3. **La correction naïve était laide** : deux cibles de 44 px empilées font 88 px de haut
|
||||
pour deux icônes de 18, et la colonne de rang devenait une colonne vide. Le test disait
|
||||
« 44 px, c'est bon » ; c'est la **capture** qui a dit que c'était laid. Passées côte à
|
||||
côte.
|
||||
|
||||
Le harnais lui-même a demandé trois corrections avant de dire la vérité, et chacune se
|
||||
reproduira : il regardait le haut de l'écran (dans un `ListView`, ce qui n'est pas visible
|
||||
n'est pas construit) ; `find` trouve un widget **posé mais hors viewport** et `getCenter`
|
||||
en rend une coordonnée qui n'existe pas (mesuré y = 1129 sur un écran de 825 px) ; la
|
||||
course de glissement était devinée (~150) là où elle vaut **384 px mesurés**.
|
||||
|
||||
### Ce que le moteur a changé, et ce que l'app en a fait
|
||||
|
||||
- **`loads[] ⊆ GetLoadConfig` rétabli** : toute borne détectée reçoit une entrée
|
||||
`LoadConfig` (`.75` passe de 2 à 4). Aller-retour verbatim vérifié **neutre** sur machine.
|
||||
- **La mise en garde borne tombe** — mais *personne d'autre ne commande* n'est pas *la
|
||||
borne obéit*. `allocationIsCommand` est **supprimé** plutôt que mis à `true` partout : le
|
||||
garder inviterait à lire « commande » comme « réalité ».
|
||||
- **`EV_GRID_START` aurait cassé la réconciliation en silence.** C'est le seul motif dont
|
||||
l'allocation se PARTAGE entre les deux compteurs du budget ; filtrer sur
|
||||
`funding == "surplus"` le comptait zéro. Trouvé en lisant le brief plutôt que son résumé.
|
||||
- **Le rang par défaut d'une borne est un artefact** (trois charges à `priority = 1` sur le
|
||||
banc). L'écran le nomme au lieu de le présenter comme un classement.
|
||||
|
||||
### Ce qui a été RETIRÉ parce que c'était faux
|
||||
|
||||
- **Le SOC véhicule à 62 % en dur.** Vérifié sur les 58 classes de `.75` : aucune classe
|
||||
`evcharger` ne déclare d'état de charge. Le brief moteur a tranché ensuite, et c'est pire
|
||||
qu'une mesure manquante — `carBatteryLevel` est une valeur que **le moteur écrit
|
||||
lui-même**, publiée sous un nom de mesure. Décision LM-1009 : l'avancement s'affichera en
|
||||
**énergie livrée**, jamais en pourcentage.
|
||||
- **`BorneSection`** : les bornes ont désormais un rang et un domaine, la section les
|
||||
affichait une seconde fois en affirmant le contraire.
|
||||
- **Les deux flèches de domaine** : doublon de la poignée, désormais vérifiée au doigt.
|
||||
|
||||
### 🔴 Aucun bilan JOURNALIER n'existe dans l'app
|
||||
|
||||
Constaté en répondant à une question sur le tableau de bord. Les quatre tuiles sous le flux
|
||||
énergétique (`features/dashboard/widgets/kpi_row.dart`) mêlent **deux natures de grandeur**,
|
||||
et **aucune n'est journalière** :
|
||||
|
||||
| Tuile | Ce qu'elle montre RÉELLEMENT |
|
||||
|---|---|
|
||||
| Autoconsommation | **% instantané** |
|
||||
| Autonomie | **% instantané** |
|
||||
| Vers réseau · cumulé | **kWh cumulés depuis l'origine** |
|
||||
| Depuis réseau · cumulé | **kWh cumulés depuis l'origine** |
|
||||
|
||||
Les deux dernières portaient « aujourd'hui », et c'était faux : `totalReturn` n'est pas remis
|
||||
à zéro chaque nuit. Le libellé dit « · cumulé » depuis. **Le bilan du jour reste à faire** —
|
||||
il passe par `GetPowerBalanceLogs` avec des bornes à minuit local, jamais par les totaux de
|
||||
`GetPowerBalance`. Voir `TODO.md`.
|
||||
|
||||
### ❓ Question ouverte au moteur — « ECS d'abord, batterie ensuite »
|
||||
|
||||
Demandé par Patrick : que le surplus aille d'abord à l'eau chaude, et à la batterie
|
||||
seulement ensuite. **Ce n'est pas exprimable aujourd'hui**, et le réglage existant fait
|
||||
l'inverse : `batteryLevelConsideration` annule le budget *sous* le seuil, donc la batterie
|
||||
est prioritaire jusque-là. Le mettre à 0 ne donne pas la priorité à l'ECS — il retire
|
||||
seulement le blocage, et c'est l'onduleur qui arbitre.
|
||||
|
||||
La cause est structurelle : **la batterie n'est pas dans le waterfall**. Elle n'a aucune
|
||||
entrée `GetLoadConfig`, et `enableCharging` / `chargingRate` / `enableDischarging`
|
||||
n'apparaissent nulle part dans le plugin ETM. Le levier existe pourtant — la classe
|
||||
**SunSpec Storage** de `.75` déclare ces cinq actions. Question à porter au moteur : *le
|
||||
stockage est-il une charge arbitrable, ou reste-t-il hors du budget ?*
|
||||
|
||||
---
|
||||
|
||||
|
||||
62
TODO.md
62
TODO.md
@ -1,19 +1,69 @@
|
||||
# TODO — ETM PowerSync App
|
||||
|
||||
## Ouvert au 2026-08-27
|
||||
|
||||
- [ ] 🔴 **Bilan JOURNALIER — il n'en existe aucun dans l'app.** Les quatre tuiles du
|
||||
tableau de bord (`features/dashboard/widgets/kpi_row.dart`) mêlent deux natures de
|
||||
grandeur, et aucune n'est journalière : *Autoconsommation* et *Autonomie* sont des
|
||||
**pourcentages instantanés**, *Vers réseau* et *Depuis réseau* des **kWh cumulés depuis
|
||||
l'origine** — `totalReturn` / `totalAcquisition` ne sont pas remis à zéro chaque nuit.
|
||||
Le libellé disait « aujourd'hui » ; il porte « · cumulé » depuis, mais **le bilan du jour
|
||||
reste à écrire**.
|
||||
- il passe par `Energy.GetPowerBalanceLogs` avec des bornes à **minuit local**, jamais par
|
||||
les totaux de `GetPowerBalance` ;
|
||||
- piège vérifié : les entrées de log portent `production` / `consumption` / `acquisition`
|
||||
/ `storage`, **sans** le préfixe `currentPower` de `GetPowerBalance`. Réutiliser les
|
||||
mauvaises clés ne produit **aucune erreur** — tout tombe sur `0` ;
|
||||
- `.75` publie des cumulés corrompus (9,1e+33 kWh exportés) : `EnergyData.isPlausibleKwh`
|
||||
existe pour ça, ne pas le contourner.
|
||||
|
||||
- [ ] ❓ **« ECS d'abord, batterie ensuite » — à porter au moteur.** Demandé le 2026-08-27,
|
||||
et **pas exprimable aujourd'hui**. `batteryLevelConsideration` fait l'inverse : il annule
|
||||
le budget *sous* le seuil, donc la batterie passe avant. La batterie n'est pas dans le
|
||||
waterfall — aucune entrée `GetLoadConfig`, et `enableCharging` / `chargingRate` /
|
||||
`enableDischarging` n'apparaissent nulle part dans le plugin ETM. Le levier existe
|
||||
pourtant : la classe **SunSpec Storage** de `.75` déclare ces cinq actions. Question :
|
||||
*le stockage est-il une charge arbitrable, ou reste-t-il hors du budget ?* Une règle
|
||||
`Rules.*` serait un contournement — deux commandeurs sur la batterie, exactement le
|
||||
défaut que 3g-2 vient de supprimer sur les bornes.
|
||||
|
||||
- [ ] **Zones de climatisation — cadrage écrit, banc à préparer.** Voir
|
||||
`docs/CADRAGE_zones_clim.md`. Le blocage n'est pas « aucune zone déclarée » : sur les 58
|
||||
classes de `.75`, **aucune ne porte `thermostat`, `closablesensor`, `temperaturesensor`
|
||||
ni `notifications`** — aucun plugin installé ne sait en créer une. Deux paquets du dépôt
|
||||
apt du banc suffisent (`nymea-plugin-generic-heatingcooling`,
|
||||
`nymea-plugin-generic-sensors`). Six décisions à prendre avant de coder.
|
||||
|
||||
- [ ] **`EV_GRID_START` / `PHASE_LIMIT` — éprouvés par test seulement.** Les clés ARB sont
|
||||
prêtes, les motifs n'ont **jamais été vus sur machine**. Signaler la première occurrence
|
||||
réelle. Ne rien bâtir autour d'ici là.
|
||||
|
||||
- [ ] **`EVChargingCard` n'est montée par AUCUN écran** (constaté le 2026-08-27 — le
|
||||
tableau de bord utilise `features/dashboard/widgets/`). Soit elle rejoint un écran, soit
|
||||
elle part ; en l'état c'est du code mort qui a l'air vivant.
|
||||
|
||||
- [ ] **Le passage sur appareil doit devenir une habitude, pas un rattrapage.** Il a glissé
|
||||
deux fois, et au premier passage il a trouvé deux cibles tactiles hors norme (26 px, 18 px)
|
||||
qu'aucun des 129 tests unitaires ne pouvait voir. `integration_test/ui_3g2_on_device_test.dart`
|
||||
est le harnais. Rappel MIUI : la confirmation d'installation est redemandée à **chaque**
|
||||
fois — faire un `adb install -r -t` préalable, puis lancer le test.
|
||||
|
||||
## Charges pilotables — ce qui attend la box (2026-08-26)
|
||||
|
||||
- [ ] **`kCodesReserveBatterie`** — le `Set` est volontairement VIDE dans
|
||||
`lib/services/telemetry_text.dart`. Y mettre le code du motif « budget annulé par la réserve
|
||||
batterie » **quand le moteur le publiera**, pas avant : deviner son nom produirait un
|
||||
affichage qui ne se déclenche jamais.
|
||||
- [x] ~~**`kCodesReserveBatterie`**~~ — **fait le 2026-08-27.** Le motif est publié :
|
||||
`BATTERY_RESERVE`, params `socPercent` / `reservePercent` / `withheldW`. Les clés que le
|
||||
fichier cherchait (`batteryLevel`, `threshold`) n'avaient **jamais** existé côté plugin —
|
||||
le motif sortait donc en repli anglais sur le seul cas qu'aucune mesure ne révèle.
|
||||
- [ ] **`minPowerW == null` sans véhicule branché** — couvert en test unitaire
|
||||
(`test/ev_runtime_test.dart`), **pas exercé sur appareil** : la borne n'entre pas dans
|
||||
`loads[]` avant `3g`. À reprendre quand l'arbitrage prendra la recharge en charge.
|
||||
- [ ] **Réserve batterie — portée élargie.** Le jour où le seuil gouverne tout le budget,
|
||||
reprendre le texte de `BatteryReserveCard` : il annonce aujourd'hui un futur, il devra
|
||||
décrire un présent.
|
||||
- [ ] ~~Zones~~ — `ac_screen.dart` est de la donnée fictive et `.75` n'en déclare aucune.
|
||||
**Décidé : à ne pas entreprendre.**
|
||||
- [ ] ~~Zones — à ne pas entreprendre~~ — **décision revue le 2026-08-27** : le lot est
|
||||
cadré (`docs/CADRAGE_zones_clim.md`), voir l'entrée en tête de ce fichier. `ac_screen.dart`
|
||||
reste de la donnée fictive — quatre pièces, huit températures crédibles affichées comme
|
||||
des mesures.
|
||||
|
||||
## En cours / priorité haute
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user