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
68 lines
3.2 KiB
JavaScript
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)`);
|