[EF-02] Rattrapage par lots de l'historique, conscient de l'état des capteurs #107

Closed
opened 2026-09-03 08:53:43 +00:00 by lenaic · 1 comment
Owner

Exigence couverte

EF-02, EF-05, ENF-06

Épreuve servie

EC05 · Data, ETL et BI

Charge estimée

2 j.h

Ce qu'on veut obtenir

Constituer l'historique de la zone bronze par lots, en complément de la collecte à la minute du #33. L'API expose GET /api/v1/readings pour ça, documenté comme servant à alimenter un pipeline ETL en batch, et l'historique remonte à plus d'un an.

C'est ce qui donnera au modèle de quoi s'entraîner sans attendre des semaines de collecte en direct. Le #36 en dépend plus que du collecteur.

Critères d'acceptation

  • Le lot interroge GET /api/v1/sensors/status avant chaque site et saute ceux dont le capteur consumption est en défaut : l'état courant d'un capteur s'applique à tout son historique, un site en panne rend une fenêtre entièrement nulle. Critère amendé le 3 septembre, il disait « saute ceux qui sont critical » ; le motif chiffré est en commentaire ci-dessous.
  • Le pas de temps est choisi explicitement : l'API rend limit points répartis sur la fenêtre demandée, donc une fenêtre de 24 heures avec limit=24 donne un point par heure. Le pas retenu est écrit dans le code, pas subi.
  • Les objets sont écrits sous endpoint=readings, jamais sous endpoint=current : les deux sources ne se mélangent pas, conformément à l'ADR 0005.
  • Rejouer la même commande deux fois ne crée aucun doublon. La clé porte les bornes de la fenêtre, et les bornes sont ancrées sur une grille et non sur l'heure du lancement. Critère précisé le 3 septembre : formulé « la même fenêtre », il était vrai des fonctions internes et faux depuis la ligne de commande, ce que la relecture d'Olivier a mis au jour.
  • Une fenêtre revenue entièrement nulle est marquée comme à rejouer et redemandée plus tard, jamais stockée comme vérité définitive ni jetée.
  • Les alertes de GET /api/v1/alerts sont ingérées et historisées, sans doublon après reprise.
  • Une exécution complète sur un an d'historique et sept sites est jouée, et le taux de points obtenus est mesuré.

Comment on le vérifie

Tests tests/unit/collector/test_batch.py, tests/integration/collector/
Commande la commande de rattrapage documentée, jouée deux fois sur la même fenêtre
Preuve le décompte d'objets bronze identique après le second passage, et le taux de points obtenus par site

Hors périmètre

La collecte à la minute, qui est le #33. Le lot ne peut pas rendre un point par minute : limit plafonne à 1000 et il en faudrait 1440 pour une journée.

