Files
EVCS/tools/patch-20260824-revert-g.mjs
Tallagrand Thierry 522f47e821 Retrait de Fix G + garde-fous anti-yoyo + diagnostic des deux oscillateurs
Fix G provoquait un yoyo EDF de 2-4 min (coupure a SOC 21 en bypass min_on
contre rallumage a SOC 20 en bypass cooldown) : son garde `soc > gridSocOn`
ne protegeait que l'instant de l'engagement sur SOC bas, pas la phase de
remontee 20 -> 30. jsCode restaure byte-identique a la version pre-Fix-G.

Le fixture de test portait les fallbacks du code (22/35) au lieu des valeurs
de production lues via MCP (20/30), et le scenario de non-regression testait
SOC 18 %, le seul point que Fix G epargnait. Suite reecrite avec les
garde-fous manquants h-recovery-band-no-cut-21/-25. Mutation : Fix G
reapplique -> 4/7 echecs, retire -> 7/7.

Documentation du diagnostic des deux oscillateurs (yoyo EDF et oscillation
de la charge EVCS en plein soleil) dans MANUEL_COMPLET 11.8 et HANDOFF 25.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
2026-08-24 12:20:12 +02:00

68 lines
3.2 KiB
JavaScript

#!/usr/bin/env node
// Patch 24/08/2026 — REVERT de FIX G (22/08/2026).
//
// Pourquoi : Fix G coupait EDF dès que l'override EVCS disparaissait ET que
// SOC > gridSocOn. Le garde `soc > gridSocOn` ne protégeait que l'INSTANT de
// l'engagement sur SOC bas (soc <= 20), pas la PHASE DE REMONTÉE 20 -> 30 qui
// est 100 % de la durée de vie de ce cas. Résultat en production la nuit du
// 23-24/08, véhicule débranché :
// SOC 20 -> branche low_soc : EDF ON (bypass cooldown)
// SOC 21 -> Fix G : EDF OFF (bypass min_on)
// ... cycle de 2 à 4 minutes, MPPT qui flappe à chaque bascule.
// Fix G avait de fait remplacé l'hystérésis 20/30 par une hystérésis 20/20,1.
//
// De plus, sa prémisse était fausse : l'incident du 21-22/08 qui l'avait
// motivé n'est pas un problème d'override EVCS mais un problème de bilan
// énergétique (couper EDF à 21 % à 06:43 alors que la PV ne couvre la conso
// maison qu'à partir de ~09:00 rend le yoyo mécaniquement inévitable, quels
// que soient les seuils). Ce sujet est traité séparément.
//
// Cible : workflows/victron-grid-hysteresis-v1.json (node "Compute Grid Hysteresis").
// Rejouable : détecte si déjà retiré.
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const FILE = path.join(ROOT, 'workflows/victron-grid-hysteresis-v1.json');
const wf = JSON.parse(fs.readFileSync(FILE, 'utf8'));
const node = wf.nodes.find(n => n.name === 'Compute Grid Hysteresis');
if (!node) throw new Error('Node "Compute Grid Hysteresis" introuvable');
let code = node.parameters.jsCode;
if (!code.includes('turn_off_evcs_override_released')) {
console.log('Fix G déjà retiré — rien à faire.');
process.exit(0);
}
// --- 1. Bloc de décision -------------------------------------------------
const decisionStart = code.indexOf('\n// ======================================================\n// FIX G (22/08/2026)');
if (decisionStart === -1) throw new Error('En-tête du bloc de décision Fix G introuvable.');
const decisionEndMarker = " forcedCut = true;\n}\n";
const decisionEnd = code.indexOf(decisionEndMarker, decisionStart);
if (decisionEnd === -1) throw new Error('Fin du bloc de décision Fix G introuvable.');
code = code.slice(0, decisionStart) + code.slice(decisionEnd + decisionEndMarker.length);
// --- 2. Branche notification --------------------------------------------
const notifStart = code.indexOf("} else if (state === 'turn_off_evcs_override_released') {");
if (notifStart === -1) throw new Error('Branche notification Fix G introuvable.');
const notifEndMarker = " notifyWanted = true;\n\n";
const notifEnd = code.indexOf(notifEndMarker, notifStart);
if (notifEnd === -1) throw new Error('Fin de la branche notification Fix G introuvable.');
code = code.slice(0, notifStart) + code.slice(notifEnd + notifEndMarker.length);
if (code.includes('turn_off_evcs_override_released')) {
throw new Error('Résidus de Fix G après retrait — vérifier manuellement.');
}
node.parameters.jsCode = code;
fs.writeFileSync(FILE, JSON.stringify(wf, null, 2) + '\n', 'utf8');
console.log('Fix G retiré de', FILE, `(jsCode: ${code.length} caractères)`);