Fix G: coupure EDF générique quand l'override EVCS disparaît mi-session

Incident nuit 21-22/08 : la fenêtre HC nuit se ferme pendant que le véhicule
est encore en session active (pas encore flag "charge terminée"). L'EVCS
relâche correctement son override, mais émet un état transitoire générique
(stop_source_lost/idle_wait_source) qu'aucune règle de coupure immédiate du
workflow Grid Hysteresis (Fix C/E2) ne reconnaît. EDF restait alors maintenu
des heures par la boucle générique jusqu'au seuil statique gridSocOff,
plafonnant le MPPT Victron à ~100W et privant la maison de solaire.

Nouvelle règle générique (Compute Grid Hysteresis) basée sur evcsGridOverride
plutôt que sur une liste blanche de noms de surplus_state — couvre donc aussi
tout futur état non énuméré. Garde anti-glitch sur lecture HA invalide.
Nouvelle suite tests/golden-hysteresis/ (7 scénarios, première pour ce
workflow), câblée bloquante dans tools/n8n-push.mjs. Déployé et validé
(golden-hysteresis 7/7, golden EVCS 39/39 inchangé).

Écarte le diagnostic incomplet laissé par un autre agent dans HANDOFF.md
(edf_general_ok_off côté EVCS aurait créé un deuxième écrivain non coordonné
sur le même switch).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Tallagrand Thierry
2026-08-22 19:56:06 +02:00
parent 5bc9784583
commit e68fa160b6
8 changed files with 577 additions and 5 deletions

View File

