Runbook (r1 — for review)
Runbook opérateur du diagnostic S14 — LightGBM output-validity. Comment déclencher le fit contrôlé Q1, lire le verdict, et dépanner. Réalise le plan r4 + architecture r1.
1. Quoi & quand le lancer¶
Quoi. Q1 teste, avant S09 et indépendamment du replay suspect, si le config/harness
LightGBM sait s'entraîner sur des données crypto à positif rare : early-stoppe-t-il à ~1 sur un plafond de
156 arbres, ou entraîne-t-il 156 arbres qui restent au prior ? Mesure le best_iteration réel (que prod
ne logge pas), l'AUPRC-lift, l'ECE equal-mass, + une ablation de la métrique d'early-stopping
pour localiser la cause.
Quand. Avant S09 (Q1 est moins cher + replay-indépendant) ; son verdict conditionne la lecture de
s43/S05. Q2 (rang/calibration sur le fold-3 replayé) ne tourne qu'après S09 et seulement si Q1 =
CONFIG_OK_LGB.
2. Prérequis (à vérifier AVANT le trigger)¶
| Prérequis | Vérification | Si KO |
|---|---|---|
| Fold de confiance RÉGIME-MATCHÉ | label = ATR0.5_1.5_H4 et base rate ±20 % du base rate s43 (~0.22) |
sinon la pathologie peut ne pas se déclencher → faux CONFIG_OK (garde regime_* → INCONCLUSIVE_TOOLING) |
| Feature store présent | cache.get_feature_store(crypto, tf) non vide pour la cellule |
seed/cache à corriger ; sinon INCONCLUSIVE_TOOLING(reason=dataprep) |
| base_env injecté (ADR-90) | la tâche validate_params du DAG FTF injecte CVN_TIMEFRAME + CVN_HPO_LGB_<TF>_* depuis ftf_config.base_env |
fit impossible hors in-pod (le harness fail-fast ADR-90) — c'est pourquoi Q1 est in-pod |
Draws best_params prod |
tirés de MLflow (CVNTrade_HPO, model_id LIKE LightGBM) |
sans draws → fit sur le seul recency |
| Deploy + DAG sync | image contient s14_* ; DAG diagnostic__s14_q1 visible (ADR-92 build=) |
attendre deploy (~10 min) / sync DAG (~7 min) |
2bis. La BARRIÈRE (in-pod, pas read-only)¶
Q1 n'est PAS read-only — c'est un petit fit instrumenté (+ un refit d'ablation), déclenché par l'opérateur via Airflow. La contrainte read-only a été levée pour Q1 seulement (§0bis : le read-only ne peut pas répondre avant S09 — prod ne logge ni val-métrique, ni
best_iteration, ni prédictions). Le fit réel exigebase_env(ADR-90) → in-pod uniquement. Localement, seul le wiring smoke tourne.
3. Déclenchement¶
3.A — Smoke local (wiring, sans cache/cluster)¶
PYTHONPATH=src python src/commun/finetune/diagnostic/s14_q1_fit_inpod.py --smoke
# -> SMOKE event=s14_q1_config_verdict verdict=INCONCLUSIVE_TOOLING reason=fit:... (no-crash prouvé)
3.B — Run décisionnel Q1 (in-pod, operator-triggered)¶
DAG diagnostic__s14_q1 (à créer — open item archi #1) wrappant run_inpod, OU exec direct dans un pod
scheduler (où base_env est injecté). Paramètres : crypto, timeframe, strategy=ATR0.5_1.5_H4,
fold_test_start/fold_test_end (fenêtre du fold de confiance régime-matché), draws (best_params prod),
s43_base_rate, es_metrics_ablation=("aucpr", …).
4. Catalogue des verdicts (Q1)¶
| Verdict | cause / reason |
Sens | Action |
|---|---|---|---|
CONFIG_DEGENERATE_LGB |
cause=early_stopping(eval_metric:…) |
best_iteration ≤ 3 ≪ plafond ; l'ablation montre qu'une autre métrique ES débloque |
bug trouvé sans S09 ; fix métrique/rounds ES (WA1) ; arm LGB de s43 contaminé à la source |
CONFIG_DEGENERATE_LGB |
cause=capacity/feature/label |
entraîne (best_iter ≈ plafond) mais AUPRC-lift ≈ hasard | investigation training/features plus profonde |
CONFIG_OK_LGB |
— (note: → Q2/S09 si s43 compressé) |
entraîne + AUPRC-lift > plancher | le config tient ; résidu fold-3/replay = Q2 (post-S09) ; sinon suspicion LGB levée |
INCONCLUSIVE_POWER |
— | IC de lift enjambe la frontière learn/not-learn | plus de draws/données/folds |
INCONCLUSIVE_TOOLING |
reason=preds\|labels\|leakage\|regime_label\|regime_base_rate\|dataprep\|fit |
input illisible / label mis-aligné / leakage / fold non régime-matché / fit échoué | corriger la cause + relancer |
5. Lire la sortie + decision routing¶
Output : event=s14_q1_config_verdict verdict=… cause/reason=… base_rate=… best_iteration=… ceiling=…
auprc_lift_med=… ece=… (+ artefact JSON). Lire d'abord best_iteration vs ceiling (156) — c'est le
smoking gun ; puis l'AUPRC-lift (en lift sur le base rate) ; l'ECE est equal-mass.
| Verdict | Routing aval |
|---|---|
CONFIG_DEGENERATE_LGB |
rouvrir l'arm LGB de s43 (contaminé à la source) ; fix selon la cause (WA1) ; datum EK GBDT provisoire. Ne dit pas « explique A6 » (underfit fait coïncider, pas diverger). |
CONFIG_OK_LGB |
si s43 montrait la compression → Q2/S09 (fold-3/replay-spécifique) ; sinon suspicion LGB levée (négatif utile) |
INCONCLUSIVE_* |
corriger (power → plus de données ; tooling → la reason) + relancer |
6. Observabilité (Loki)¶
event=s14_q1_datasets_built (n_train/val/test, base_rate, embargo) · s14_q1_draw_skipped (un draw KO
n'invalide pas la distribution) · s14_q1_config_verdict (le verdict). Requête : skill loki-query.
7. Troubleshooting¶
| Symptôme | Cause | Action |
|---|---|---|
fit:RuntimeError / Hyperparam … not in Console |
base_env ADR-90 non injecté |
lancer in-pod via le DAG FTF (pas localement) |
INCONCLUSIVE_TOOLING reason=regime_base_rate |
fold de confiance hors régime (base rate ≠ ±20 % s43) | choisir un fold/univers même régime d'imbalance |
INCONCLUSIVE_TOOLING reason=dataprep |
feature store vide / fenêtres de fold hors-range | vérifier le cache + les dates du fold |
INCONCLUSIVE_POWER |
trop peu de draws → IC large | élargir les draws/données |
smoke reason=fit:… |
attendu hors in-pod (ADR-90) | normal ; le smoke ne fait pas un vrai fit |
8. Réplication¶
Le verdict réel n'est pas un test CI. Slice A (decision core) : pytest
tests/unit/finetune/diagnostic/test_s14_lgb_output_validity.py (12/12). Slice B wiring : --smoke. Le vrai
fit + best_iteration : run in-pod §3.B (geste opérateur). Toute valeur décisionnelle (BEST_ITER_FLOOR,
RANK_MATERIAL, ECE_BAD, BASE_RATE_TOL) est figée dans le plan r4 / le module.