### Exigence couverte EF-02, EF-05, ENF-06 ### Épreuve servie EC05 · Data, ETL et BI ### Charge estimée 2 j.h ### Ce qu'on veut obtenir Constituer l'historique de la zone bronze par lots, en complément de la collecte à la minute du #33. L'API expose `GET /api/v1/readings` pour ça, documenté comme servant à alimenter un pipeline ETL en batch, et l'historique remonte à plus d'un an. C'est ce qui donnera au modèle de quoi s'entraîner sans attendre des semaines de collecte en direct. Le #36 en dépend plus que du collecteur. ### Critères d'acceptation - [ ] Le lot interroge `GET /api/v1/sensors/status` avant chaque site et saute ceux dont le capteur `consumption` est en défaut : l'état courant d'un capteur s'applique à tout son historique, un site en panne rend une fenêtre entièrement nulle. **Critère amendé le 3 septembre**, il disait « saute ceux qui sont `critical` » ; le motif chiffré est en commentaire ci-dessous. - [ ] Le pas de temps est choisi explicitement : l'API rend `limit` points répartis sur la fenêtre demandée, donc une fenêtre de 24 heures avec `limit=24` donne un point par heure. Le pas retenu est écrit dans le code, pas subi. - [ ] Les objets sont écrits sous `endpoint=readings`, jamais sous `endpoint=current` : les deux sources ne se mélangent pas, conformément à l'ADR 0005. - [ ] Rejouer la **même commande** deux fois ne crée aucun doublon. La clé porte les bornes de la fenêtre, et les bornes sont ancrées sur une grille et non sur l'heure du lancement. **Critère précisé le 3 septembre** : formulé « la même fenêtre », il était vrai des fonctions internes et faux depuis la ligne de commande, ce que la relecture d'Olivier a mis au jour. - [ ] Une fenêtre revenue entièrement nulle est marquée comme à rejouer et redemandée plus tard, jamais stockée comme vérité définitive ni jetée. - [ ] Les alertes de `GET /api/v1/alerts` sont ingérées et historisées, sans doublon après reprise. - [ ] Une exécution complète sur un an d'historique et sept sites est jouée, et le taux de points obtenus est mesuré. ### Comment on le vérifie Tests tests/unit/collector/test_batch.py, tests/integration/collector/ Commande la commande de rattrapage documentée, jouée deux fois sur la même fenêtre Preuve le décompte d'objets bronze identique après le second passage, et le taux de points obtenus par site ### Hors périmètre La collecte à la minute, qui est le #33. Le lot ne peut pas rendre un point par minute : `limit` plafonne à 1000 et il en faudrait 1440 pour une journée.
lenaic self-assigned this 2026-09-03 08:53:43 +00:00
florian added this to the EnerVision project 2026-09-03 09:42:50 +00:00
Author
Owner

Le critère 1 est amendé, voici le chiffre qui le motive

Le critère disait « saute ceux qui sont critical ». Le code filtre sur le capteur
consumption et collecte donc aussi des sites degraded. L'écart est délibéré, et
Olivier a eu raison de demander qu'il figure ici plutôt que dans une demande de fusion.

Croisement de l'état annoncé et de ce que /readings rend réellement, 84 observations
des sept sites, le 3 septembre :

overall consumption des valeurs ? n
critical failing non 70
degraded failing non 7
critical ok non 3
ok ok oui 2
degraded ok oui 2

consumption: failing n'a jamais rien rendu, 77 fois sur 77. C'est un prédicteur
négatif parfait, et le seul filtre qui se justifie.

overall ne convient pas, pour deux raisons. Un site n'est ok que 1,8 % du temps
relevé sur 280 observations, contre 69,6 % critical et 28,6 % degraded — ce qui
condamnerait le rattrapage à ne presque jamais tourner. Et un site degraded dont la
consommation va bien rend des valeurs : le filtrer sur overall jetterait ces
fenêtres-là sans raison.

L'effet est mesuré, sur dix passes visant 49 fenêtres : 2 fenêtres écrites avec
l'ancien filtre, 9 avec celui-ci.

L'inverse n'est pas vrai pour autant, consumption: ok ne garantit rien : trois cas sur
sept n'ont rien rendu, un autre capteur en défaut suffisant à annuler la ligne. C'est le
critère 5 qui les rattrape — la fenêtre revenue sans aucune valeur est reportée, jamais
écrite comme vérité ni jetée.

Le critère 4 est précisé

Il disait « rejouer la même fenêtre ». C'était vrai des fonctions internes et faux
depuis la ligne de commande : les bornes étaient calées sur l'heure du lancement, donc
deux exécutions à une minute d'écart écrivaient deux jeux d'objets chevauchants. Corrigé,
et le critère dit désormais « la même commande », qui est ce qui compte pour cron.

Vérifié sur le serveur, deux passes de la même commande à 70 secondes d'écart :

passe 1 · bornes 2026-08-31T00:00:00.000Z à 2026-09-03T00:00:00.000Z
passe 2 · bornes 2026-08-31T00:00:00.000Z à 2026-09-03T00:00:00.000Z
         4 fenêtres écrites, 1 seule clé nouvelle

