[44] Manuel de réentraînement : la séquence, la promotion, et « quand ça échoue » #187

Merged
lenaic merged 1 commit from olivier/44-runbook-reentrainement into develop 2026-09-08 10:35:27 +00:00
Member

Ferme le quatrième geste sensible d'ENF-16 : docs/runbooks/reentrainement.md, le seul des quatre qui n'existait pas. Déploiement, reprise et incident de collecte sont déjà là.

Ce que le manuel contient

  • La séquence d'entraînement sur le serveur : les trois contrôles préalables, la commande nominale, et le worktree pour faire tourner autre chose que ce que main porte.
  • La promotion et son garde-fou : la règle est du code (registre.decider_promotion, strictement mieux que la persistance ou rien). Le geste manuel — comparer deux versions, déplacer l'alias, revenir en arrière — reste le §5 de mlflow.md, auquel le manuel renvoie plutôt que de le recopier.
  • « Quand ça échoue » : les codes 2, 3 et 4 du lanceur, la promotion refusée hors enervision_prod, MLflow injoignable, et le modèle qui ne bat pas la persistance.

Sur ce dernier cas, ce que le manuel dit explicitement : il sort en code 0, ce n'est pas une panne, c'est un résultat. L'alias n'a pas bougé, donc il n'y a aucun geste de repli à faire — c'est l'intérêt du garde-fou. On consigne le chiffre, la fenêtre et la base, et on cherche pourquoi ensuite. Un manuel qui ne décrit que la promotion réussie laisse croire qu'un refus est une panne.

Deux modes de panne que le manuel nomme et qui n'étaient écrits nulle part :

  • MLflow injoignable ne sort en aucun des codes documentés — c'est une trace, code 1 — et elle tombe après la lecture, l'apprentissage et le tableau de comparaison. Le chiffre est donc acquis quand la publication échoue : le relire à l'écran avant de relancer. Le piège en amont : depuis un poste sous tunnel, le port local est 5001 et non 5000, et l'erreur ressemble à un registre à terre alors que c'est l'adresse qui est fausse.
  • mktemp: too few X's in template n'est pas un écart de modèle. Le lanceur que main porte échoue encore sur les coreutils GNU ; le correctif est dans develop.

Ce que ça corrige au passage

Le venv du serveur est /opt/enervision/venv, pas venv-model : suivre la lettre du README sortait en code 3 sur un chemin qui n'existe pas. Corrigé dans services/inference/README.md et dans l'en-tête du lanceur — sans quoi le manuel et le paquet se contrediraient, ce qui est pire que pas de manuel. Le README gagne aussi un renvoi vers le manuel, et l'index des runbooks sa ligne.

Ce qui n'est pas dans cette demande, et le manuel le dit

La dernière section liste ce qui n'a pas été rejoué sur le serveur — même règle que le §5 de mlflow.md, qui signale déjà sa propre commande non jouée :

Cas État
Entraînement nominal, code 3, --deux-passes identiques joués le 08/09/2026
Code 4 (deux passes qui diffèrent) jamais observé : une divergence OpenMP ne se provoque pas à la demande. La conduite est déduite du code, et c'est dit
Promotion refusée hors enervision_prod, MLflow injoignable, modèle qui ne bat pas la persistance à jouer — les trois sont provocables, chacun en une dizaine de minutes

Deux points de coordination

  1. L'assignation. Le ticket #44 est assigné à @gabriel, BACKLOG.md dit lenaic. J'écris ce manuel-ci parce que le critère 2 l'exige — « chacun est écrit par celui qui tient le geste » — et que le geste est celui du #36. À réassigner, ou à trancher au point du soir.
  2. Le critère 3 est déjà tenu, et pas par ce manuel : reprise.md, écrit par @gabriel et rejoué intégralement par @lenaic le 02/09/2026 en 9 min 51 s. Le ticket demande « au moins une procédure ». La relecture croisée de celui-ci reste à programmer avant le jour 8, comme le « Risque » du ticket le demande.

Une trouvaille qui mérite son propre ticket

Avec --deux-passes, --jusqu-a doit s'écrire avec le signe égal. Le lanceur ne reconnaît que cette forme pour figer les bornes ; passée en deux mots, la valeur file à Python, le lanceur croit n'en avoir aucune et ajoute la sienne — l'heure courante — qui l'emporte. Les deux passes restent comparables entre elles, donc le contrôle de rejouabilité reste valide, mais la fenêtre demandée est remplacée en silence. Le manuel documente le contournement ; --environnement a déjà un traitement explicite de la forme espacée, --jusqu-a mériterait le même. Correctif d'une ligne, mais c'est du code sur un ticket de documentation : je ne le fais pas ici.

