Runbook (r1 — for review)
Runbook opérateur du diagnostic s18 replay-fidelity (S09). Comment le déclencher, lire le verdict, et dépanner. Réalise la règle pré-enregistrée du plan r4 + architecture r2. Statut : pré-implémentation — les noms de DAG/params sont la cible de l'archi (à figer à l'impl).
1. Quoi & quand le lancer¶
Quoi : vérifie, indépendamment d'un run diagnostic, (A) que le replay s18 est déterministe
(cross-process, même seed) et (B) qu'il correspond au f1_buy canonique de la prod, à epsilon près.
Rend un verdict qui nomme la cause (instabilité / gap logique / artefact d'environnement).
Quand :
- pour lever l'astérisque A6 sur un verdict diagnostic basé s18 (dont S05/s43) ;
- comme précondition au passage de skip_phase_a=true en défaut ;
- en nightly (surveillance de fidélité) une fois stabilisé.
Deux jobs distincts (cadences différentes — archi #4) :
1. D0 — diagnostic__s18_eps_prod : caractérise ε_prod (rare ; seulement au changement d'image prod).
2. Verdict — diagnostic__s18_replay_fidelity : le check de fidélité par cellule (à la demande / nightly).
2. Prérequis (à vérifier AVANT le trigger)¶
| Prérequis | Vérification | Si KO |
|---|---|---|
| Provenance canonique persistée (P0) | finetune_results (ou table annexe) porte, pour la cellule de référence : build_sha, instance_type, versions features/libs |
INFEASIBLE-until-schema — la persistance de provenance ship d'abord (archi #2). Sans elle : P0 = unverifiable → INCONCLUSIVE_TOOLING partout |
ε_prod mesuré + frais |
le store ε_prod a une valeur pour le SHA image prod courant |
lancer D0 (diagnostic__s18_eps_prod) d'abord. Sinon : verdict INCONCLUSIVE_TOOLING reason=epsilon_prod_unmeasured |
| Canonique présent | query_canonical_from_pg retourne une ligne pour (crypto, fold-3) |
INCONCLUSIVE_TOOLING reason=canonical_absent |
| Deploy à jour | Deploy to Scaleway K8s SUCCESS sur le SHA qui contient le module s18-replay-fidelity |
attendre le deploy (~10 min post-merge) |
| DAG synchronisé | diagnostic__s18_replay_fidelity visible dans l'UI + bannière build=<sha> (ADR-92) |
attendre la sync DAG-repo (~7 min) |
2bis. La BARRIÈRE de validité (avant un verdict décisionnel)¶
Le verdict décisionnel (
FIDELITY_OK/CANONICAL_DIVERGENCE) est gaté tant que ces trois ne sont pas vrais (mirror du gate coût de s43). Le smoke (machinerie) peut tourner sans.
- Provenance P0 disponible des deux côtés (replay et canonique) — sinon P0
unverifiable. ε_prodmesuré sous la config réelle prod (un-capped), clé = SHA image prod courant.- Config déterministe replay posée au bon moment (archi §2bis) —
PYTHONHASHSEED+ thread caps au spawn ; flags LightGBM au train. Un replay « cru épinglé mais pas épinglé » fausse H1.
3. Déclenchement¶
3.A — D0 diagnostic__s18_eps_prod (rare, si ε_prod stale)¶
{
"crypto_group": "defi_top5",
"fold_id": 3,
"n_runs": 10,
"prod_config": true,
"tolerance": "0.95/0.95"
}
prod_config=true → re-runs sous la config réelle prod (un-capped) — pas §3.C.
- Écrit ε_prod (borne de tolérance unilatérale) keyé par le SHA image prod dans le store.
- Pod dédié (un-capped) — ne pas co-scheduler avec le verdict job.
3.B — Verdict diagnostic__s18_replay_fidelity¶
- cells=all → les 5 cellules (classification de cause ; 1 cellule = smoke/H1 wiring).
- parallel_replays → A∥B (≈2× CPU, moitié wall-clock) vs séquentiel (1 CPU). Aucun impact déterminisme
(cappé) — choix sizing/latence (archi §8bis).
- Lit ε_prod du store (par SHA image prod) ; ne le re-mesure jamais.
4. Catalogue des verdicts¶
| Verdict | cause / reason |
Sens |
|---|---|---|
FIDELITY_OK |
— | P0 parité + H1 PASS + \|replay−canonique\| ≤ ε. Replay indiscernable du canonique. |
NON_DETERMINISTIC |
cause=numeric_residue |
H1 FAIL mais det_delta ≤ ε_num → résidu numérique sous config épinglée (pas une vraie instabilité). |
NON_DETERMINISTIC |
cause=real_instability |
H1 FAIL, det_delta > ε_num → vraie instabilité (seed/ordre/fenêtre/threads). |
CANONICAL_DIVERGENCE |
cause=logic_fidelity_gap |
H1 PASS + P0 equal + > ε → vrai gap de fidélité (env contrôlé). |
CANONICAL_DIVERGENCE |
cause=env_parity_gap |
H1 PASS + P0 differs + > ε → divergence attribuée à l'env/version, pas à la logique. |
INCONCLUSIVE_TOOLING |
reason=replay_error |
replay ERROR / NaN. |
INCONCLUSIVE_TOOLING |
reason=canonical_absent |
pas de canonique en PG. |
INCONCLUSIVE_TOOLING |
reason=epsilon_prod_unmeasured |
ε_prod non mesuré pour le SHA prod courant → lancer D0. |
INCONCLUSIVE_TOOLING |
reason=env_parity_unverified |
P0 unverifiable (dimension non enregistrable) → corriger la provenance. |
Désambiguïsation clé :
logic_fidelity_gap(le replay est infidèle) vsenv_parity_gap(les environnements diffèrent — re-générer le canonique sous image parité avant de conclure à l'infidélité). L'ordre de décision est H1 → P0 → H2 : une divergence sous P0≠equal n'est jamais un gap logique.
5. Lire la sortie + decision routing¶
Output (artefact JSON + event=s18_replay_verdict) : verdict, cause/reason, cell, det_delta,
canon_delta, epsilon, ε_num, ε_prod + eps_prod_image_sha, parity_state, parity_dims,
provenance replay et canonique, canonical_run_id (schéma complet : archi §6).
| Verdict | Action |
|---|---|
FIDELITY_OK (sur la surface couverte) |
lever A6 pour cette surface ; autoriser skip_phase_a=true par défaut seulement dessus |
NON_DETERMINISTIC (real_instability) |
corriger seed/ordre/fenêtre/threads avant tout claim de fidélité ; A6 reste |
NON_DETERMINISTIC (numeric_residue) |
résidu sous config épinglée → enquêter libs/SIMD ; pas une instabilité de logique |
CANONICAL_DIVERGENCE (logic_fidelity_gap) |
diagnostiquer la cause (carte de contrôle _replay_cell) ; borne les verdicts s18 (dont S05) ; feeder D2/EK |
CANONICAL_DIVERGENCE (env_parity_gap) |
re-générer le canonique sous une image parité (ou matcher l'env) — pas un fix de logique |
INCONCLUSIVE_TOOLING |
corriger la cause reason (§4) + relancer |
Prior (plan §1) : vu A6 (deltas 0.1–0.3 ≫ ε), l'issue attendue est
CANONICAL_DIVERGENCE— H1 est un prérequis rapide pour écarter « c'est du bruit ». L'effort va à la carte de surface de contrôle de_replay_cell(env / ordre LdP / fenêtre / version artefact).
6. Observabilité (Loki)¶
| Event | Quand | Sévérité |
|---|---|---|
s18_replay_determinism status=PASS\|FAIL\|ERROR abs_delta_runs=… |
chaque cellule (zéro trou) | info / warn |
s18_replay_determinism_cause cause=… |
sur H1 FAIL | warn (lisible sans parser l'artefact) |
s18_replay_divergence abs_delta=… parity_state=… |
sur le chemin H2 | info / warn |
s18_replay_verdict verdict=… cause=… reason=… |
tout verdict | info |
Requête : loki-query skill (event=s18_replay_verdict, fenêtre du run). Le verdict JSON est aussi dans
artifact_dir.
7. Troubleshooting¶
| Symptôme | Cause probable | Action |
|---|---|---|
INCONCLUSIVE_TOOLING reason=epsilon_prod_unmeasured partout |
D0 jamais lancé pour le SHA prod courant | lancer diagnostic__s18_eps_prod (§3.A) |
INCONCLUSIVE_TOOLING reason=env_parity_unverified partout |
provenance canonique absente du schéma (archi #2) | schema first ; ne pas forcer |
NON_DETERMINISTIC systématique avec det_delta minuscule |
config §3.C non posée au spawn (numpy importé avant les caps) | vérifier l'injection env au spawn (archi §2bis), pas dans le worker |
| une cellule manque, les autres OK | échec partiel de pod | cette cellule = INCONCLUSIVE_TOOLING ; relancer la cellule (pas de collapse silencieux du pool) |
| verdict émis mais provenance canonique vide dans l'artefact | query_canonical_from_pg ne surface pas les colonnes P0 |
corriger la requête/le schéma (archi #2) |
8. Réplication¶
Le verdict réel n'est pas un test CI (plan §8 / test-strategy §12). Pour rejouer : déclencher §3.B sur
la cellule, lire s18_replay_verdict + l'artefact JSON. Pour rejouer la caractérisation ε_prod :
§3.A (N≥10, prod_config). Toute valeur décisionnelle (ε_num, ε_prod, seuils) est dans le plan r4.