Fiche de décision — XGBoost dans le gate s43 (r3 b)¶
Pour : opérateur · Date : 2026-06-05 · Story : CVN-N001-EI-S05 · Statut : ✅ DÉCIDÉE — Option A (exclure XGBoost), verrouillée sur le négatif confirmé. Une phrase : on teste fidèlement LightGBM et CatBoost, pas XGBoost (ses archives HPO n'enregistrent que des essais bruts, jamais ce qui a été déployé par cycle) → gate sur LGB+CB, XGBoost « non-évaluable ».
✅ Décision (2026-06-05)¶
Option A — exclure XGBoost, gater sur LightGBM + CatBoost. Verrouillée après vérification DIRECTE du négatif (§0bis sur le diagnostic lui-même) : on applique à XGBoost le même filtre par-cycle qui sort les sélections LGB/CB —
model_id='LightGBM_Direct_Sprint7' → 12 runs (UNIUSDC, ≤6/fenêtre = par-cycle)
model_id='CatBoost_Direct_Sprint7' → 10 runs (≤4/fenêtre = par-cycle)
model_id='XGBoost_Direct_Sprint7' → 0 runs ← le négatif, DIRECT
La décision repose donc sur le zéro du filtre direct (« existe-t-il une archive XGBoost par-cycle ? » → non), PAS sur une inférence depuis les 1927 essais Sprint3 (qui n'établirait que « XGB a du logging par-trial » — nécessaire-non-suffisant). XGBoost est noté « non-évaluable (archivage HPO par-trial, pas par-cycle) » partout — jamais un verdict « XGB non tradable ».
1. Le contexte, en clair (pourquoi on fait ça)¶
La question de l'Epic : le signal ML est-il vraiment tradable — gagne-t-il de l'argent net de frais, de façon fiable ?
s43 est le test qui tranche. La version r3 (b) pose la question d'une manière plus exigeante, et c'est important de comprendre pourquoi :
En production, on ne déploie pas un modèle figé. À chaque ré-entraînement, l'optimiseur d'hyperparamètres (HPO) re-choisit une config un peu différente (learning rate, profondeur…). Les chiffres le prouvent : pour un même crypto, le HPO a choisi des configs différentes d'un cycle à l'autre.
Donc « le signal est-il tradable ? » doit vraiment dire : « l'edge tient-il quelle que soit la config que le HPO tire ? » — parce que si ça ne marche que pour certaines configs chanceuses, la production (qui tire des configs semi-aléatoirement) ne le captera pas de façon fiable. C'est ça que le gate teste : il rejoue les configs que la prod a réellement sélectionnées et vérifie si l'edge survit à cette instabilité.
Pour faire ça, s43 a besoin de la liste des configs que la prod a sélectionnées — il les lit dans MLflow (notre archive d'entraînements).
2. Ce qu'on a découvert (la cause de la décision)¶
En lisant MLflow pour de vrai (read-only, avant tout merge), on a trouvé que les trois familles de modèles n'ont pas été archivées de la même façon :
| Famille | Ce que MLflow contient | Est-ce « ce que la prod a déployé » ? |
|---|---|---|
| LightGBM | 12 enregistrements / crypto, ~4 fenêtres de données distinctes | ✅ Oui — un best par cycle de déploiement. C'est exactement le bon objet. |
| CatBoost | 10 / crypto, ~4 fenêtres | ✅ Oui — pareil. |
| XGBoost | 1927 / crypto, jusqu'à 545 pour une seule fenêtre | ❌ Non — ce sont les essais bruts de la recherche HPO (l'optimiseur a testé 545 configs pour une fenêtre, on a tout loggé), pas « la config retenue à chaque cycle ». |
Pourquoi ça casse pour XGBoost : échantillonner ces 1927 essais, ce serait tester l'espace de recherche (y compris les centaines de configs rejetées par l'optimiseur) — pas ce que la prod déploie réellement. Ça répondrait à une autre question que celle de l'Epic. Et accessoirement : 1927 entraînements = absurde en temps de calcul.
Note technique : il n'existe pas d'archive XGBoost « par cycle » récupérable (l'XGBoost archivé vient d'un vieux sprint qui loggait chaque essai ; les LightGBM/CatBoost viennent d'un sprint plus récent qui logge proprement le best par cycle).
3. La décision à prendre¶
Que fait-on de XGBoost dans le gate ?
| Option | En quoi ça consiste | Coût | Risque |
|---|---|---|---|
| A — Exclure XGB (reco) | Le gate tourne sur LightGBM + CatBoost ; XGBoost est noté « non-évaluable (archivage HPO) », pas un verdict. Changement = une ligne de config (families=("lightgbm","catboost")), zéro code. |
Quasi nul | Le verdict couvre 2 familles sur 3. Si LGB et CB se contredisent, pas de 3ᵉ pour départager. |
| B — Investiguer XGB | Reconstruire « le best par cycle » XGB depuis les 1927 essais (meilleur essai par fenêtre). | Opérationnellement bloqué (≠ conceptuellement faux : le best-essai-par-fenêtre ≈ best-par-cycle) — les fenêtres XGB sont trop fragmentées (292 incohérentes) pour faire le regroupement essais→fenêtre→cycle de façon fiable. Voie de retour = re-lancer l'HPO XGB sous le logging Sprint7 (par-cycle). | retarde le merge ; chantier séparé hors S05 |
| C — Inclure XGB tel quel | Échantillonner les 1927 essais. | Élevé (calcul) | ❌ Faux scientifiquement — teste le mauvais objet. À écarter. |
4. Les enjeux (ce que chaque choix change pour la réponse finale)¶
Est-ce grave de tester 2 familles sur 3 ? Non — et encore moins que la 1ʳᵉ version de cette fiche ne le disait, pour deux raisons :
- Les trois familles sont des variantes GBDT (gradient-boosted decision trees) — pas trois classes d'algorithmes indépendantes, mais trois implémentations du même paradigme (boosting d'arbres, splits axis-aligned, biais inductifs très corrélés). XGBoost n'est donc pas un « 3ᵉ point de vue indépendant » mais un 3ᵉ point de vue corrélé à LGB/CB : son absence coûte encore moins d'information qu'un vrai 3ᵉ algo.
- Sous la règle « OR-pour-proceed » (le gate PASS si une famille est robuste-positive), retirer XGBoost rend le gate marginalement plus conservateur sur la dépense multi-fold — direction sûre : XGB-absent ne peut pas fabriquer un PASS spurious. Et le désaccord ne bloque pas le gate : LGB-PASS + CB-NOT → PASS (pas besoin d'un 3ᵉ pour départager au gate). Le « pas de tiebreaker » est un enjeu du verdict final, pas du gate — et là, un résultat famille-dépendant sur 2 familles est lui-même informatif, pas un deadlock.
- Inclure XGBoost (option C) serait pire que l'exclure : ça contaminerait le résultat avec le mauvais objet (l'espace de recherche au lieu du déploiement).
- Exclure XGBoost n'est pas cacher un problème : c'est constater que l'archivage HPO historique de XGBoost ne permet pas ce test (limite des données, pas un défaut de
s43) — noté explicitement, jamais un verdict « XGB non tradable ».
Borne du verdict (load-bearing — anti-sur-attribution, discipline S04)¶
Un verdict qui clôt (C_FRAGILE / C_GENERALISED_NOT_TRADEABLE) doit porter DEUX bornes, pas une :
1. Familles fidèlement évaluables = LGB + CB ; XGB « non-évaluable » partout. (la décision de cette fiche)
2. Classe GBDT — parce que les trois familles sont GBDT, même un LGB+CB+XGB ne dirait rien d'une famille non-GBDT (régression linéaire, réseau de neurones). Un négatif ne s'over-read pas en « le signal est mort pour tout modèle » ; il dit « pas d'edge net tradable pour les modèles GBDT ». Cette borne (2) tient indépendamment de la décision XGB — elle est ajoutée au catalogue de verdicts (runbook §4).
Ce que le verdict dira, selon l'option A :
- PASS (LGB ou CB robuste) → on dépense le test multi-fold cher (l'edge mérite d'être creusé).
- C_FRAGILE_TO_SELECTION → l'edge ne survit pas à l'instabilité du HPO → S05 se clôt observationnellement, sans dépenser plus.
- C_GENERALISED_NOT_TRADEABLE → pas d'edge net → route vers S06 (refonte features/cibles).
- (+ inconclusifs si sous-puissance.)
- XGBoost apparaît partout comme « non-évaluable », jamais compté dans le verdict.
5. Décision retenue¶
Option A — exclure XGBoost, gater sur LightGBM + CatBoost, XGBoost noté « non-évaluable (archivage HPO par-trial, pas par-cycle) ». Honnête, propre, et scientifiquement plus sûr (XGB est GBDT-corrélé, et son absence ne peut que rendre le gate plus conservateur).
Implémentation (pas « une ligne » naïve — vérifier que TOUT consommateur lit le tuple families) : EVALUABLE_FAMILIES = ("lightgbm","catboost") ; XGBoost surfacé en non_evaluable dans le verdict (visible, pas silencieusement absent) ; aucun « 3 familles » hardcodé (assertion-complétude, itération-familles, catalogue verdicts) — sinon passer à 2 lèverait un INCONCLUSIVE_TOOLING faux.
Si plus tard on veut XGBoost : re-lancer son HPO sous le logging Sprint7 (par-cycle) — chantier séparé, hors S05.
6. Après cette décision — ce qui reste avant le verdict¶
Cette décision débloque le merge. Ensuite, la barrière de validité (checklist §2bis du runbook) — surtout le coût réel mesuré (le signe du résultat en dépend) et les parquets fold-3 présents. Puis : merge → deploy → dry-run → run du gate. Aucun merge ni run sans ton go explicite.
Déjà résolus (read-only, ce tour) : schéma MLflow (corrigé + validé), complétude des params (LGB/XGB/CB complets), fidélité CatBoost
l2_leaf_reg(confirmée). La seule décision ouverte est XGBoost ci-dessus.