# tests-pv — banc de test « gammes PV » de l'agent vocal Garde-fou de la section **« Repères énergie »** d'`AGENTS.md`. À rejouer à CHAQUE modification de cette section : il vérifie que l'agent lit la bonne source, discrimine bridage / vraie baisse / substitution, décide (charge voiture, reste à capter) et reste propre sur des données abîmées (gel GX, capteur `unavailable`). ## Lancer node tests-pv/campagne-pv.mjs [passages=3] [--only=] - Extrait la section « Repères énergie » de la vraie `AGENTS.md` à l'exécution (donc teste la fiche DÉPLOYÉE, pas une copie). - Envoie des snapshots FIGÉS de capteurs au modèle Spark (`qwen3-coder`), puis note sur N passages (>=3 : un run unique ne distingue pas 3/5 de 5/5). - Écrit un journal `journal-.json` à côté du script. Variables : `SPARK_URL` (défaut http://10.10.10.8:8000/v1/chat/completions), `AGENTS_MD` (défaut ../AGENTS.md). ## Vérité-terrain Snapshots et attendus = mesures RÉELLES fournies par le contrôleur EVCS (PostgreSQL/InfluxDB). **Ne jamais inventer un attendu** — cf. le bug des 4,2 kWh (extrapolation prise pour du réalisé). Statut de chaque cas : | Cas | Teste | Source | |-----|-------|--------| | G1 | production du jour = somme des 3 yield | réel | | G2 | reste à produire = prévision restante (seule exception) | réel | | G3 | bridage batterie pleine → lit `evcs_pv_diagnostic`=bridage_normal, ne rejuge pas | réel | | G4 | vraie baisse → `evcs_pv_diagnostic`=ressource_limitee | réel | | G5 | substitution → `evcs_pv_diagnostic`=substitution_edf, l'agent NE rejuge PAS | apprentissage (réel 27/08) | | G6 | charge voiture : excédent négatif → non | réel | | G7 | reste-t-il du solaire à capter | réel | | G8 | gel GX en journée → ne pas citer une valeur figée | synthétique hygiène | | G9 | yield `unavailable` → production partielle, ne pas sommer un trou | synthétique | | G10 | prévision de production DEMAIN (≠ réalisé du jour) | réel | | G11 | cellule la plus sensible → détail BMS `unavailable` (HA), le dire sans inventer | réel (HA cell down depuis 15/09) | | G11b | cellule la plus sensible → identifier le plus grand déséquilibre | réel (relevé série EVCS) | | G12 | charge voiture nuit : faut-il de l'EDF ? surplus vs besoin, jamais soustraire un SOC | réel | Architecture (25/09/2026) : le JUGEMENT est sorti de la fiche vers des capteurs calculés côté service EVCS — `sensor.evcs_pv_diagnostic` (état + explication) et `sensor.evcs_cellules` (écart + module, ou statut perime/muet). L'agent LIT et RELAIE, il ne discrimine plus. Fraîcheur via `sensor.evcs_historisation_heartbeat`. Cela a GUÉRI la fragilité : G3, G4, G5, G13b = **7/7** sur 7 passages (avant, un ajout anodin ailleurs faisait chuter G5 de 7/7 à 1/7). Dernier état (26/09) : réseau/EDF câblé — import du jour (evcs_import_jour_kwh, compteur EDF), import nuit (bilan_nuit.reseau_importe_kwh), état réseau (evcs_reseau : non_raccorde/mesure_muette/incoherent). Nouveaux cas 5/5. e2e E1–E8. Gmail déplacé en reference-gmail.md (garde-fous 4.6/4.7 gardés en fiche). Fiche 24 137 car (marge 5 863). ## Banc bout en bout — `e2e-attributs.mjs` `campagne-pv.mjs` injecte des snapshots directement : il teste le raisonnement, mais ne traverse pas l'outil de lecture `airtria-ha-read.js`. Un défaut de l'outil lui est donc invisible — c'est ainsi qu'un banc à 15/15 a coexisté avec un agent qui ne voyait aucun attribut en réel (le module de la cellule, trouvé à la main par le propriétaire le 25/09). `e2e-attributs.mjs` bouche ce trou : il appelle le VRAI outil sur les VRAIES entités live et vérifie qu'un fait porté UNIQUEMENT par un attribut remonte (1) dans la sortie de l'outil, (2) dans la réponse du modèle. L'attendu est lu au moment du run via l'API HA (concordance, jamais une valeur figée). node tests-pv/e2e-attributs.mjs [passages=3] Cas : E1 module_le_plus_sensible (evcs_cellules), E2 source/raison contrôleur (evcs_charge_solaire), E3 statut (evcs_production_jour_kwh). Si l'outil n'expose pas la vérité, le banc l'affiche en clair — c'est le défaut qu'on veut attraper.