Repository navigation
fix(ci,#17217): organe de fraicheur du catalogue + deblocage de la livraison quotidienne - #17221
Conversation
…vraison quotidienne Le README promet un catalogue regenere chaque jour. Le cron tient sa part -- huit runs `success` d'affilee -- mais il ne pousse pas sur `main` : il livre par une PR longue duree (#15942, `chore/catalog-refresh-pending`), et cette PR est BLOCKED depuis 8 jours. Le catalogue de `main` date donc du 09-12 : 83 entrees pointent un fichier inexistant, 301 notebooks reels sont absents, couverture reelle 77,7 % au lieu de 100 %. Personne ne le voyait : un cron qui reussit est silencieux, une PR ouverte est silencieuse, et un catalogue perime se lit exactement comme un catalogue a jour. La promesse vivait dans un commentaire, pas dans une mesure. Cause mesuree, qui refute le diagnostic inscrit dans le workflow (#11202, « a push with GITHUB_TOKEN never emits [a pull_request event] ») : les runs SONT emis. `gh run list --branch chore/catalog-refresh-pending` en rend 83, event `pull_request`, tous `action_required`. Ils ne sont pas absents, ils sont non approuves -- un run gare n'a jamais tourne, donc le check requis qu'il porte n'existe pas au head, et la PR reste BLOCKED sans qu'aucun rouge ne l'explique. Le remede n'est donc pas le « empty-commit wake-up » manuel que ce commentaire designait comme canonique. Trois gestes : - `scripts/ci/check_catalog_freshness.py` -- le temoin permanent. Mesure deux choses independantes parce qu'elles cassent separement : la divergence catalogue/arbre (hors-ligne), et l'etat de la livraison (age de la PR, runs gares AU HEAD COURANT). Fail-closed : un catalogue illisible rend 2, jamais 0. - `scripts/tests/test_check_catalog_freshness.py` -- 8 tests, controles positifs en tete. Dont celui qui garde la capacite a VERDIR : un run gare sur un head perime n'est pas impute, sinon l'organe reste rouge pour toujours une fois la panne reparee, et devient indiscernable d'un organe debranche. - `catalog-cron.yml` -- diagnostic corrige, et step `Release the parked runs` qui approuve les runs gares du head apres chaque poussee (`actions: write`, `continue-on-error`, avertissement nomme si le jeton ne peut pas approuver). Verification firsthand : les 16 runs gares du head 8b0cc5c ont ete approuves a la main ; au meme head, plus aucun `action_required` -- 6 success, 1 in_progress, 10 queued. Le mecanisme repond. See #17217 See #15942 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Grain tag obligatoire (#10045, bloquant).
Pour passer ce gate, le body doit porter en tete une ligne de la forme : Le |
…afflux qui a tue le gate Le step livre plus tot approuvait d'un coup TOUS les runs gares au head. Mesure du 2026-09-21, faite en approuvant 16 runs a la main sur #15942 : les checks sont restes `queued` 19 minutes sur un pool de runners deja sature, pendant lesquelles le job "PR gate" les a sondes toutes les ~31 s jusqu'a epuiser le quota du jeton d'INSTALLATION (HTTP 403, budget distinct de celui d'un jeton utilisateur) -- et il echoue fail-closed. Le step tel que livre aurait donc refabrique cet afflux a chaque passage quotidien du cron. Ce que change ce commit : - `RELEASE_STAGGER_SECONDS` (15 s) entre deux approbations. Le debit TOTAL est inchange -- ce qui baisse est le taux d'ARRIVEE, donc le nombre de runs simultanement en file pendant que le gate sonde. - `RELEASE_CEILING` (40) comme soupape, pas comme plafond de debit : au-dela, des runs s'empilent sans s'executer et approuver n'y repond pas. Le depassement est ECRIT (`::warning`), jamais silencieux -- un plafond tu se lit comme « tout a ete traite ». Pourquoi pas un plafond par passage : le cron pousse un commit neuf a chaque derive, donc le head change. Des runs « reportes au lendemain » seraient gares sur un head perime, que l'organe n'impute deja plus. Plafonner le debit casserait la convergence au lieu de l'etaler. Verifie : YAML parse, `bash -n` sur le bloc extrait, et controle positif du `\t` du jq (rend bien une tabulation reelle, que le `read` decoupe). See #17221 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
[ADJOINT PREFLIGHT] Verdict BLOCKED, cause nommee. 17 check-runs dedupliques par (started_at, id) au head b3ceedd (commit tardif inclus) : 9 pending, 1 rouge. Le rouge est |
|
Grain tag obligatoire (#10045, bloquant).
Pour passer ce gate, le body doit porter en tete une ligne de la forme : Le |
|
[ADJOINT PREFLIGHT] Verdict BLOCKED, 3 rouges nommes, 0 pending (les 9 checks en vol au cycle precedent se sont stabilises). (1) PR gate = failure : quota d'installation GitHub, echec de flotte. (2) Scripts Tests (CPU) = failure : abort natif herite de la base, corrobore par myia-po-2023 sur 7+ PRs. (3) Always-on guards -- 15 organes, 1 checkout = failure : rouge base-inherited, corroborated sur #17213/#17229/#17189 (imputations ecrites). mergeable=true, b0 rc=0. Ce qui leverait : disparition des rouges au prochain balayage. |
|
[ADJOINT PREFLIGHT] |
|
G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels |
|
[ADJOINT PREFLIGHT] |
|
[ADJOINT PREFLIGHT] |
Grain: MED/harness -- lane myia-ai-01:CoursIA -- paths: scripts/ci/check_catalog_freshness.py, scripts/tests/test_check_catalog_freshness.py, .github/workflows/catalog-cron.yml
Le problème
Le README promet un catalogue régénéré chaque jour. Le cron tient sa part — huit runs
successd'affilée, dont celui de ce matin. Mais il ne pousse pas surmain: il livre par une PR longue durée, #15942 (chore/catalog-refresh-pending), et cette PR estBLOCKEDdepuis 8 jours.Mesure sur
main(dc0ccbf) :Sur la branche de livraison, le même jour : 0 fantôme, 1240 entrées. La régénération était correcte depuis le début — c'est la livraison qui manquait.
Personne ne le voyait, et c'est le point : un cron qui réussit est silencieux, une PR ouverte est silencieuse, et un catalogue périmé se lit exactement comme un catalogue à jour. La promesse « eventual consistency, <24 h » vivait dans un commentaire de workflow, pas dans une mesure.
Le diagnostic inscrit dans le dépôt est réfuté par la mesure
catalog-cron.ymlportait, depuis #11202 :Les runs sont émis :
Ils ne sont pas absents, ils sont non approuvés. Un run
action_requiredn'a jamais tourné : le check requis qu'il porte n'existe pas au head — il n'est ni vert ni rouge, il manque. D'où unmergeStateStatus: BLOCKEDavec tous les checks visibles au vert, que rien n'explique quand on lit le rollup.Conséquence pratique : le remède désigné comme canonique par ce commentaire — le « empty-commit wake-up » manuel — visait la mauvaise cause. Le commentaire est corrigé dans le diff, avec la mesure qui le réfute.
Vérification firsthand
Les 16 runs garés du head
8b0cc5c1ont été approuvés à la main. Au même head, immédiatement après :Le mécanisme répond. #15942 finira de virer au vert sans autre geste.
Ce que dépose cette PR
scripts/ci/check_catalog_freshness.py— le témoin permanent. Il mesure deux choses indépendantes, parce qu'elles cassent séparément :.github/workflows/catalog-cron.yml— diagnostic corrigé, et un stepRelease the parked runs on the delivery branchqui approuve les runs garés du head après chaque poussée :actions: write,continue-on-error: true, et un::warningnommé si le jeton n'a pas le droit d'approuver. Le geste ne peut pas casser le cron ; s'il échoue, il le dit au lieu de laisser la PR pourrir en silence.Le contrôle qui porte la valeur des tests
Huit tests, contrôles positifs en tête — un garde qui ne peut pas échouer ne prouve rien quand il rend vert, et le cas nominal de ce garde est justement un vert.
Celui qui compte le plus est le contrôle de capacité à verdir :
Une PR longue durée accumule les heads : chaque régénération quotidienne en pousse un neuf, et les runs garés des anciens ne disparaissent jamais. Ma première version les comptait tous — elle aurait affiché « 83 garés » même une fois la panne réparée, donc un organe incapable de verdir, indiscernable d'un organe débranché, et qu'on aurait fini par ignorer. Seul le head courant porte les checks requis de la PR telle qu'elle est ; les autres sont comptés à part et non imputés.
Fail-closed également : un catalogue illisible rend
rc=2, jamaisrc=0— une mesure impossible n'est pas une mesure à zéro.Validation
Le test est dans
scripts/tests/, seul emplacement detestpathspour les organes descripts/ci/— je l'avais d'abord écrit dans unscripts/ci/tests/qui n'est pas collecté, où il n'aurait jamais tourné.Aucun notebook touché.
COURSE_CATALOG.generated.*non touché — byte-identique àmain.Non couvert par cette PR
scripts/ci/fast_lane_registry.py) : geste séparé, à poser advisory d'abord comme le reste de la famille. Cette PR dépose l'organe, elle ne le câble pas — le câbler bloquant aujourd'hui rougirait toutes les PRs tant que chore(catalog): scheduled auto-regenerate (long-lived PR) #15942 n'est pas mergée.Correctif
b3ceedda48— l'afflux que ce step fabriquaitLa première version de ce step approuvait d'un coup tous les runs garés au head. Mesuré le jour même, en approuvant 16 runs à la main sur #15942 : les checks sont restés
queued19 minutes sur un pool de runners déjà saturé, pendant lesquelles le jobPR gateles a sondés toutes les ~31 s jusqu'à épuiser le quota du jeton d'installation (HTTP 403) — et il échoue fail-closed.Le quota d'installation est un budget distinct de celui d'un jeton utilisateur : le mien lisait
5000/5000au même instant. Lire l'un pour conclure sur l'autre aurait donné le diagnostic inverse.L'échec de
PR gatesur #15942 n'est donc pas un défaut de cette PR-là, et le step tel que livré aurait refabriqué cet afflux à chaque passage quotidien du cron.RELEASE_STAGGER_SECONDS(15 s)RELEASE_CEILING(40), soupape et non plafond de débit::warningexplicite, jamais silencieuxPourquoi pas un plafond par passage. Le cron pousse un commit neuf à chaque dérive, donc le head change : des runs « reportés au lendemain » seraient garés sur un head périmé, que l'organe n'impute déjà plus (
parked_stale_heads). Plafonner le débit casserait la convergence au lieu de l'étaler — et un plafond tu se lit comme « tout a été traité », ce que cette PR existe précisément pour empêcher.Vérifié : parse YAML,
bash -nsur le bloc extrait, et contrôle positif dudujq— il rend bien une tabulation réelle (cat -A→^I), celle sur laquelle lereaddécoupe. Les trois constructions d'échappement avaient été dépliées par un heredoc à la rédaction ; sans ce contrôle, le step serait parti avec unjqcassé.See #17217
See #15942
See #11202
🤖 Generated with Claude Code