Ferme le quatrième geste sensible d'ENF-16 : `docs/runbooks/reentrainement.md`, le seul des quatre qui n'existait pas. Déploiement, reprise et incident de collecte sont déjà là. ## Ce que le manuel contient - **La séquence d'entraînement** sur le serveur : les trois contrôles préalables, la commande nominale, et le worktree pour faire tourner autre chose que ce que `main` porte. - **La promotion et son garde-fou** : la règle est du code (`registre.decider_promotion`, strictement mieux que la persistance ou rien). Le geste manuel — comparer deux versions, déplacer l'alias, revenir en arrière — reste le [§5 de `mlflow.md`](../src/branch/develop/docs/runbooks/mlflow.md), auquel le manuel renvoie plutôt que de le recopier. - **« Quand ça échoue »** : les codes 2, 3 et 4 du lanceur, la promotion refusée hors `enervision_prod`, MLflow injoignable, et le modèle qui ne bat pas la persistance. Sur ce dernier cas, ce que le manuel dit explicitement : **il sort en code 0, ce n'est pas une panne, c'est un résultat.** L'alias n'a pas bougé, donc il n'y a aucun geste de repli à faire — c'est l'intérêt du garde-fou. On consigne le chiffre, la fenêtre et la base, et on cherche pourquoi ensuite. Un manuel qui ne décrit que la promotion réussie laisse croire qu'un refus est une panne. Deux modes de panne que le manuel nomme et qui n'étaient écrits nulle part : - **MLflow injoignable ne sort en aucun des codes documentés** — c'est une trace, code 1 — et elle tombe *après* la lecture, l'apprentissage et le tableau de comparaison. Le chiffre est donc acquis quand la publication échoue : le relire à l'écran avant de relancer. Le piège en amont : depuis un poste sous tunnel, le port local est 5001 et non 5000, et l'erreur ressemble à un registre à terre alors que c'est l'adresse qui est fausse. - **`mktemp: too few X's in template` n'est pas un écart de modèle.** Le lanceur que `main` porte échoue encore sur les coreutils GNU ; le correctif est dans `develop`. ## Ce que ça corrige au passage Le venv du serveur est `/opt/enervision/venv`, pas `venv-model` : suivre la lettre du README sortait en **code 3** sur un chemin qui n'existe pas. Corrigé dans `services/inference/README.md` et dans l'en-tête du lanceur — sans quoi le manuel et le paquet se contrediraient, ce qui est pire que pas de manuel. Le README gagne aussi un renvoi vers le manuel, et l'index des runbooks sa ligne. ## Ce qui n'est pas dans cette demande, et le manuel le dit La dernière section liste ce qui n'a pas été rejoué sur le serveur — même règle que le §5 de `mlflow.md`, qui signale déjà sa propre commande non jouée : | Cas | État | |---|---| | Entraînement nominal, code 3, `--deux-passes` identiques | joués le 08/09/2026 | | Code 4 (deux passes qui diffèrent) | **jamais observé** : une divergence OpenMP ne se provoque pas à la demande. La conduite est déduite du code, et c'est dit | | Promotion refusée hors `enervision_prod`, MLflow injoignable, modèle qui ne bat pas la persistance | **à jouer** — les trois sont provocables, chacun en une dizaine de minutes | ## Deux points de coordination 1. **L'assignation.** Le ticket #44 est assigné à @gabriel, `BACKLOG.md` dit `lenaic`. J'écris ce manuel-ci parce que le critère 2 l'exige — « chacun est écrit par celui qui tient le geste » — et que le geste est celui du #36. À réassigner, ou à trancher au point du soir. 2. **Le critère 3 est déjà tenu**, et pas par ce manuel : `reprise.md`, écrit par @gabriel et rejoué intégralement par @lenaic le 02/09/2026 en 9 min 51 s. Le ticket demande « au moins une procédure ». La relecture croisée de celui-ci reste à programmer avant le jour 8, comme le « Risque » du ticket le demande. ## Une trouvaille qui mérite son propre ticket Avec `--deux-passes`, **`--jusqu-a` doit s'écrire avec le signe égal.** Le lanceur ne reconnaît que cette forme pour figer les bornes ; passée en deux mots, la valeur file à Python, le lanceur croit n'en avoir aucune et ajoute la sienne — l'heure courante — qui l'emporte. Les deux passes restent comparables entre elles, donc le contrôle de rejouabilité reste valide, mais **la fenêtre demandée est remplacée en silence**. Le manuel documente le contournement ; `--environnement` a déjà un traitement explicite de la forme espacée, `--jusqu-a` mériterait le même. Correctif d'une ligne, mais c'est du code sur un ticket de documentation : je ne le fais pas ici.
docs: manuel de réentraînement, le quatrième geste d'ENF-16 (#44)
All checks were successful
Intégration / Tableau de bord — dépendances, tests et construction (pull_request) Successful in 35s
Intégration / Contrôles statiques du dépôt (pull_request) Successful in 6s
Intégration / Workflows — lint et audit de sécurité (pull_request) Successful in 17s
Intégration / Python — qualité, tests et dépendances (pull_request) Successful in 5m36s
ec99fd1ec5
Le README de services/inference/ décrit ce que le paquet fait ; un manuel
décrit ce qu'on tape quand ça part mal. docs/runbooks/reentrainement.md
reprend la séquence d'entraînement et la promotion — le geste manuel reste
le §5 de mlflow.md — et ajoute la section « Quand ça échoue » : les codes
2, 3 et 4 du lanceur, la promotion refusée hors enervision_prod, MLflow
injoignable, et le modèle qui ne bat pas la persistance.

