Le signal vit dans GetLoadConfig, en r:, et non dans la télémétrie. `measurement` n'existe que pour les charges arbitrées ; or une charge qu'on DÉCLARE est précisément celle qui n'y est pas encore. L'écran serait muet au moment exact où il doit parler — celui de la saisie, avant qu'une obligation n'achète à l'aveugle tous les jours. Trois causes, trois gestes : noMeter se répare en une manipulation, meterWithoutEnergy demande de remplacer le compteur, noSessionEnergy ne se répare pas. Sans la cause, l'avertissement ne peut dire que « ça ne marchera pas ». Et meterThingId ne permet pas de le déduire : un compteur peut publier currentPower sans totalEnergyConsumed — mesuré sur l'ECS du banc, reproduit au test avec un powerSwitch désigné comme compteur. La puissance ne suffit pas, il faut une énergie. Contre-épreuve : déduction par meterThingId seul, le cas du banc passe pour mesurable. INVENTAIRE À FROID DU MOCK. Trois fois en trois jours qu'un cas réel s'est révélé inatteignable ; ce n'est plus un incident, c'est une propriété du banc — il est plus homogène que la réalité, ayant été construit pour faire marcher des scénarios et non pour représenter la diversité du parc. Quatre cas restent structurellement introuvables, dont `source: none` pour une charge SAINE — toutes les classes pilotables portent une puissance, si bien qu'une charge non mesurée mais en bon état est impossible à fabriquer, alors qu'un relais sec est banal sur le terrain. Et la branche `temperature`, écrite et jamais exécutée faute d'une classe qui porte l'état. La règle : avant d'écrire un test qui exerce une ABSENCE, vérifier que le mock peut la produire. Une assertion sur un cas inatteignable ne passe pas, elle NE S'EXÉCUTE PAS — ce qui est pire, car elle compte comme verte. Le symptôme se reconnaît : la contre-épreuve ne mord pas. Deux ajouts dans AGENTS.md. L'asymétrie des latences est une PROPRIÉTÉ, pas une chance : le refus qui coûte de l'argent est celui de la descente, et c'est le plus vite constaté — ce qui n'est vrai que parce que le seuil vient du mécanisme. Et la question opératoire appliquée aux trois autres identités, avec un résultat inégal qui est le but : celle de `draw` repose sur le fait que le compteur voie toute la maison, ce que rien ne vérifie ; Σ levels[].targetW == estimatedPowerW est interne au plan et ne dit rien du matériel — il a fallu un champ hors de la formule pour relier les deux. Suite : simulation 61/61, loadmodel 22/22, charging 48/48 identique à la référence, spotmarket 32/32, doxygen 0 avertissement. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015F7G5VeaPVSMeVNjiGj36p
80 lines
4.4 KiB
Markdown
80 lines
4.4 KiB
Markdown
# INVENTAIRE À FROID DU MOCK — ce qu'il rend structurellement introuvable
|
|
|
|
*(Fait le 2026-09-01, après trois occurrences en trois jours d'un cas réel impossible à
|
|
reproduire. Ce n'est plus un incident, c'est une propriété du banc d'essai.)*
|
|
|
|
## Pourquoi cet inventaire
|
|
|
|
Trois fois cette semaine, un défaut réel s'est révélé **inatteignable par la suite** :
|
|
|
|
| Occurrence | Ce qui était introuvable | Comment on l'a su |
|
|
|---|---|---|
|
|
| Correctif amont `calculateAllowanceAmpere` | un compteur publiant les courants **sans** les puissances par phase | le mock pose `currentPhaseB = currentPowerPhaseB / 230`, cohérent **par construction** |
|
|
| Test `command` sous `source: none` | une charge dont rien ne mesure la puissance | **toutes** les classes pilotables portent `currentPower` |
|
|
| Test `ECO_FLOOR_*` en régime `unmeasurable` | une borne sans `sessionEnergy` | il a fallu **ajouter** l'état à une seule classe pour avoir les deux cas |
|
|
|
|
Le point commun : **le mock est plus homogène que la réalité.** Il a été construit pour faire
|
|
marcher des scénarios, pas pour représenter la diversité du parc — et une suite verte ne dit alors
|
|
rien sur les cas qu'il ne sait pas produire.
|
|
|
|
## Les classes, et ce qu'elles portent
|
|
|
|
| Classe | `currentPower` | `totalEnergyConsumed` | `sessionEnergy` |
|
|
|---|---|---|---|
|
|
| `meter` | ✅ | ✅ | — |
|
|
| `charger` | ✅ | ✅ | ❌ |
|
|
| `chargerPhaseSwitching` | ✅ | ✅ | ✅ *(ajouté le 2026-08-31)* |
|
|
| `simpleCharger` | ❌ | ❌ | ❌ |
|
|
| `powerSwitch` | ✅ | ❌ | — |
|
|
| `etmVariableLoad` | ✅ *(`currentPowerW`)* | ❌ | — |
|
|
| `energyStorage` | ✅ | ❌ | — |
|
|
| `car`, `notification` | ❌ | ❌ | — |
|
|
|
|
**Ce que la table donne, et c'est la bonne nouvelle** : `sessionEnergy` et `totalEnergyConsumed`
|
|
sont désormais **discriminants** — il existe des classes avec et sans. Les régimes `measured` /
|
|
`unmeasurable` et les causes `noSessionEnergy` / `meterWithoutEnergy` sont donc exerçables.
|
|
|
|
## Ce qui reste STRUCTURELLEMENT introuvable
|
|
|
|
**1. `measurement.source: none` pour une charge saine.** Toutes les classes pilotables portent une
|
|
puissance. Le seul chemin est une charge dont le **Thing n'existe pas** (câblage manquant) — cas
|
|
réel, mais qui traîne avec lui `available: false`. **Une charge saine et non mesurée est
|
|
impossible à fabriquer ici**, alors qu'elle est banale sur le terrain (un relais sec).
|
|
|
|
**2. Un compteur par phase incohérent.** `currentPhaseX` et `currentPowerPhaseX` sont posés
|
|
ensemble par le mock, dans un rapport fixe de 230. Aucun scénario ne peut produire une tension
|
|
réelle ≠ 230 V, ni un compteur qui ne publierait qu'une des deux familles.
|
|
|
|
**3. `temperature`.** Le code teste `hasState("temperature")` et **aucune classe du mock ne le
|
|
porte** : la branche « sonde présente » n'a jamais été exécutée. Elle est écrite, elle n'est pas
|
|
testée.
|
|
|
|
**4. Une borne triphasée à phases déséquilibrées.** Les états existent, mais aucun helper de test
|
|
ne les pose indépendamment — d'où le pessimisme de `LM-1210-a` qui n'a jamais été exercé sur un
|
|
vrai déséquilibre.
|
|
|
|
## La règle qui en sort
|
|
|
|
> **Avant d'écrire un test qui exerce une ABSENCE, vérifier que le mock peut la produire.**
|
|
> Une assertion sur un cas inatteignable ne passe pas : elle **ne s'exécute pas**, ce qui est
|
|
> pire — elle compte comme verte.
|
|
>
|
|
> Le symptôme se reconnaît : **la contre-épreuve ne mord pas**. C'est le corollaire fin
|
|
> d'`AGENTS.md` appliqué au banc d'essai plutôt qu'au code.
|
|
|
|
**Et la parade tient en une ligne de test** : quand on itère pour trouver des cas, **compter
|
|
combien on en a examinés**, et échouer si le compte est nul. C'est ce qui a rattrapé le test de
|
|
`command`, et ce qui garde celui de la mesurabilité.
|
|
|
|
## Ce qu'il faudrait ajouter, par ordre d'utilité
|
|
|
|
1. **Une classe pilotable SANS aucune puissance** — un relais sec. Débloque `source: none` sur
|
|
une charge saine, et sépare enfin « non mesurée » de « en panne ».
|
|
2. **Un compteur sans `totalEnergyConsumed`** en tant que classe déclarée, plutôt qu'un
|
|
`powerSwitch` détourné comme aujourd'hui.
|
|
3. **Une tension par phase réglable** indépendamment des puissances — pour exercer le correctif
|
|
amont ailleurs qu'en inversant la fonction.
|
|
|
|
> Aucune de ces trois n'est urgente. Ce qui l'est, c'est de **savoir qu'elles manquent** : sans
|
|
> cette liste, chaque lot repaiera le même temps à découvrir qu'un cas est introuvable.
|