Skip to content

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.