@@ -1109,5 +1109,136 @@ p11-changement-vehicule-nuit (prev=night_recovery_done_idle + charging_time 15s
2. CHANGEMENT DE VÉHICULE / nouvelle connexion (charging_time ≤ 90 s, P11) ;
3. force_charge_now / force_grid_now (échappatoires manuelles).
## Diagnostic en attente de vérification (Qwen, 22/08)
Voici mon analyse et plan de correction :
Diagnostic
Le bug est dans HA_SERVICE_CALLS_OUTPUT.js:987-996 :
edf_general_ok_on: {
execute: ['grid_forced', 'grid_hc_allowed'].includes(context.sourceMode) && !parsed.gridAvailable,
...
}
Il n'existe pas de edf_general_ok_off. Le workflow ne coupe JAMAIS activement EDF. Il ne fait que le rallumer quand sourceMode est grid ET que le réseau n'est pas encore disponible. Quand sourceMode revient à solar_only/blocked, le switch reste ON dans l'état qu'il avait.
Conséquence : après la fenêtre HC nocturne (~06:00), EDF reste allumé. La présence du réseau bloque la production PV (Victron plafonne à ~100 W). Le débranchement du véhicule résout parce que c'est le seul mécanisme qui coupe physiquement le switch.
Plan de correction
Fichier : src/nodes/HA_SERVICE_CALLS_OUTPUT.js
Ajouter un call edf_general_ok_off juste après edf_general_ok_on (ligne 996) :
edf_general_ok_off: {
execute:
!['grid_forced', 'grid_hc_allowed'].includes(context.sourceMode) &&
parsed.gridAvailable &parsed.evcsVehicle
**Verdict (Claude, 22/08) : diagnostic ÉCARTÉ, voir §24 ci-dessous.** Le
symptôme est correctement identifié (EDF ne se coupe jamais activement après
la fenêtre HC) mais la cause et le correctif proposés sont faux : le bug n'est
pas dans `HA_SERVICE_CALLS_OUTPUT.js` (qui n'a jamais eu vocation à couper EDF
— la coupure est le rôle exclusif du workflow séparé "Victron - Battery / Grid
Hysteresis Fix V1"), et ajouter un `edf_general_ok_off` côté EVCS créerait un
deuxième écrivain non coordonné sur `switch.edf_general_ok_switch` (courses
30s/1min entre les deux workflows, le hysteresis reprenant la main au cycle
suivant via son propre `latchIsOn` et rallumant probablement EDF quand même).
Le vrai bug et son correctif (Fix G, côté hystérésis) sont documentés en §24.
---
*Document mis à jour le : 12/08/2026 (~05:05) — P11 déployé et validé live, golden 39/39*
*Document mis à jour le : 22/08/2026 (~18:00) — Fix G déployé (hystérésis), diagnostic Qwen écarté, golden-hysteresis 7/7*
## 24. Session du 22/08/2026 — Fix G : coupure EDF quand l'override EVCS disparaît mi-session (hystérésis)
### Incident (nuit 21-22/08)
Le takeover nuit (P7) a correctement rechargé la batterie à ~35 % via EDF.
Quand la fenêtre HC s'est fermée (~06:00-07:24) avec le véhicule **encore
branché en session active** (pas encore flag "charge terminée"), EDF est resté
allumé — le réseau a plafonné le MPPT Victron à ~100 W, privant la maison de
600-4000 W de solaire disponible (elle tirait ~1000 W d'EDF). Seul le
débranchement du véhicule a libéré EDF (2179 W de PV immédiatement après).
### Root cause
Côté EVCS (`WINDOWS_SOURCEV2.js`/`DECISION_ENGINEV2.js`) : **pas le bug**.
Chaque cycle, `nightSessionActive` et tout le moteur nuit sont activement
recalculés à `false`/`'blocked'` dès la fermeture de fenêtre — `helper
night_grid_takeover_needed` passe à `off` et `source_mode` à `'Bloqué'`
correctement et immédiatement, même mi-session. MAIS les deux branches
"collantes" de fin de session (Fix F, exige `profile === 'night_hc'` ; P10
`day_vehicle_full_idle`, exige que le `surplus_state` précédent soit déjà un
pattern "terminé") ne se déclenchent PAS sur le cycle exact où la fenêtre se
ferme mi-session non-terminée. Le système retombe sur des états génériques
transitoires (`stop_source_lost` puis `idle_wait_source`).
Côté **Grid Hysteresis** (`workflows/victron-grid-hysteresis-v1.json`, node
"Compute Grid Hysteresis") : **c'est là le bug**. Les règles de coupure
immédiate existantes (Fix C `turn_off_vehicle_unplugged`, Fix E2
`turn_off_recovery_done`) ne matchent que des noms exacts de `surplus_state`
(`vehicle_not_connected`, `night_recovery_done_idle`, `departure_done_idle`) —
aucune ne matche `stop_source_lost`/`idle_wait_source` (ni `day_vehicle_full_idle`
lui-même). Sans matche, le code retombe sur la boucle générique qui maintient
EDF jusqu'au seuil statique `grid_soc_off` (35 %, `input_number.victron_grid_soc_off`),
totalement découplé de la cible dynamique de l'EVCS — potentiellement des
heures, d'autant qu'EDF-ON lui-même bride la recharge solaire organique.
### Fix G (déployé 22/08 ~18:00, golden-hysteresis 7/7)
Au lieu d'ajouter encore un nom d'état à une liste blanche fragile, nouvelle
règle **générique** dans "Compute Grid Hysteresis", basée sur `evcsGridOverride`
(déjà fiable) plutôt que sur le nom de `surplus_state` — couvre donc aussi
automatiquement tout futur nom d'état non énuméré :
```javascript
if (
!forcedCut && latchIsOn && gridIsOn &&
!evcsGridOverride &&
soc > gridSocOn && // 22%, PAS gridSocOff 35% — protège le cas
// indépendant "SOC bas" qui doit tenir
// jusqu'à gridSocOff
evcsSourceModeLooksValid // garde anti-glitch (lecture HA vide/
// unavailable/unknown → pas d'action)
) {
desiredGrid = 'off'; desiredLatch = 'off';
state = 'turn_off_evcs_override_released';
forcedCut = true;
}
```
Coupure immédiate, bypass min_on (25 min), comme Fix C/E2. Décision validée
avec l'utilisateur : vitesse de libération prioritaire sur le risque résiduel
(un glitch de lecture HA sur un seul cycle pourrait causer une coupure/
rallumage isolé, auto-diagnosticable dans le logbook — pas de chatter soutenu
car il faudrait une lecture fausse à *chaque* cycle).
### Nouvelle suite de tests : `tests/golden-hysteresis/` (7 scénarios, première
suite pour ce workflow — 0 → 7)
`g-incident-gap-mid-session`/`g-incident-gap-idle-wait-source` (les deux noms
d'état zombies de l'incident, min_on non écoulé) · `g-incident-replay-hc-boundary`
(rejeu complet, min_on déjà écoulé aussi — prouve que ce n'est pas seulement un
bypass min_on) · `g-baseline-low-soc-no-override` (garde non-régression : SOC
bas indépendant doit continuer à tenir) · `g-regression-fixc-unplugged` /
`g-regression-fixe2-recovery-done` (Fix C/E2 toujours prioritaires, pas
absorbés par Fix G) · `g-glitch-guard-unavailable` (garde anti-glitch).
Lancée AVANT patch : 3 échecs (les scénarios d'incident, stuck sur
`hold_on_min_runtime`/`hold_on_until_soc_off`) + 4 succès (gardes déjà bonnes)
— confirme que le harnais détecte vraiment le bug. Après patch : 7/7.
Câblée dans `tools/n8n-push.mjs` (nouveau `isHysteresisWorkflow`), bloquante
au push comme les 2 autres workflows.
### Outillage
`tools/patch-20260822-g-override-released-cut.mjs` (rejouable, même patron que
`patch-20260809-e2-recovery-done-cut.mjs`) · `tests/golden-hysteresis/{fixture-snapshot.json,run.mjs,scenarios.mjs}`.
### Déploiement
`node tools/n8n-push.mjs workflows/victron-grid-hysteresis-v1.json` → backup
serveur auto (`modified/prepush-7iIlu7LLTW7TZA8o-*.json`) → syntaxe OK →
golden-hysteresis 7/7 → PUT OK. `grid_min_on_minutes` réel vérifié via MCP
`ha-get-state` avant de figer le fixture : **25** (pas le fallback 45 du code).
### Hors périmètre (volontairement)
Aucun changement côté `src/nodes/*` (EVCS V2.6) — le fix est entièrement côté
hystérésis. Amélioration cosmétique future possible, non incluse ici :
remplacer les noms zombies `stop_source_lost`/`idle_wait_source` par un état de
transition dédié pour la lisibilité dashboard/logbook.
### À surveiller (prochaine fermeture de fenêtre HC avec véhicule encore
branché mi-session)
1. Logbook doit montrer `turn_off_evcs_override_released` peu après la
fermeture de fenêtre si le véhicule n'est pas encore flag "terminé" ;
2. La PV doit remonter (MPPT non-plafonné) immédiatement après ;
3. Aucune coupure/rallumage répété (`turn_off_evcs_override_released` suivi de
près par `turn_on_evcs_override` répétitivement) — signe d'un glitch de
lecture HA à investiguer si observé.
---
*Document mis à jour le : 22/08/2026 (~18:05) — Fix G déployé et validé (syntaxe + golden-hysteresis 7/7 + PUT OK), à confirmer en conditions réelles à la prochaine fermeture de fenêtre HC mi-session