Commit Graph
7 Commits
Author SHA1 Message Date
Dorian b00c39277b fix(backend,airflow,ml): cloture la reconciliation entre les deux sources de lectures (#15) 2026-09-23 14:45:38 +02:00
Johan LEROY 314e3b72c0 fix(ml,backend): corrige la revue, le typage du drapeau CSV et la portée du biais
`load_from_csv` gardait un `astype(bool)` sur `is_working_hours`, joué avant `_typer` :
une case vide du CSV arrivait en `NaN` et en ressortait `True`, soit une heure ouvrée
inventée. Le chemin base était corrigé, pas celui-ci, et rien ne le couvrait. La ligne
disparaît, et `_typer` ramène désormais les colonnes de `FLAG_COLUMNS` à `float64` quel
que soit le contenu lu : sans cela le dtype dépendait de l'écriture du fichier (`0`/`1`
contre `True`/`False`) et de la présence d'un trou, et l'égalité de schéma entre les deux
chargeurs que promet ML-START n'était vraie que par accident du jeu de test.

`Seuils.seuil_biais` valait `0` et `_verdict` exigeait `> 0` : la règle était inerte
partout, CLI et DAG compris, et aucun test ne l'exerçait. Elle reste désactivée par
défaut, parce qu'un seuil en kWh ne se transpose pas d'un bureau de 10 kWh à une usine
de 1 000 kWh et qu'aucune valeur n'a été calibrée sur la vraie série, mais `--bias-threshold`
la rend atteignable et l'ADR 0011 porte l'arbitrage. Trois tests couvrent le chemin :
inerte par défaut, dérive au-delà du seuil réglé, et priorité de la MAE sur le biais.

Deux lignes de doc devenues fausses au passage : la signature de `load_recent_from_database`
dans ML-START, qui omettait `until` devenu obligatoire, et la ligne `bias` de 20-backend,
qui laissait croire que la métrique décide du verdict.
2026-09-22 16:25:02 +02:00
Johan LEROY cb961ec2c5 fix(ml): borne la fenetre de scoring a l'instant demande, pour que --now rejoue l'historique
`load_recent_from_database` n'avait qu'une borne basse. `build_scoring_frame` repartait donc de
la derniere lecture de toute la table quel que soit `--now` : `target_at` valait toujours
"fin du jeu + 1h", et `_age = instant - derniere_lecture` devenait negatif, ce qui passait le
seuil de peremption sans rien signaler.

Consequence concrete : sur le jeu historique, arrete au 31/12/2024, aucune boucle de rattrapage
ne pouvait produire une prevision dont le realise existe deja. La surveillance de derive livree
par la migration precedente n'aurait donc rien eu a comparer en demonstration.

`until` est desormais obligatoire sur ce chargeur, ce qui interdit de l'oublier, et le mode CSV
filtre symetriquement. En exploitation rien ne change, aucune lecture n'etant posterieure a
l'heure courante.
2026-09-22 14:29:03 +02:00
Johan LEROY 5b5c97532d fix(ml): type is_working_hours pour que LightGBM accepte une lecture sans valeur
`reading.is_working_hours` est nullable et fait partie des features. Une seule lecture a
NULL dans la fenetre suffisait a rendre la colonne `object` au retour de `pd.read_sql`, et
LightGBM refuse alors de construire son Dataset : "pandas dtypes must be int, float or
bool". La panne n'arrivait qu'au scoring, sur la vraie base, jamais en test.

`_typer` coerce donc aussi cette colonne, comme les colonnes mesurees : NaN vaut valeur
manquante, que LightGBM gere nativement. Effet de bord voulu, les deux chargeurs rendent
enfin le meme dtype : `load_from_csv` faisait un `astype(bool)` qui ecrasait silencieusement
une valeur absente en `False`.
2026-09-22 14:10:35 +02:00
Dorian eb4291b10a fix(ml,backend,frontend): borne la peremption des predictions et isole les erreurs par flux 2026-09-18 14:58:39 +02:00
Dorian e9376a98bf feat(ml,backend): implemente le service de scoring et GET /predictions (#37) 2026-09-18 11:06:04 +02:00
Dorian 4f69199734 feat(ml): initialise le pipeline d'entrainement LightGBM (ADR 0005)
ML / Lint, typage et tests (push) Successful in 2m2s
2026-09-17 14:12:26 +02:00