Le pipeline ML n'avait aucun test touchant PostgreSQL : `ml/README.md` le disait, faute de
base joignable en CI. Le marqueur `integration` de `ml/pyproject.toml` etait declare et porte
par zero test.
- `ml/tests/conftest.py` : deux fixtures d'acces a la base, jamais interchangeables.
`connexion_ml` annule sa transaction, `parc` valide ses ecritures parce que `run_scoring`
ouvre sa propre connexion et ne verrait rien d'autre. Garde sur le nom de base, marque uuid
sur chaque site, nettoyage dans l'ordre des cles etrangeres.
- `test_data_integration.py` : les neuf colonnes du contrat confrontees au schema Alembic
reel, la borne `since`, l'ordre de tri dont dependent des lags positionnels, et le typage
des colonnes entierement nulles.
- `test_score_integration.py` : les contraintes de `prediction` vues depuis le code qui
ecrit, l'empilement volontaire de deux runs, et `run_scoring` de bout en bout sur un
booster reel.
- `apps/backend/tests/test_chaine_ml_api.py` : lance les vrais binaires `enervision_ml.train`
et `.score` en sous-processus, comme les DAGs, puis relit par `GET /api/v1/predictions`.
Marqueur `chaine` distinct : le job `integration` du backend n'a pas l'environnement de ml/.
- `ml.yml` : job `integration`, seul du depot a reunir les deux environnements uv et une base.
Ses `paths` incluent les migrations du backend, sans quoi le schema deriverait du SQL du
pipeline sans que rien ne casse.
- Makefile : `migrate-test`, qui manquait (`enervision_test` n'a jamais recu de table),
`ml-test-integration` et `test-chaine`.
`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`.
Le document était référencé 11 fois, dont 4 depuis le code (config.py, data.py,
train.py, score.py, features.py), et n'avait jamais été écrit. Deux chemins
contradictoires coexistaient : `../ML-START.md` depuis ml/README.md et
docs/architecture/, `docs/ML-START.md` depuis le code. Le chemin retenu est celui
du code, majoritaire et le seul qu'un lecteur du module rencontre.
Il couvre les trois sections que les renvois annoncent : mécanisme d'accès aux
données et pourquoi ce n'est pas l'API, étapes d'un run de scoring, frontière
entre FastAPI et LightGBM.
Ferme C34 de la grille d'auto-évaluation.