You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
CI routing : 32 des 124 workflows self-hosted n'ont AUCUN besoin local, dont pr-gate — un gate ne doit pas dependre du parc qu'il mesure #17397
Arbitrage user du 2026-09-22, verbatim : « Mon mandat, c'est d'équilibrer pour l'efficacité maximale (en se posant la question de quelle lane à quel endroit pour que le CI soit le plus performant et robuste) ».
Et la correction qui l'accompagne : le « mandat de consommer les runs conteneurisés » n'est pas un mandat user. Voir la section « Attribution fabriquée » plus bas.
Mesure
124 workflows ciblent self-hosted. Classés par ce dont ils ont réellement besoin (grep sur secrets.*, docker, cuda|gpu, lake|elan|mathlib, dotnet, papermill|jupyter|.ipynb, conda, wsl) :
L'argument de robustesse, qui pèse plus que celui de capacité
pr-gate.yml n'a aucun besoin local, et c'est l'organe qui décide si une PR est mergeable. Il tourne aujourd'hui sur le parc dont il est censé rapporter l'état.
Conséquence mesurée sur le cycle du 2026-09-22 : sur 80 candidates, 27 refusées pour rouge CI, et PR gate figure parmi les checks fautifs d'une vingtaine d'entre elles — alors que la cause était la saturation du parc. Quand le parc dégrade, l'organe qui le mesure dégrade en même temps, et la file qu'il devrait débloquer grossit exactement au moment où il en est le moins capable.
Le même fichier pr-gate-stale-sweep.yml le décrit déjà, sans en tirer la conséquence : « the waiters are held by the aggregators this sweep must unblock ». Le pool coursia-waiter — 28 slots (16 ai-01 + 12 po-2024) — existe presque uniquement pour héberger ces agrégateurs en long-poll, chacun occupant un slot 9 à 12 minutes pour interroger une API.
Sur ai-01, ces 16 waiters pèsent 16 processus Runner.Listener et 4 des 24 vCPU du budget CI — exactement la marge qui manque (cf. #17390 et la mesure de capacité : 24 demandés contre 24 accordés, zéro marge).
Principe proposé
Un job va sur self-hosted uniquement s'il a besoin de quelque chose qui n'existe que là. Tout le reste va sur GitHub-hosted. Et les organes qui gatent un merge y vont par exigence de robustesse, pas seulement de capacité : un gate ne doit pas dépendre du parc qu'il mesure.
Ce principe ne coupe aucune capacité. Il libère du self-hosted pour ce qui en a un besoin réel — notebooks, secrets, Lean, .NET, GPU — et rend les gates immunisés à la saturation locale.
Attribution fabriquée à corriger
pr-gate-stale-sweep.yml:116 porte : # GitHub-hosted stays out (mandat: consume the containerized runs; #12728.
Vérifié firsthand : #12728 ne contient ni le mot « mandat », ni « containerized », ni « hosted », ni dans son body ni dans ses commentaires. Elle argumente même l'inverse en esprit — router un workflow précis vers self-hosted pour fuir la file GitHub contendue de l'époque, en notant que « contre-intuitivement, ce ne sont pas les suites lourdes qu'il faut migrer en premier : ce sont les petits jobs fréquents dont la valeur s'effondre avec le délai ».
Deux défauts distincts, et le second est le plus coûteux :
un arbitrage lié à une mesure s'est durci en « mandat » ;
La phrase n'a essaimé nulle part ailleurs (1 seule occurrence dans tout le dépôt) : elle se corrige à peu de frais, maintenant.
Découpage proposé
Aucune de ces étapes ne réduit la capacité CI.
Étape 0 — corriger le commentaire fabriqué de pr-gate-stale-sweep.yml:116 (commentaire seul, zéro changement de comportement).
Étape 1 — router pr-gate.yml vers ubuntu-latest. C'est le plus fort ratio : aucun besoin local, agrégateur pur, et il découple le gate du parc qu'il mesure. Mesurer avant/après : délai run-created → job-started, durée totale, et occupation du pool coursia-waiter.
Étape 2 — si l'étape 1 tient, router les autres agrégateurs et sweeps sans besoin local (pr-gate-rerun, pr-gate-sweep-health-advisory, stale-guard-red-sweep, adjacency-stale-sweep).
Étape 3 — redimensionner coursia-waiter sur ai-01 une fois la charge réellement partie, et rendre le vCPU libéré à coursia-runner : c'est là que se crée la marge qui manque.
Étape 4 — les 27 restants des 32, au cas par cas, en vérifiant que le grep ne rate pas un besoin implicite (cache chaud, accès réseau interne, durée).
Limites de cette mesure — à ne pas surinterpréter
La classification est un grep sur le texte du workflow, pas une analyse d'exécution. Un workflow sans motif détecté peut avoir un besoin implicite : cache chaud, accès réseau interne, durée dépassant les limites GitHub-hosted. L'étape 4 existe pour ça ; les étapes 1-2 ne portent que sur des agrégateurs dont l'absence de besoin est lisible directement.
Le grep peut aussi sur-accuser : un docker cité en commentaire compte comme un besoin. Les 92 « avec besoin » sont donc un majorant, et les 32 un minorant — ce qui va dans le sens prudent.
Non mesuré : le coût GitHub-hosted en minutes pour un dépôt public, et les éventuelles limites de concurrence du plan. À vérifier avant l'étape 2.
Lane : myia-ai-01:CoursIA. Voir #17390 (double fetch du gate) et #17394 (contrat du cycle de merge) — même chantier de fiabilisation.
Mandat
Arbitrage user du 2026-09-22, verbatim : « Mon mandat, c'est d'équilibrer pour l'efficacité maximale (en se posant la question de quelle lane à quel endroit pour que le CI soit le plus performant et robuste) ».
Et la correction qui l'accompagne : le « mandat de consommer les runs conteneurisés » n'est pas un mandat user. Voir la section « Attribution fabriquée » plus bas.
Mesure
124 workflows ciblent
self-hosted. Classés par ce dont ils ont réellement besoin (grep sursecrets.*,docker,cuda|gpu,lake|elan|mathlib,dotnet,papermill|jupyter|.ipynb,conda,wsl) :Raisons de rester self-hosted, par fréquence :
notebook61 ·secrets36 ·lean11 ·docker8 ·dotnet8 ·wsl4 ·gpu4 ·conda3.Les 32 sans besoin local
adjacency-stale-sweep·catalog-cron·check-resync-only·concurrency-conj-guard·docs-link-check·exercise-leak-ci·fast-lane-shadow·harness-coauthor-guard·hooks-parity·ict-tests-profile·label-paths-guard·linux-runner-version-pin-advisory·machine-dep-timing-inventory·manifest-description-visuelle-gate·owui-playwright-check·perimeter-review-guard·pr-gate-rerun·pr-gate-sweep-health-advisory·pr-gate·pr-path-collision-advisory·qc-research-monitor·repeated-prose-advisory·repo-size-advisory·series-naming-gate·slides-composition-pr-relay·slow-lane·split-reading-advisory·stale-guard-red-sweep·testpaths-coverage-guard·translation-hot-drift-advisory·twin-parity-drift-audit·workflow-path-filter-auditL'argument de robustesse, qui pèse plus que celui de capacité
pr-gate.ymln'a aucun besoin local, et c'est l'organe qui décide si une PR est mergeable. Il tourne aujourd'hui sur le parc dont il est censé rapporter l'état.Conséquence mesurée sur le cycle du 2026-09-22 : sur 80 candidates, 27 refusées pour rouge CI, et
PR gatefigure parmi les checks fautifs d'une vingtaine d'entre elles — alors que la cause était la saturation du parc. Quand le parc dégrade, l'organe qui le mesure dégrade en même temps, et la file qu'il devrait débloquer grossit exactement au moment où il en est le moins capable.Le même fichier
pr-gate-stale-sweep.ymlle décrit déjà, sans en tirer la conséquence : « the waiters are held by the aggregators this sweep must unblock ». Le poolcoursia-waiter— 28 slots (16 ai-01 + 12 po-2024) — existe presque uniquement pour héberger ces agrégateurs en long-poll, chacun occupant un slot 9 à 12 minutes pour interroger une API.Sur ai-01, ces 16 waiters pèsent 16 processus
Runner.Listeneret 4 des 24 vCPU du budget CI — exactement la marge qui manque (cf. #17390 et la mesure de capacité : 24 demandés contre 24 accordés, zéro marge).Principe proposé
Ce principe ne coupe aucune capacité. Il libère du self-hosted pour ce qui en a un besoin réel — notebooks, secrets, Lean, .NET, GPU — et rend les gates immunisés à la saturation locale.
Attribution fabriquée à corriger
pr-gate-stale-sweep.yml:116porte :# GitHub-hosted stays out (mandat: consume the containerized runs; #12728.Vérifié firsthand : #12728 ne contient ni le mot « mandat », ni « containerized », ni « hosted », ni dans son body ni dans ses commentaires. Elle argumente même l'inverse en esprit — router un workflow précis vers self-hosted pour fuir la file GitHub contendue de l'époque, en notant que « contre-intuitivement, ce ne sont pas les suites lourdes qu'il faut migrer en premier : ce sont les petits jobs fréquents dont la valeur s'effondre avec le délai ».
Deux défauts distincts, et le second est le plus coûteux :
La phrase n'a essaimé nulle part ailleurs (1 seule occurrence dans tout le dépôt) : elle se corrige à peu de frais, maintenant.
Découpage proposé
Aucune de ces étapes ne réduit la capacité CI.
pr-gate-stale-sweep.yml:116(commentaire seul, zéro changement de comportement).pr-gate.ymlversubuntu-latest. C'est le plus fort ratio : aucun besoin local, agrégateur pur, et il découple le gate du parc qu'il mesure. Mesurer avant/après : délairun-created → job-started, durée totale, et occupation du poolcoursia-waiter.pr-gate-rerun,pr-gate-sweep-health-advisory,stale-guard-red-sweep,adjacency-stale-sweep).coursia-waitersur ai-01 une fois la charge réellement partie, et rendre le vCPU libéré àcoursia-runner: c'est là que se crée la marge qui manque.Limites de cette mesure — à ne pas surinterpréter
dockercité en commentaire compte comme un besoin. Les 92 « avec besoin » sont donc un majorant, et les 32 un minorant — ce qui va dans le sens prudent.Lane :
myia-ai-01:CoursIA. Voir #17390 (double fetch du gate) et #17394 (contrat du cycle de merge) — même chantier de fiabilisation.