Bilan : plus de faux statut degrade le soir (heure lue dans la courbe horaire)

Chaque soir ~1 h, une heure de deficit encore ensoleillee etait classee
« minoree » d'apres le taux de censure de l'enveloppe, alors que sa production
venait de la courbe horaire VRM / Forecast.Solar. Le bilan passait `degrade`
et le controleur l'ignorait (plancher du soir a 85 % fixe). Les heures lues
dans la courbe sont desormais `courbe`. Verifie : 18:20 ok, chiffres
identiques a 18:15 degrade. Bilan 72/72.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
This commit is contained in:
Tallagrand Thierry
2026-09-29 18:26:29 +02:00
parent 0975e62bda
commit 98c7e6b1d0
4 changed files with 34 additions and 7 deletions

View File

@@ -1179,11 +1179,13 @@ affiner ; demarrage solaire de l'apres-midi toujours non couvert par le besoin d
l'historique de production de ces heures de fin de journee est incomplet … la decision l'historique de production de ces heures de fin de journee est incomplet … la decision
reelle est reprise a 01:24 » ; `indisponible` seulement sans bilan, bilan perime ou reelle est reprise a 01:24 » ; `indisponible` seulement sans bilan, bilan perime ou
statut inconnu, avec la raison dans `explication`. Diagnostics 90/90, mutation qui mord. statut inconnu, avec la raison dans `explication`. Diagnostics 90/90, mutation qui mord.
⚠️ **OUVERT, decision du proprietaire** : pendant cette heure, le controleur ignore Pendant cette heure, le controleur ignorait AUSSI le bilan (`balanceStatusOk`) :
AUSSI le bilan (`balanceStatusOk`) -> plancher du soir retombe sur 85 % fixe, cible et plancher du soir retombe sur 85 % fixe. **Corrige a la source (accord du proprietaire,
session sur les regles historiques. A 01:24 le statut est `ok` (pas d'effet sur la 18:20)** : `RESOURCE_ESTIMATE` classe `courbe` toute heure dont l'energie est lue dans la
session de nuit constate). Piste : ne pas degrader sur une forme minoree quand la courbe horaire ; `minoree` ne qualifie plus que les heures reparties sur l'enveloppe
production horaire vient de la courbe de prevision (et non de l'enveloppe). (repli). Verifie en reel : 18:15 `degrade`, 18:20 `ok`, chiffres IDENTIQUES (67,2 /
81,5 / 13,56 kWh) — l'etiquette ne changeait rien au calcul. Bilan 72/72, mutation qui
mord. Le statut `sous_reserve` de la prevision ne doit plus apparaitre qu'en repli.
- SPARK : les transcripts SQLite (`openclaw-agent.sqlite`, droits 600) remontent au - SPARK : les transcripts SQLite (`openclaw-agent.sqlite`, droits 600) remontent au
18/07, AUCUNE rotation ; un evenement contient le jeton HA (l'agent a lu `.ha-token`). 18/07, AUCUNE rotation ; un evenement contient le jeton HA (l'agent a lu `.ha-token`).
Signale au proprietaire par SPARK, base non modifiee. Signale au proprietaire par SPARK, base non modifiee.

View File

@@ -216,10 +216,14 @@ const tomorrowSlots = slots.filter(s => s.day !== today);
if (hourlyAvailable) { if (hourlyAvailable) {
// Lecture directe : chaque heure porte déjà son énergie prévue. // Lecture directe : chaque heure porte déjà son énergie prévue.
for (const slot of todaySlots) slot.expectedKwh = Math.max(0, hourlyForToday[slot.hour] ?? 0); for (const slot of todaySlots) {
slot.expectedKwh = Math.max(0, hourlyForToday[slot.hour] ?? 0);
slot.fromCurve = true;
}
if (hourlyForTomorrow) { if (hourlyForTomorrow) {
for (const slot of tomorrowSlots) { for (const slot of tomorrowSlots) {
slot.expectedKwh = Math.max(0, hourlyForTomorrow[slot.hour] ?? 0); slot.expectedKwh = Math.max(0, hourlyForTomorrow[slot.hour] ?? 0);
slot.fromCurve = true;
} }
} else { } else {
// Courbe decalee : on connait aujourd'hui, pas demain. L'enveloppe mesuree // Courbe decalee : on connait aujourd'hui, pas demain. L'enveloppe mesuree
@@ -232,6 +236,19 @@ if (hourlyAvailable) {
distribute(tomorrowSlots, tomorrowKwh); distribute(tomorrowSlots, tomorrowKwh);
} }
// Une heure lue dans la COURBE HORAIRE ne doit rien a l'enveloppe (29/09/2026).
// La classer « minoree » d'apres le taux de censure de l'enveloppe faisait
// passer le bilan `degrade` chaque soir pendant une heure (19 h du 23 au 28/09,
// 18 h le 29/09) : l'heure du soir encore ensoleillee est une heure de deficit,
// et son historique est censure parce que la batterie est souvent pleine a
// cette heure. Or sa production venait de VRM / Forecast.Solar, pas de cet
// historique. Pendant cette heure le controleur ignorait le bilan (plancher du
// soir retombe a 85 % fixe). « minoree » ne qualifie plus que les heures dont
// l'energie a ete repartie sur l'enveloppe (repli).
for (const slot of slots) {
if (slot.fromCurve && slot.quality !== 'nuit') slot.quality = 'courbe';
}
// Repère de vraisemblance, sans écrêtage : l'enveloppe est minorée l'après-midi. // Repère de vraisemblance, sans écrêtage : l'enveloppe est minorée l'après-midi.
for (const slot of slots) { for (const slot of slots) {
slot.aboveEnvelope = !!envelope && envelope[slot.hour] > 0 slot.aboveEnvelope = !!envelope && envelope[slot.hour] > 0

View File

@@ -319,6 +319,12 @@ export const resourceScenarios = [
mode: 'courbe_horaire_api', mode: 'courbe_horaire_api',
// Reste de la journée à partir de 09 h : lu dans la courbe, pas recalculé. // Reste de la journée à partir de 09 h : lu dans la courbe, pas recalculé.
todayExpected: 42.8, todayExpected: 42.8,
// 29/09 : une heure lue dans la courbe ne doit rien a l'enveloppe, meme
// censuree (14 h : taux 0,63) — plus de faux « minoree », plus de faux
// `degrade` du bilan chaque soir. La nuit reste la nuit.
qualityAtHour14: 'courbe',
qualityAtHour3: 'nuit',
shapeConfidenceBelow: false,
}, },
}, },
{ {
@@ -338,6 +344,8 @@ export const resourceScenarios = [
usable: true, usable: true,
mode: 'repli_enveloppe', mode: 'repli_enveloppe',
todayExpected: 15.9, todayExpected: 15.9,
// Repli sur l'enveloppe : la forme minoree reste signalee.
qualityAtHour14: 'minoree',
}, },
}, },
{ {

File diff suppressed because one or more lines are too long