Ce dernier cas sort en code 0 : ce n'est pas une panne, c'est un résultat.
Le manuel dit quoi faire — l'alias n'a pas bougé, donc il n'y a rien à
replier ; on consigne le chiffre, la fenêtre et la base, et on cherche
pourquoi ensuite.

Trois faits qui n'étaient écrits nulle part :

- le venv du serveur est /opt/enervision/venv et non venv-model. Suivre la
  lettre de l'ancien README sortait en code 3 sur un chemin inexistant. Le
  README et l'en-tête du lanceur sont corrigés ici, sinon le manuel et le
  paquet se contrediraient.
- « mêmes bornes » n'est pas « mêmes données » : mesure_horaire est un
  agrégat continu qui se complète en arrière — 10 283 puis 10 290 heures à
  dix minutes d'écart sur des bornes identiques. Sans ce fait, on cherche un
  non-déterminisme dans le régresseur alors qu'il est dans la base.
- avec --deux-passes, --jusqu-a doit s'écrire avec le signe égal. Le lanceur
  ne reconnaît que cette forme pour figer les bornes ; en deux mots, il
  ajoute la sienne, qui l'emporte, et la fenêtre demandée est remplacée en
  silence.

Le tableau final dit ce qui n'a pas été rejoué sur le serveur, comme le §5
de mlflow.md le fait déjà : le code 4 n'a jamais été observé et ne se
provoque pas à la demande, et trois cas restent à jouer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lenaic requested review from lenaic 2026-09-08 10:25:03 +00:00
lenaic approved these changes 2026-09-08 10:26:24 +00:00
lenaic left a comment

Approuvée. J'ai vérifié ce que le manuel affirme plutôt que de le lire :

registre.decider_promotion    existe, registre.py:99
codes du lanceur              2, 3, 4 et 0 posés là où le manuel les annonce
/opt/enervision/venv          existe
/opt/enervision/venv-model    n'existe pas

Le seul changement de code est la correction du chemin dans l'en-tête de entrainer.sh, venv-model vers venv. Elle est juste.

Le passage que je retiens est celui sur le refus de promotion : « il sort en code 0, ce n'est pas une panne, c'est un résultat ». Un manuel qui ne décrit que la promotion réussie laisse croire qu'un refus est un incident, et c'est exactement ce qui pousse quelqu'un à forcer l'alias à la main la veille d'une soutenance.

Le tableau des gestes en fin de manuel dit lesquels ont été joués et lesquels ont été observés. C'est la bonne distinction, et elle manque à la plupart de nos runbooks.

Deux notes, sans blocage.

Le code 3 sur venv-model est consigné comme observé le 08/09 « en suivant la lettre de l'ancien README ». C'est le même mécanisme que le rejeu de Justine sur le collecteur ce matin : une commande publiée qui ne pouvait pas marcher, trouvée en l'exécutant. Deux fois en une journée, ça mérite d'être dit au point du soir.

Et le manuel ne parle pas du critère de promotion lui-même, qui est en discussion sur le #36 : l'ADR 0013 dit trois jours, le modèle promu perd sur trois jours et a été promu sur quatorze. Ce n'est pas le sujet de ce manuel, mais le jour où la fenêtre change, la section « le modèle ne bat pas la persistance » changera de sens.

Approuvée. J'ai vérifié ce que le manuel affirme plutôt que de le lire : ``` registre.decider_promotion existe, registre.py:99 codes du lanceur 2, 3, 4 et 0 posés là où le manuel les annonce /opt/enervision/venv existe /opt/enervision/venv-model n'existe pas ``` Le seul changement de code est la correction du chemin dans l'en-tête de `entrainer.sh`, `venv-model` vers `venv`. Elle est juste. **Le passage que je retiens** est celui sur le refus de promotion : « il sort en code 0, ce n'est pas une panne, c'est un résultat ». Un manuel qui ne décrit que la promotion réussie laisse croire qu'un refus est un incident, et c'est exactement ce qui pousse quelqu'un à forcer l'alias à la main la veille d'une soutenance. Le tableau des gestes en fin de manuel dit lesquels ont été **joués** et lesquels ont été **observés**. C'est la bonne distinction, et elle manque à la plupart de nos runbooks. Deux notes, sans blocage. Le code 3 sur `venv-model` est consigné comme observé le 08/09 « en suivant la lettre de l'ancien README ». C'est le même mécanisme que le rejeu de Justine sur le collecteur ce matin : une commande publiée qui ne pouvait pas marcher, trouvée en l'exécutant. Deux fois en une journée, ça mérite d'être dit au point du soir. Et le manuel ne parle pas du critère de promotion lui-même, qui est en discussion sur le #36 : l'ADR 0013 dit trois jours, le modèle promu perd sur trois jours et a été promu sur quatorze. Ce n'est pas le sujet de ce manuel, mais le jour où la fenêtre change, la section « le modèle ne bat pas la persistance » changera de sens.
lenaic merged commit ed85ce0ab7 into develop 2026-09-08 10:35:27 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
g2/enervision!187
No description provided.