Skip to content

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 exige base_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é)
Le smoke prouve le câblage (run_q1 → fit_fn → verdict structuré, fail-loud) ; il ne fait pas un vrai fit (ADR-90).

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.