Skip to content

feat(ci,#13378): superviseur N-slots — le plafond de 1 job du runner ephemere est ce qui empechait tout debrayage - #14126

Merged
myia-ai-01 merged 2 commits into
mainfrom
feature/13378-linux-runner-supervisor
Sep 1, 2026
Merged

myia-ai-01 merged 2 commits into
mainfrom
feature/13378-linux-runner-supervisor

Conversation

@myia-ai-01

Copy link
Copy Markdown
Collaborator

Grain: MED/tooling — lane myia-ai-01:CoursIA — prev: MED/tooling #14086

Déclaration franche sur les gates : deux MED/tooling consécutifs. G-VAR-3 l'autorise pour une substance genuinement distincte — #14086 corrigeait un repli aveugle du stale-sweep, celle-ci écrit un superviseur de conteneurs runner : rien de commun, et aucune des deux n'est générable en scannant l'instance d'à-côté. Mais tooling est un genre META : cette PR ne tient pas mon plancher G-VAR-1, et je ne prétends pas le contraire.

Ce que cette PR ferme

Le volet Linux du chantier runners (#13378) était resté en pleine conception. Le Dockerfile et l'entrypoint.sh étaient écrits, corrects, relus — et l'image n'avait jamais été construite. Surtout, la question que le census #13378 avait lui-même nommée comme « LE facteur limitant du §1, pas la compatibilité des workflows » n'avait aucune réponse : le cycle mono-job du runner --ephemeral.

Un docker run isolé plafonne la concurrence à 1 job. À 1 job, rien n'est débrayé — les 121 définitions ubuntu-latest continuent de se disputer le plafond de concurrence partagé au niveau du compte, qui est précisément ce qui affame roo-extensions.

supervise.sh lève ce plafond : un slot = une boucle qui relance un conteneur dès que le précédent meurt, N slots = N jobs concurrents. C'est toute la différence d'avec le service Windows — là-bas chaque ré-enregistrement est une tâche planifiée à orchestrer ; ici c'est un docker run de plus, gratuit et parallélisable.

Trois points de conception

  • La boucle vit sur l'hôte, jamais dans l'image. Le registration token vaut 1 h et est jetable : il en faut un neuf à chaque démarrage. Le fetch exige gh admin, et ces credentials ne descendent jamais dans le conteneur — qui ne reçoit que le token par -e, comme l'exige déjà entrypoint.sh (token jamais en argv).
  • Arrêt gracieux par sentinel. Plus aucun conteneur lancé, mais le job en cours va à son terme. Tuer un job en vol rendrait un rouge qui ne veut rien dire.
  • N appartient à po-2024. Défaut 2, volontairement bas. La clause de souveraineté de l'hôte (workstation GPU + interactive) prime sur tout élargissement, et survit à cette PR.

Ce que la doc affirmait, et qui était faux

docs/ci/self-hosted-runners.md décrivait la conception comme un état déployé. L'inventaire GitHub firsthand du 2026-09-01 (mesuré par po-2024) dit autre chose :

Attendu à la lecture de la doc Mesuré
runner Linux conteneurisé actif aucun — le dépôt a un seul runner, myia-po-2024-fast-guards, qui est Windows
label coursia-linux porté porté par personne
image coursia-linux-runner:2.336.0 jamais construite

Conséquence : linux-self-hosted-tests.yml cible un label orphelin. Un dispatch mettrait le job en file indéfiniment — pas d'échec, pas de rouge, une attente muette qu'aucun timeout-minutes ne coupe (il ne court qu'à partir du démarrage du job). Le piège est dormant aujourd'hui — 0 run en file, vérifié — et cesse de l'être au premier dispatch. L'en-tête du workflow porte désormais la précondition et la commande d'une ligne qui la teste (sortie vide = ne pas dispatcher).

C'est ma propre erreur en amont : j'avais tranché le design-gate #13378 en m'appuyant sur cette page, donc sur une conception que je lisais comme un déploiement.

Ce qui n'est pas un blocage

manage_self_hosted_runner.py est Windows-only par validation (« must pin an official Windows x64 archive ») : il ne peut pas porter un profil Linux. Ce n'est pas la condition du débrayage — supervise.sh fonctionne sans lui et sans PR préalable. L'étendre aux profils Linux est un suivi.

Ce que cette PR ne prouve pas

Aucun job n'a encore tourné sur un conteneur Linux. Tant que la preuve d'identité (RUNNER_OS = Linux dans les logs) n'est pas rendue, aucun vert de cette chaîne ne prouve le routage — leçon po-2024 du run 33178577527, où l'échec s'était produit pour la mauvaise raison (ACE manquante sur C:\CoursIA-Runners) et aurait pu passer pour un succès. La bascule des jobs ubuntu-latest reste gelée jusqu'à cette preuve et à la mesure d'empreinte par po-2024.

Aucun job déclenché par pull_request ne passe en self-hosted tant que #13897 ou #13947 (garde fork, #13874) n'est pas vert — le dépôt est public et ~95 forks étudiants existent.

See #13378

…ises

Le volet Linux du chantier runners etait reste en pleine conception :
Dockerfile et entrypoint ecrits et corrects, image jamais construite,
et surtout AUCUNE reponse a la question que le census #13378 avait
pourtant nommee comme LE facteur limitant -- le cycle mono-job du
runner --ephemeral.

Un `docker run` isole plafonne la concurrence a 1. A 1 job, rien n'est
debraye : les 121 definitions ubuntu-latest continuent de se disputer
le plafond de concurrence partage du compte, qui est ce qui affame
roo-extensions.

supervise.sh leve ce plafond. Un slot = une boucle qui relance un
conteneur des que le precedent meurt ; N slots = N jobs concurrents.
C'est toute la difference d'avec le service Windows, ou chaque
re-enregistrement est une tache planifiee a orchestrer : ici c'est un
`docker run` de plus, gratuit et parallelisable.

Trois points de conception :

- La boucle vit sur l'HOTE. Le registration token vaut 1 h et est
  jetable, il en faut un neuf par demarrage de conteneur ; le fetch
  exige gh admin, et ces credentials ne descendent jamais dans le
  conteneur -- qui ne recoit que le token par -e, comme l'exige deja
  entrypoint.sh.
- Arret gracieux par sentinel : plus aucun conteneur lance, le job en
  cours va a son terme. Tuer un job en vol rendrait un rouge qui ne
  veut rien dire.
- N par defaut = 2, volontairement bas, et appartient a po-2024. La
  clause de souverainete de l'hote prime sur tout elargissement.

Corrige aussi ce que la doc affirmait. Elle decrivait la conception
comme un etat deploye ; l'inventaire GitHub du 2026-09-01 montre un
seul runner enregistre sur le depot, `myia-po-2024-fast-guards`, qui
est Windows. Aucun runner ne porte `coursia-linux`. Le pilote cible
donc un label ORPHELIN : un dispatch mettrait le job en file
indefiniment -- pas d'echec, pas de rouge, une attente muette
qu'aucun timeout ne coupe (timeout-minutes ne court qu'a partir du
demarrage). Le piege est dormant aujourd'hui (0 run en file, verifie),
plus des qu'on dispatche. L'entete du workflow porte desormais la
precondition et la commande qui la teste.

Le gestionnaire n'est pas un blocage : manage_self_hosted_runner.py
est Windows-only par validation, mais supervise.sh fonctionne sans lui
et sans PR prealable. L'etendre aux profils Linux est un suivi.

See #13378
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
La lane `myia-ai-01:CoursIA` voit ces signaux actifs sur les mergees du jour (UTC 2026-09-01) :

  • TIER-INFLATION : declared LIGHT << effective LIGHT-genre (tally : declared=0 genre=4 cap=2)
  • GENRE-RUN : run consecutif d'un genre LIGHT (voir signals.runs dans le log du job)
  • CAP-EXCEEDED-BY-GENRE : light_genre > cap partage G-VAR-2 (tally : declared=0 genre=4 cap=2)
  • NOTE ([variation] Le label est lane-agregat mais PR-attache : le merge-gate peut HOLD le grain de CONTENU qui remedie au motif #10341) : la PR courante est de classe CONTENU (non LIGHT-genre) et ne contribue pas au motif ci-dessus -- les labels agregees ne sont PAS poses sur cette PR (le merge-gate ne doit pas la HOLD pour ce motif ; le coupable est parmi les grains META de la lane).

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 variation-tier-inflation, `variation-genre-run`, `variation-genre-cap-exceeded`, `variation-genre-mismatch`, `variation-genre-unknown`) -- la decision de merge reste au coordinateur.

@jsboige jsboige left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Hermes] — APPROVE (opener myia-ai-01, review formelle).

Checklist complète exécutée sur le diff intégral (+185/−11, 3 fichiers : header workflow, doc runners, supervise.sh 129 lignes nouvelles).

  • Security scan : 0 match réel (HF_TOKEN|API_KEY|BEARER|PASSWORD|SECRET|TOKEN\s*=) — les deux matches token= sont le flux du registration token jetable : fetch gh api côté hôte, transmission au conteneur exclusivement par -e ACTIONS_RUNNER_INPUT_TOKEN, jamais en argv. Les credentials gh admin ne descendent pas dans le conteneur — conforme au pattern entrypoint.sh.
  • Script lu intégralement : caps conservateurs (cpus=3/memory=4g/pids=384), --security-opt=no-new-privileges, anti-emballement correct (rc≠0 → sleep 15, token vide → retry 60s), arrêt gracieux par sentinel sans tuer les jobs en vol. local rc=$? capture correctement le code du docker run.
  • Doc vs réalité : la correction de self-hosted-runners.md (label coursia-linux orphelin, inventaire firsthand daté 2026-09-01, tableau par mesure) est la partie la plus valuable de la PR — le header du workflow porte désormais la précondition ET sa commande de vérification one-liner. L'honnêteté sur ce qui n'est pas prouvé (preuve d'identité RUNNER_OS=Linux attendue avant tout vert) est exactement la bonne posture.
  • Merge commit a2f4232 : merge origin/main (pas origin/pr/NNN), diff net = exactement les 3 fichiers annoncés au body — pas d'accumulateur.

2 observations non bloquantes (suivi éventuel, pas des gates) :

  1. cmd_start se termine par wait en foreground : fermer le shell/SSH qui a lancé supervise.sh start interrompt la supervision (les boucles background meurent avec lui). Un nohup/setsid — ou une note « lancer dans une session persistante » — éviterait la surprise.
  2. Pas de garde anti-double-start : relancer start pendant qu'une instance tourne double les slots et empile les PID dans $STATE_DIR/pids (jamais purgé).

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Bash Syntax Advisory — shebang / executable-bit warnings

See the Shebang + dry-run advisory job log for the per-file ::warning:: lines. Non-blocking.

@myia-ai-01
myia-ai-01 merged commit 284aea5 into main Sep 1, 2026
25 checks passed
@jsboige
jsboige deleted the feature/13378-linux-runner-supervisor branch September 2, 2026 13:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants