L'écart à la veille exige la même couverture des deux côtés (#179) #200

Merged
lenaic merged 1 commit from gabriel/179-couverture-veille into develop 2026-09-08 12:32:18 +00:00
Member

Trouvé en relisant la mise en production (#198), corrigé ici pour qu'elle parte propre.

Le garde-fou ne tenait que d'un côté

_consommation_veille_kw restreint bien la somme d'hier aux sites mesurés aujourd'hui — c'est ce que le #179 a corrigé, et le cas test_la_veille_est_sommee_sur_les_seuls_sites_mesures le garde. Mais rien ne vérifiait que la veille les portait TOUS.

mesure_horaire.moyenne_kw vaut avg(valeur_kw) filter (where indicateur_qualite <> 'critical') (0016) : un site dont le seau de la veille est vide ou entièrement dégradé rend null, sum() l'ignore en silence, et six sites d'aujourd'hui se comparent à trois d'hier. C'est exactement le faux delta que le périmètre corrigeait, retourné — une perte de COUVERTURE affichée comme une baisse de CONSOMMATION.

Le cas n'est pas théorique : le 08/09 à 08 h, la source marquait 416 relevés sur 420 en critical (#112).

Ce que ça change

select sum(moyenne_kw) as total, count(moyenne_kw) as sites

count(moyenne_kw) et non count(*) : une ligne présente dont la moyenne est nulle n'est pas une couverture. La colonne sites était déjà sélectionnée et jamais lue — le garde-fou était prévu, pas câblé. Une veille partielle rend maintenant None, et l'écran dit « pas de comparaison » au lieu d'un chiffre plausible et faux. Le contrat le permet déjà : consommation_veille_kw et ecart_veille_pct sont nullables depuis le #179, et SyntheseParc.vue les garde derrière un v-if.

Le double disait « sites: 7 » à une requête qui en demandait six

Il décrivait une base impossible, celle-là même dont la couverture partielle passait inaperçue. Il suit maintenant ce qu'on lui demande, et un cas nouveau rescripte une veille à trois sites pour éprouver le garde-fou.

Aucune requête d'aujourd'hui ne bouge, aucun schéma non plus.

Trouvé en relisant la mise en production (#198), corrigé ici pour qu'elle parte propre. ## Le garde-fou ne tenait que d'un côté `_consommation_veille_kw` restreint bien la somme d'hier aux sites mesurés aujourd'hui — c'est ce que le #179 a corrigé, et le cas `test_la_veille_est_sommee_sur_les_seuls_sites_mesures` le garde. Mais rien ne vérifiait que la veille les portait TOUS. `mesure_horaire.moyenne_kw` vaut `avg(valeur_kw) filter (where indicateur_qualite <> 'critical')` (0016) : un site dont le seau de la veille est vide ou entièrement dégradé rend `null`, `sum()` l'ignore en silence, et six sites d'aujourd'hui se comparent à trois d'hier. C'est exactement le faux delta que le périmètre corrigeait, retourné — une perte de COUVERTURE affichée comme une baisse de CONSOMMATION. Le cas n'est pas théorique : le 08/09 à 08 h, la source marquait 416 relevés sur 420 en `critical` (#112). ## Ce que ça change ```sql select sum(moyenne_kw) as total, count(moyenne_kw) as sites ``` `count(moyenne_kw)` et non `count(*)` : une ligne présente dont la moyenne est nulle n'est pas une couverture. La colonne `sites` était déjà sélectionnée et jamais lue — le garde-fou était prévu, pas câblé. Une veille partielle rend maintenant `None`, et l'écran dit « pas de comparaison » au lieu d'un chiffre plausible et faux. Le contrat le permet déjà : `consommation_veille_kw` et `ecart_veille_pct` sont nullables depuis le #179, et `SyntheseParc.vue` les garde derrière un `v-if`. ## Le double disait « sites: 7 » à une requête qui en demandait six Il décrivait une base impossible, celle-là même dont la couverture partielle passait inaperçue. Il suit maintenant ce qu'on lui demande, et un cas nouveau rescripte une veille à trois sites pour éprouver le garde-fou. Aucune requête d'aujourd'hui ne bouge, aucun schéma non plus.
api : l'écart à la veille exige la même couverture des deux côtés (#179)
All checks were successful
Intégration / Contrôles statiques du dépôt (pull_request) Successful in 8s
Intégration / Workflows — lint et audit de sécurité (pull_request) Successful in 22s
Intégration / Tableau de bord — dépendances, tests et construction (pull_request) Successful in 38s
Intégration / Python — qualité, tests et dépendances (pull_request) Successful in 5m38s
0666526590
Le périmètre de la requête était bien restreint aux sites mesurés du jour,
mais rien ne vérifiait que la veille les portait tous. `moyenne_kw` vaut
`avg(...) filter (where indicateur_qualite <> 'critical')` dans la 0016 :
un site dont le seau de la veille est vide ou entièrement dégradé rend
`null`, `sum()` l'ignore, et six sites d'aujourd'hui se comparaient à trois
d'hier. Le même faux delta que le périmètre corrigeait, retourné — une
perte de couverture lue comme une baisse de consommation. Le 08/09 à 08 h
la source marquait 416 relevés sur 420 en `critical` (#112).

`count(moyenne_kw)` et non `count(*)` : une ligne présente dont la moyenne
est nulle n'est pas une couverture. La colonne était déjà sélectionnée et
jamais lue ; elle décide maintenant, et une veille partielle rend `None` —
l'écran dit « pas de comparaison » plutôt qu'un chiffre plausible et faux.

Le double de la veille répondait « sites: 7 » à une requête qui en demandait
six : il décrivait une base impossible, celle-là même dont la couverture
partielle passait inaperçue. Il suit maintenant ce qu'on lui demande.
lenaic approved these changes 2026-09-08 12:32:17 +00:00
lenaic left a comment

Vérifié contre enervision_prod avant d'approuver, parce que le garde-fou peut couper une comparaison utile s'il est trop strict. Il ne l'est pas :

        heure          sites_couverts
2026-09-08 09:00:00+00              7
2026-09-08 08:00:00+00              2
2026-09-08 07:00:00+00              7
2026-09-08 06:00:00+00              7

Le seau de la veille visé à cette heure porte 7 lignes et 7 moyennes. La couverture est pleine presque partout, et l'heure où elle tombe est bien celle des 416 relevés critical que tu cites. Le garde-fou se déclenche donc rarement, et exactement quand il le faut.

count(moyenne_kw) et non count(*) est le bon compte : la 0016 filtre les critical dans l'agrégat, une ligne peut exister avec une moyenne nulle, et la compter comme couverte est précisément le trou. Le double qui écrivait sites: 7 à une requête qui en demandait six décrivait une base impossible — bien vu.

Deux notes, aucune bloquante.

La #201 que je viens d'ouvrir touche le même fichier dans la même famille de défauts : elle fait tomber consommation_kw à null quand la minute courante est une panne, donc mesures rétrécit et ton len(comparables) suit. Les deux se composent, il n'y a pas de conflit de logique. Je rebase la mienne sur la tienne.

Le tableau de bord n'a pas de rafraîchissement automatique (#196), donc une veille partielle affichera « pas de comparaison » jusqu'au prochain F5. C'est le bon comportement, je le note pour qu'on ne le lise pas comme un bug demain.

Bon pour moi.

Vérifié contre `enervision_prod` avant d'approuver, parce que le garde-fou peut couper une comparaison utile s'il est trop strict. Il ne l'est pas : ``` heure sites_couverts 2026-09-08 09:00:00+00 7 2026-09-08 08:00:00+00 2 2026-09-08 07:00:00+00 7 2026-09-08 06:00:00+00 7 ``` Le seau de la veille visé à cette heure porte 7 lignes et 7 moyennes. La couverture est pleine presque partout, et l'heure où elle tombe est bien celle des 416 relevés `critical` que tu cites. Le garde-fou se déclenche donc rarement, et exactement quand il le faut. `count(moyenne_kw)` et non `count(*)` est le bon compte : la 0016 filtre les `critical` dans l'agrégat, une ligne peut exister avec une moyenne nulle, et la compter comme couverte est précisément le trou. Le double qui écrivait `sites: 7` à une requête qui en demandait six décrivait une base impossible — bien vu. Deux notes, aucune bloquante. La #201 que je viens d'ouvrir touche le même fichier dans la même famille de défauts : elle fait tomber `consommation_kw` à `null` quand la minute courante est une panne, donc `mesures` rétrécit et ton `len(comparables)` suit. Les deux se composent, il n'y a pas de conflit de logique. Je rebase la mienne sur la tienne. Le tableau de bord n'a pas de rafraîchissement automatique (#196), donc une veille partielle affichera « pas de comparaison » jusqu'au prochain F5. C'est le bon comportement, je le note pour qu'on ne le lise pas comme un bug demain. Bon pour moi.
lenaic merged commit 9863205e6e into develop 2026-09-08 12:32:18 +00:00
lenaic deleted branch gabriel/179-couverture-veille 2026-09-08 12:32:18 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
g2/enervision!200
No description provided.