clés de la passe 1 disparues après la passe 2 : 0

Trois écritures sur trois, réécrites en place. La clé nouvelle vient d'un site redevenu
sain entre les deux passes, pas d'un décalage de la grille.

Le critère 7 reste ouvert

Il demande une exécution sur un an et sept sites avec le taux mesuré. Ce qui a été joué
porte sur trois jours. Le taux, lui, est déjà connu et il est bas : le simulateur bascule
ses capteurs toutes les trente secondes environ, et une passe n'attrape que les sites
sains à cet instant. Le rattrapage d'un an demandera donc plusieurs dizaines de passes,
et c'est ce que le manuel docs/runbooks/collecteur.md dit de faire.

### Le critère 1 est amendé, voici le chiffre qui le motive Le critère disait « saute ceux qui sont `critical` ». Le code filtre sur le capteur `consumption` et collecte donc aussi des sites `degraded`. L'écart est délibéré, et Olivier a eu raison de demander qu'il figure ici plutôt que dans une demande de fusion. **Croisement de l'état annoncé et de ce que `/readings` rend réellement**, 84 observations des sept sites, le 3 septembre : | `overall` | `consumption` | des valeurs ? | n | |---|---|---|---| | critical | failing | non | 70 | | degraded | failing | non | 7 | | critical | ok | non | 3 | | ok | ok | **oui** | 2 | | degraded | ok | **oui** | 2 | `consumption: failing` n'a **jamais** rien rendu, 77 fois sur 77. C'est un prédicteur négatif parfait, et le seul filtre qui se justifie. `overall` ne convient pas, pour deux raisons. Un site n'est `ok` que **1,8 % du temps** — relevé sur 280 observations, contre 69,6 % `critical` et 28,6 % `degraded` — ce qui condamnerait le rattrapage à ne presque jamais tourner. Et un site `degraded` dont la consommation va bien **rend des valeurs** : le filtrer sur `overall` jetterait ces fenêtres-là sans raison. **L'effet est mesuré**, sur dix passes visant 49 fenêtres : 2 fenêtres écrites avec l'ancien filtre, 9 avec celui-ci. L'inverse n'est pas vrai pour autant, `consumption: ok` ne garantit rien : trois cas sur sept n'ont rien rendu, un autre capteur en défaut suffisant à annuler la ligne. C'est le critère 5 qui les rattrape — la fenêtre revenue sans aucune valeur est reportée, jamais écrite comme vérité ni jetée. ### Le critère 4 est précisé Il disait « rejouer la même **fenêtre** ». C'était vrai des fonctions internes et faux depuis la ligne de commande : les bornes étaient calées sur l'heure du lancement, donc deux exécutions à une minute d'écart écrivaient deux jeux d'objets chevauchants. Corrigé, et le critère dit désormais « la même **commande** », qui est ce qui compte pour cron. **Vérifié sur le serveur**, deux passes de la même commande à 70 secondes d'écart : ``` passe 1 · bornes 2026-08-31T00:00:00.000Z à 2026-09-03T00:00:00.000Z passe 2 · bornes 2026-08-31T00:00:00.000Z à 2026-09-03T00:00:00.000Z 4 fenêtres écrites, 1 seule clé nouvelle clés de la passe 1 disparues après la passe 2 : 0 ``` Trois écritures sur trois, réécrites en place. La clé nouvelle vient d'un site redevenu sain entre les deux passes, pas d'un décalage de la grille. ### Le critère 7 reste ouvert Il demande une exécution sur un an et sept sites avec le taux mesuré. Ce qui a été joué porte sur trois jours. Le taux, lui, est déjà connu et il est bas : le simulateur bascule ses capteurs toutes les trente secondes environ, et une passe n'attrape que les sites sains à cet instant. Le rattrapage d'un an demandera donc plusieurs dizaines de passes, et c'est ce que le manuel `docs/runbooks/collecteur.md` dit de faire.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
g2/enervision#107
No description provided.