Repository navigation
fix(ci,#15091): budget memoire po-2024 coherent avec la VM de 24 Go + mur kernel - #19802
Conversation
… mur kernel La VM WSL de po-2024 fait 24 032 Mo (.wslconfig memory=24GB, free -m), le budget declare etait 42 Go (pose par #17322 pour une VM de 40 Go depuis revenue a 24) et la composition reelle totalisait 27 648 Mo de caps (6x1536 docker + 12x512 waiters + 2x6144 lean) -- une somme de caps superieure a la RAM, payee en swap : 104 GiB ecrits en moins de 11 h, DriveFS puis G: et RooSync emportes. Budget 42 -> 21 (le meme sur les trois jambes), composition 21 504 Mo, marge 2 528 Mo pour le noyau, dockerd et le page cache. On reduit des NOMBRES DE SLOTS, jamais des CAPS : 3 des 6 conteneurs docker touchaient leur cap de 1536 Mo a 99 %, c'est la concurrence qui ne tenait pas. La machine n'avait aucun mur kernel (coursia-ci.slice inexistante, MemoryHigh/Max/SwapMax = infinity) : le budget userspace refuse de DEMARRER un slot, il ne borne pas ce qu'un slot deja lance consomme. Ajout de persist/po-2024/coursia-ci.slice (MemoryHigh=20G, MemoryMax=22G, MemorySwapMax=0) et de COURSIA_RUNNER_CGROUP_PARENT dans les deux wrappers, qui y font entrer les conteneurs. memory-swap = memory sur la jambe lean : consequence nommee dans le fichier -- le build Hashlife de conway_lean depassait 16 Go a froid, il ne passera plus a 6 Go sans swap, et la reponse est de le router vers un runner hosted, pas de remonter le swap de cette machine. Le drop-in waiters est scopé po-2024 : coursia-waiters.service est le fichier d'ai-01 que les deux machines executent (byte-identique), editer l'unite aurait descendu ai-01 en silence. CPU 30 -> 24 : consequence arithmetique de la composition (4x3 + 2x6), pas un arbitrage -- #15574 garde son point de retour J+7 du jour. test_supervise_guards.sh : 137 PASS / 0 FAIL. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
[po-2024:CoursIA] Fermeture + reouverture accidentelles (23:1xZ) : la session qui reconciliait le doublon #19806 a laisse un gh pr close 19802 silencieux dans sa commande -- erreur de composition, aucune intention. Aucun merge, aucun rebase, la branche na pas bouge : la PR est intacte (OPEN, B.0 OK au releve). Desole pour le bruit dans la timeline du dossier. |
L'ancien defaut unique /mnt/d/CoursIA est correct pour ai-01 mais casse po-2024 depuis la migration du 2026-09-17 (repo sous /mnt/d/Dev/CoursIA) : au premier restart post-deploiement budget, la jambe waiters a crash-loope sur 'master.env illisible' (StartLimitBurst epuise). Le wrapper etant deploye a l'identique sur les deux sieges, le defaut sonde les deux racines documentees (persist/README.md) ; surcharge COURSIA_REPO_DIR inchangee. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… lean 2->1, slice 14/16G Point de retour prevu par l'arbitrage #15574 item 3, joue le 2026-10-08 : characterize_runner_variance.py --days 7 (456 jobs lourds) mesure le ratio p90/mediane a 9,3/5,1/14,5/4,0/23,3/15,4 par runner po-2024 -- 5 runners sur 6 au-dessus du seuil 5x. La regle s'applique : CPU 24 -> 18 (docker 4x3 + lean 1x6), right-sizing lean 2 -> 1 slots (cap unitaire 6 Go / 6 vCPU INCHANGE, volume chaud lean-2 conserve). La memoire suit : budget 21 -> 15 (composition 4x1536 + 6x512 + 1x6144 = 15 360 Mo, marge 8 672 Mo sur 24 032), slice po-2024 MemoryHigh 14G / MemoryMax 16G. Commentaires des huit fichiers persist/ realignes (le point de retour J+7 passe d'ouvert a resolu, references croisees 20G/22G corrigees). Temoins : test_supervise_guards.sh rejoue sur le worktree -- 137 PASS / 0 FAIL. Deploiement a suivre (fichiers vivants encore a 21/24/2 slots). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
[ADJOINT PREFLIGHT] |
Bash Syntax Advisory — shebang / executable-bit warningsSee the |
|
[ADJOINT PREFLIGHT] Tiers ai-01 (perimetre CI) : le seul ajout depuis le dossier du secretariat est l'avis shebang non bloquant de github-actions ; DWELL ecoule, derive-verdict READY a la tete 4936b99, budget memoire relu au cycle 22:13Z. |
…ur (composition derivee, surcharge slice, RAM VM declaree) Revue coordinateur 2026-10-08 (commentaire 🟡 cid 6053027290) a identifie 3 defauts sur l'organe #19805 : 1. Composition maintenue a la main (po2024_budget.json) -> derive depuis supervise.sh (BudgetSnapshot.from_supervise_defaults). Le snapshot JSON derive a chaque push supervise.sh, l'organe mesurait alors son propre instantane au lieu du deploiement. Lecture directe des variables COURSIA_RUNNER_MEMORY / COURSIA_RUNNER_WAITER_MEMORY / COURSIA_LEAN_RUNNER_MEMORY + N par defaut (2 start / 24 waiters / 2 lean). 2. Slice generique persist/coursia-ci.slice (16G) surchargeait la lecture sans tenir compte d'un plafond machine-specifique. Ajout lookup_slice() qui cherche persist/<machine>/coursia-ci.slice d'abord, fallback generique. La surcharge po-2024 n'est pas encore materialisee (#19802) mais le motif est en place. 3. RAM VM mesuree sur l'hote de l'organe (191.8 GiB ai-01, 63.6 GiB po-2027) au lieu d'etre declaree (24 GiB po-2024). Defaut fondateur ferme : l'organe peut tourner depuis n'importe quelle machine du cluster, mais c'est la machine-CIBLE qui plafonne. Constante PO2024_VM_RAM_GIB=24.0 + lookup_vm_ram_gib() + avertissement stderr si machine inconnue (mode slice seule). Tests : 16/16 verts (10 anciens + 6 nouveaux : lookup_vm_ram_gib x2, lookup_slice x2, from_supervise_defaults x2). Le mode JSON snapshot reste l'option par defaut pour la compat ascendante ; --from-supervise est opt-in (derive depuis supervise.sh defauts). Validation manuelle : python scripts/ci/assert_memory_budget.py --from-supervise --machine po-2024 [INCOHERENT] po-2024 : composition 27.0 GiB vs borne 16.0 GiB start : 2 x 1.5 GiB = 3.0 GiB waiters : 24 x 0.5 GiB = 12.0 GiB lean : 2 x 6.0 GiB = 12.0 GiB TOTAL : 27.0 GiB VM RAM : 24.0 GiB (hote reserve 0.5 GiB) Slice MemoryMax: 16.0 GiB Borne : 16.0 GiB (marge 0.5 GiB, seuil 15.5 GiB) Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
…'instantane Defaut 1 de la revue coordinateur, resté ouvert : le defaut de la composition etait encore le snapshot JSON recopie a la main. La CI appelle l'organe sans drapeau, donc il remesurait sa propre constante. La derivation `from_supervise_defaults` (valeurs documentees en en-tete de `supervise.sh`) derivait elle aussi du deploiement : 24 slots d'attente documentes quand l'unite en lance 12, et 6 sur po-2024 par drop-in. - `from_deployed_units(machine)` : effectif = dernier jeton entier de l'`ExecStart` du wrapper de jambe, cap = `Environment=` de la meme unite ; le drop-in `persist/<machine>/<unite>.d/*.conf` surcharge l'unite de base. - Composition par defaut = unites deployees. `--from-json` et `--from-supervise` restent disponibles pour l'audit et le repli. - Provenance portee au verdict (champ `source`, texte et JSON) : un organe qui confronte une composition dit d'ou elle vient. - Workflow : les `paths:` couvrent `persist/**` -- sans quoi le guard ne se relance pas quand un dimensionnement change, et rend un verdict perime. - Test stale corrige : `lookup_slice` sur po-2024 affirmait le repli sur la generique en se fondant sur l'absence de la surcharge, materialisee depuis #19802. Le postulat avait disparu avec le deploiement. Mesure : la composition reelle de `main` (4 x 1.5 + 6 x 0.5 + 1 x 6 = 15.0 GiB) tient sous le seuil 15.5 GiB. Le rouge `Composition vs RAM VM` etait un artefact de lecture, pas une incoherence du deploiement -- c'est la reponse que la revue demandait a l'organe. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
… VM (#19851) * feat(infra,#19805): assert_memory_budget -- organe composition vs RAM VM Issue #19805 -- fix(runners): budget memoire po-2024 incoherent avec la VM (42 Go declares pour 24 032 Mo disponibles). Le budget cumule des conteneurs runners (effectifs x caps) etait superieur a la RAM de la VM WSL, et rien dans l'instrumentation existante ne le detectait. measure_po2024_topology mesure la topologie OS mais ne confronte pas la composition au budget declare, et le garde precedent ne connaissait que le budget (pas la RAM VM). Cause racine documentee : agrandissement VM 2026-09-24 revertu, declarations non revisees (deuxieme derive de la meme famille, la premiere corrigee par #17322 dans l'autre sens). Livrable : - scripts/ci/assert_memory_budget.py : organe cross-platform qui lit la RAM VM via measure_po2024_topology.measure() et la composition depuis docker-configurations/runners/<host>_budget.json (snapshot canonique), confronte a la borne la plus contraignante (min entre MemoryMax de la slice et RAM VM - hote reserve 0.5 GiB). Sortie texte ou --json. Exit 0 si composition <= borne, 1 sinon. - docker-configurations/runners/po2024_budget.json : snapshot de la composition mesuree firsthand (docker 6x1.5=9, waiters 12x0.5=6, lean 2x6=12 = 27.0 GiB). Verdict au snapshot : INCOHERENT (27.0 > 16.0 MemoryMax slice). - scripts/tests/test_assert_memory_budget.py : 10 tests unitaires (load snapshot, parse MemoryMax, OK/INCOHERENT, marge, snapshot bien forme). 10/10 verts en local. - .github/workflows/assert-memory-budget.yml : CI bloquante sur PR/push touchant le snapshot, l'organe, la topologie, la slice ou supervise.sh. Schedule lundi 06:37 UTC pour detecter la derive de l'instrument quand aucune PR ne touche le snapshot. Run sur ubuntu-latest (jamais self-hosted : l'observateur ne doit pas consommer ce qu'il observe). Anti-patterns evites : - Re-implémenter measure_po2024_topology : refus. L'organe importe la fonction measure() deja existante (cf. #13564 organ-first). - Mesure VM dependante du daemon docker : refus. measure() lit la RAM via WMI / procfs / sysctl sans docker. - Hand-edit sortie : refus (secrets-hygiene regle 6). - Rapport commité : refus (cadrage coordinateur 07/10 + CLAUDE.md §A). Scope CPU strict -- pas d'execution CI sur la machine cible (po-2024) : le workflow tourne sur ubuntu-latest pour verifier l'instrument, et un operateur execute l'organe sur po-2024 elle-meme (le snapshot detecte l'incoherence via la slice 16 GiB, qui est partagee par toutes les machines CI). Le gate est : composition <= borne tranche au plus serré. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * fix(infra,#19851): assert_memory_budget -- 3 defauts revue coordinateur (composition derivee, surcharge slice, RAM VM declaree) Revue coordinateur 2026-10-08 (commentaire 🟡 cid 6053027290) a identifie 3 defauts sur l'organe #19805 : 1. Composition maintenue a la main (po2024_budget.json) -> derive depuis supervise.sh (BudgetSnapshot.from_supervise_defaults). Le snapshot JSON derive a chaque push supervise.sh, l'organe mesurait alors son propre instantane au lieu du deploiement. Lecture directe des variables COURSIA_RUNNER_MEMORY / COURSIA_RUNNER_WAITER_MEMORY / COURSIA_LEAN_RUNNER_MEMORY + N par defaut (2 start / 24 waiters / 2 lean). 2. Slice generique persist/coursia-ci.slice (16G) surchargeait la lecture sans tenir compte d'un plafond machine-specifique. Ajout lookup_slice() qui cherche persist/<machine>/coursia-ci.slice d'abord, fallback generique. La surcharge po-2024 n'est pas encore materialisee (#19802) mais le motif est en place. 3. RAM VM mesuree sur l'hote de l'organe (191.8 GiB ai-01, 63.6 GiB po-2027) au lieu d'etre declaree (24 GiB po-2024). Defaut fondateur ferme : l'organe peut tourner depuis n'importe quelle machine du cluster, mais c'est la machine-CIBLE qui plafonne. Constante PO2024_VM_RAM_GIB=24.0 + lookup_vm_ram_gib() + avertissement stderr si machine inconnue (mode slice seule). Tests : 16/16 verts (10 anciens + 6 nouveaux : lookup_vm_ram_gib x2, lookup_slice x2, from_supervise_defaults x2). Le mode JSON snapshot reste l'option par defaut pour la compat ascendante ; --from-supervise est opt-in (derive depuis supervise.sh defauts). Validation manuelle : python scripts/ci/assert_memory_budget.py --from-supervise --machine po-2024 [INCOHERENT] po-2024 : composition 27.0 GiB vs borne 16.0 GiB start : 2 x 1.5 GiB = 3.0 GiB waiters : 24 x 0.5 GiB = 12.0 GiB lean : 2 x 6.0 GiB = 12.0 GiB TOTAL : 27.0 GiB VM RAM : 24.0 GiB (hote reserve 0.5 GiB) Slice MemoryMax: 16.0 GiB Borne : 16.0 GiB (marge 0.5 GiB, seuil 15.5 GiB) Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * fix(infra,#19851): composition derivee des unites deployees, pas de l'instantane Defaut 1 de la revue coordinateur, resté ouvert : le defaut de la composition etait encore le snapshot JSON recopie a la main. La CI appelle l'organe sans drapeau, donc il remesurait sa propre constante. La derivation `from_supervise_defaults` (valeurs documentees en en-tete de `supervise.sh`) derivait elle aussi du deploiement : 24 slots d'attente documentes quand l'unite en lance 12, et 6 sur po-2024 par drop-in. - `from_deployed_units(machine)` : effectif = dernier jeton entier de l'`ExecStart` du wrapper de jambe, cap = `Environment=` de la meme unite ; le drop-in `persist/<machine>/<unite>.d/*.conf` surcharge l'unite de base. - Composition par defaut = unites deployees. `--from-json` et `--from-supervise` restent disponibles pour l'audit et le repli. - Provenance portee au verdict (champ `source`, texte et JSON) : un organe qui confronte une composition dit d'ou elle vient. - Workflow : les `paths:` couvrent `persist/**` -- sans quoi le guard ne se relance pas quand un dimensionnement change, et rend un verdict perime. - Test stale corrige : `lookup_slice` sur po-2024 affirmait le repli sur la generique en se fondant sur l'absence de la surcharge, materialisee depuis #19802. Le postulat avait disparu avec le deploiement. Mesure : la composition reelle de `main` (4 x 1.5 + 6 x 0.5 + 1 x 6 = 15.0 GiB) tient sous le seuil 15.5 GiB. Le rouge `Composition vs RAM VM` etait un artefact de lecture, pas une incoherence du deploiement -- c'est la reponse que la revue demandait a l'organe. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * fix(ci,#19851): installer pytest dans le smoke test du workflow Le runner ubuntu-latest n'expose pas pytest dans le Python 3.13 installe par setup-python : l'etape `Run pytest (smoke)` echouait sur `No module named pytest` (rouge fondeur du 2026-10-09), pas sur le code de l'organe. Ajout d'une etape d'installation explicite avant le smoke test. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
…-in slice-guard.conf) (#20096) * fix(ci): garde slice CI po-2024 — activation boot + fail-closed (slice-guard.conf) Signalement Sheriff msg-20261009T103550-mypwn3 (jsboige/Maintenance#76) : apres le reboot du 08/10 21:47, les 11 conteneurs CI sont nes hors coursia-ci.slice. Cause racine mesuree : rien n'active la slice au boot, et assert_ci_slice (supervise.sh) lit memory.max dans le cgroup fs — slice inactive = pas de cgroup = « illisible », placement saute en silence (COURSIA_REQUIRE_CI_SLICE=0 par defaut). Deux copies de reference du drop-in deploye ce cycle sur po-2024 (byte-identiques au deploiement) : - [Unit] Wants/After=coursia-ci.slice : la slice demarre avec l'unite. Une slice vide demarree reste active/active avec limites lisibles (valide firsthand). - [Service] Environment="COURSIA_REQUIRE_CI_SLICE=1" : assert_ci_slice passe en fail-closed (branche die prevue par le code) — slice absente = unite FAILED visible, jamais un pool non borne silencieux. Le deploiement porte aussi la couche J+7 (#19802, revue passee, jamais jouee) : budget 15 / CPU 18 / lean x1 / slice 14G-16G. Dry-run poste sur le dashboard AVANT les gestes root ; sauvegardes /root/ci-cgroup-bak-20261009T1400Z/. See #19802 (deploiement de l'amendement J+7 ; ne le clot pas — le suivi variance reste ouvert) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(ci): jambe waiters sous la slice -- drop-in specifique (dispatch ai-01 c1600) Le wrapper coursia-waiters-start.sh appartient a ai-01 (byte-identique sur les deux sieges) et n'exporte ni slice ni garde : supervise.sh les lit dans son environnement. Le drop-in waiters injecte donc les DEUX variables (COURSIA_RUNNER_CGROUP_PARENT + COURSIA_REQUIRE_CI_SLICE=1) en plus du Wants/After, perimetre po-2024 uniquement. Deploye et verifie le 2026-10-09 : 6/6 waiters CgroupParent=coursia-ci.slice, slice a 11 scopes docker (5 CI + 6 waiters), memory.current ~6,7 Go, budget 15 Go aligne sur la 3e jambe (drift 21->15 du 10-sizing.conf deploye au passage -- le repo portait deja 15), waiters reconnectes et a l'ecoute apres purge des 6 stale hors slice (idle verifie Runner.Worker=0 x6). See jsboige/Maintenance#76 (suite) ; claim dispatch ai01-c1600-po2024c-waiters-slice Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
…-> 22.0) Le test test_lookup_slice_machine_override_wins_on_real_po2024 asserte la valeur MemoryMax de la slice po-2024 materialisee sur main -- son docstring le dit lui-meme : il teste l'etat du depot, pas l'organe. #19802 (J+7) y avait pose 16.0 ; l'arbitrage c2153 remonte le mur a 22G avec le budget 21 (#20174), la valeur attendue suit. Docstring completee avec la genealogie 16.0 (#19802) -> 22.0 (c2153). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…0425) Famine justifee : la composition persist re-etiquetee #20174 est entree apres le J+7 de #19802 sans suivi du budget. Hier (2026-10-11 vers 03:10:57 CEST), le pool waiters a commence a refuser ses slots : 18432 Mo CI en vol + 3072 Mo demandes (6 x 512m) = 21504 Mo > 15360 Mo budget (COURSIA_RUNNER_BUDGET_GB=15). Le service a atteint "Start request repeated too quickly" et Result: exit-code 1 ; aucun waiter container n'a demarre pendant l'incident. Mission coordinateur c2153, option b : retablir le budget a 21 Go, le meme nombre que celui de l'ere pre-J+7 (avant amendement 15 Go du 2026-10-08). Doctrine "meme nombre sur les 3 jambes" preservee : runner-start.sh, lean-start.sh, et le drop-in waiters portent 21. Slice 20G/22G/0 swap inchangee, CPU 18 inchange -- seul le budget memoire evolue. La valeur documentee reste 21 dans l'en-tete du drop-in waiters (le commentaire note 15 comme "avant"). Deployment : dry-run sed montre les 3 substitutions, apply, verification post-deploy. systemctl daemon-reload && systemctl restart coursia-waiters.service. Witness : 6 waiters Up, slice memory.high=14G memory.max=16G, hote sain (pagewrites=0 pagesout=0). See #19802, See #20174 Co-authored-by: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
…, volet 2) (#20431) * Fix(ci,#19802): budget CI po-2024 15 -> 21 Go (3 jambes alignees) Famine justifee : la composition persist re-etiquetee #20174 est entree apres le J+7 de #19802 sans suivi du budget. Hier (2026-10-11 vers 03:10:57 CEST), le pool waiters a commence a refuser ses slots : 18432 Mo CI en vol + 3072 Mo demandes (6 x 512m) = 21504 Mo > 15360 Mo budget (COURSIA_RUNNER_BUDGET_GB=15). Le service a atteint "Start request repeated too quickly" et Result: exit-code 1 ; aucun waiter container n'a demarre pendant l'incident. Mission coordinateur c2153, option b : retablir le budget a 21 Go, le meme nombre que celui de l'ere pre-J+7 (avant amendement 15 Go du 2026-10-08). Doctrine "meme nombre sur les 3 jambes" preservee : runner-start.sh, lean-start.sh, et le drop-in waiters portent 21. Slice 20G/22G/0 swap inchangee, CPU 18 inchange -- seul le budget memoire evolue. La valeur documentee reste 21 dans l'en-tete du drop-in waiters (le commentaire note 15 comme "avant"). Deployment : dry-run sed montre les 3 substitutions, apply, verification post-deploy. systemctl daemon-reload && systemctl restart coursia-waiters.service. Witness : 6 waiters Up, slice memory.high=14G memory.max=16G, hote sain (pagewrites=0 pagesout=0). See #19802, See #20174 Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * Fix(ci,#20174): slice po-2024 14G/16G -> 20G/22G + arithmetique budget 21 Go Arbitrage c2153 (option b), volet absent de #20425 : le mur kernel suit la composition vive 8x1536 + 6x512 + 1x6144 = 21 504 Mo de caps -- un MemoryMax 16G sous cette composition tue au kernel des jobs que le budget d'admission 21 laisse partir. L'arithmetique #20174/#19802 ecrite dans les commentaires des trois jambes, exigee par la meme consigne. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * Fix(tests,#20174): test slice po-2024 suit le mur 22G de c2153 (16.0 -> 22.0) Le test test_lookup_slice_machine_override_wins_on_real_po2024 asserte la valeur MemoryMax de la slice po-2024 materialisee sur main -- son docstring le dit lui-meme : il teste l'etat du depot, pas l'organe. #19802 (J+7) y avait pose 16.0 ; l'arbitrage c2153 remonte le mur a 22G avec le budget 21 (#20174), la valeur attendue suit. Docstring completee avec la genealogie 16.0 (#19802) -> 22.0 (c2153). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
Grain: DEEP/tooling -- lane myia-po-2024:CoursIA -- prev: MED/notebook-python #19795
Mission ai-01 (DM URGENT, 2026-10-08). La VM WSL de po-2024 fait 24 Go, la CI y déclarait un budget de 42 Go pour une composition de 27 648 Mo de caps, et la machine n'avait aucun mur kernel derrière ce budget : 104 GiB écrits dans le swap en moins de 11 h, DriveFS emporté le premier, puis
G:et RooSync — l'arrêt de la coordination de la flotte.Ce que la mesure dit (2026-10-08, firsthand sur po-2024)
free -m,.wslconfig)memory=24GB)coursia-ci.sliceinactive (dead), fichier/etc/systemd/system/coursia-ci.sliceinexistantMemoryHigh/MemoryMax/MemorySwapMaxLe 42 était faux deux fois — et cette PR le défait sciemment.
Le 42 a été posé par #17322 (« declarations budget po-2024 12->42 Go (VM WSL 40 Go) »), et la composition actuelle par #18691 (« waiters hors du budget CPU + deploy po-2024 (30, docker 8->6) »). Cette PR ne les contredit pas sur leur raisonnement : elle constate que leur prémisse a changé.
memory=40GB(arbitrage user, missionmsg-20260921T203652-qxg3en) ;.wslconfigetfree -mdisent tous les deux 24 Go aujourd'hui. fix(runners): declarations budget po-2024 12->42 Go (VM WSL 40 Go) #17322 avait raison le jour où il a été écrit — c'est la VM qui a rebouclé en arrière depuis, sans que le budget suive.WAITER_MEMORYvaut512m(supervise.shl.180). La composition réelle totalisait 27 648 Mo — déjà supérieure à la RAM de la VM, et c'est cela qui se payait en swap.Arithmétique retenue — budget 21, le même nombre sur les trois jambes
start)VM 24 032 Mo − caps 21 504 Mo = 2 528 Mo de marge pour le noyau WSL2, dockerd et le page cache. Mesure du même jour : le système hors conteneurs pesait ~3 200 Mo, dont 2 429 Mo de
buff/cache— reclaimable, et c'est précisément ce queMemoryHighmet sous pression avant le mur.On réduit des NOMBRES DE SLOTS, jamais des CAPS. Mesure : 3 des 6 conteneurs docker touchaient leur cap de 1536 Mo à 99 % (1,492 / 1,474 / 1,497 GiB) — le cap unitaire n'est pas en trop, c'est la concurrence qui ne tenait pas. Un job lourd garde exactement le même régime mémoire ; il attend son tour au lieu de pousser la machine dans le swap.
CPU, conséquence et non arbitrage :
COURSIA_RUNNER_CPU_BUDGETpasse de 30 à 24 (4×3 + 2×6) mécaniquement, par la même règle qu'avant (le budget est la somme des caps). L'axe CPU lui-même n'est pas tranché ici — #15574 a son propre point de retour mesuré J+7, qui tombe aujourd'hui et reste ouvert.Le mur kernel — ce que la PR ajoute vraiment
Un budget userspace refuse de démarrer un slot ; il ne borne pas ce qu'un slot déjà lancé consomme. C'est tout l'écart, et aucun garde userspace ne peut le fermer.
persist/po-2024/coursia-ci.slice(nouveau, homonyme de la slice d'ai-01, valeurs différentes) :MemorySwapMax=0est l'arbitrage central, et il est assumé, pas subi. Le swap d'une VM WSL est un fichier sur le disque Windows : chaque page poussée retarde DriveFS, puisG:, puis RooSync. Un job qui dépasse son cap doit mourir (exit 137, échec local, retryable, un job perdu) plutôt que d'emporter la coordination de la flotte.Conséquence nommée, pour qu'elle ne soit pas découverte en panne : la jambe lean perd son coussin.
LEAN_MEMORY_SWAPvalait12g(6 Go RAM + 6 Go swap par slot). Le commentaire du bloc LEAN desupervise.shdocumente pourquoi — « supprimer le swap ne retire pas le pic de Hashlife, il transforme un build qui déborde en un exit 137 — c'est un curseur, pas un dogme ». Le curseur est ici tourné dans l'autre sens, délibérément. Le build Hashlife deconway_leandépassait 16 Go à froid : à 6 Go sans swap il ne passera pas. La réponse n'est pas de remonter le swap de cette machine, elle est de router ce lake vers un runner hosted (32 Go de fallocate swap,lean-axiom.yml) — exactement la conclusion que le commentaire desupervise.shtire déjà.Aucun
CPUQuotasur la slice : l'axe CPU a son propre arbitrage et son point de retour du jour.CPUAccounting=yesest posé — on mesure, on ne plafonne pas.Deux constats de la pose, relevés sur le cgroup vivant et versés ici parce qu'ils changent ce qu'un lecteur peut croire de cette slice :
1.
IOWeight=50est inerte sur ce noyau — et ce n'est pas un défaut de la slice. Les fichiers io présents dans le cgroup sontio.latency,io.max,io.pressure,io.stat: il n'y a pas deio.weight. En cgroup v2,io.weightn'est exposé que sous l'ordonnanceurbfq; sans lui, c'estio.latencyqui tient ce rôle, et systemd rapporteIOWeight=50comme propriété sans que rien ne soit écrit dans le noyau. Le seul plafond I/O qui mord réellement estio.max— c'est aussi le seul queassert_cgroup_budgetlit (supervise.shl.1147-1149). Un opérateur qui croiraitIOWeightprotecteur se tromperait : c'est exactement la « garde de façade » que le commentaire d'en-tête de la slice dénonce pour l'unité du superviseur, et elle se reproduit ici pour une autre raison.2. Le trou de câblage est corroboré par une mesure indépendante. La lane
po-2024:Maintenancea relevé le 2026-10-07 queHostConfig.CgroupParentétait vide sur les trois familles (jsboige/Maintenance#76, c. 08/10 00:3x) : les conteneurs n'étaient rattachés à aucune slice. C'est la démonstration, depuis un autre instrument que le mien, que poser la slice sansCOURSIA_RUNNER_CGROUP_PARENTl'aurait laissée inerte — un cgroup correct que rien n'habite. Les deux moitiés voyagent donc ensemble dans cette PR.Une sonde à ne pas refaire :
[ -s "$cg/io.max" ]rend faux sur un fichier cgroupfs, dont lest_sizevaut 0 alors qu'il a du contenu. Le contrôle juste est[ -r ]puis lecture du contenu — ce que faitassert_cgroup_budget. Un test de taille y fabrique un faux « mur absent » sur un mur présent.Les deux listes exigées par #15202 (cette PR abaisse des bornes)
Jobs dont le pic a été MESURÉ sous la nouvelle valeur
docker stats)Les deux familles dont on réduit le nombre gardent leur cap unitaire intact : aucun job mesuré ne change de régime mémoire.
Jobs NON mesurés qui tournent sur ce pool, nommés un par un
coursia-linux(famillestart, 4 slots) — 128 workflows la portent. Famille d'exécution générale : les jobs de gate et de vérification du dépôt. Le passage de 6 à 4 slots réduit la concurrence, pas le cap : un job qui consommait 1,5 Go continue de pouvoir le faire, il attend son tour plus souvent.coursia-waiter(6 slots) — 4 workflows :pr-gate.yml(le principal),pr-gate-stale-sweep.yml,linux-runner-starvation-advisory.yml,runner-starvation-advisory.yml. Un waiter n'est pas un conteneur inerte : il EXÉCUTE ces jobs. C'est pourquoi son cap de 512 Mo n'est pas abaissé — le faire aurait changé le régime de jobs non mesurés, ce que ci(runner): 'Build Quarto site' OOM (exit 137) sur le pool auto-heberge -- le dimensionnement du parc n'a jamais echantillonne le job le plus lourd, et main est rouge depuis 13 h #15202 interdit. Seul le nombre de slots baisse (12 → 6), et 6 reste strictement supérieur aux 4 slots d'exécution : la file de gates garde de quoi absorber une rafale sans faire attendre un job derrière un slot d'exécution.coursia-lean(2 slots) —lean-knot.yml(+ 2 workflows d'observation). Inchangée : ni le nombre, ni le cap. Elle reste le poste dominant (58 % du budget) et c'est assumé — c'est le goulot du parc, et l'abaisser toucherait des builds Lean, pas des jobs interchangeables.myia-po-2024-fast-guards(labelcoursia-fast-guards, 2 workflows) — ce runner n'est pas lancé parsupervise.shet n'est donc pas couvert par le budget ni par la slice. Signalé ici pour qu'il ne soit pas découvert plus tard : il consomme de la mémoire hors de tout plafond, et sa mise sous slice est un sujet distinct.Le nombre 6 pour les waiters n'est pas un plancher mesuré — cette machine n'a pas d'historique d'occupation, seulement un instantané (12 waiters, 12 ×
busy: falseau relevé). Il est choisi par la règle ci-dessus (supérieur aux slots d'exécution), et si l'occupation soutenue approche 6, c'est le budget de la machine qu'il faudra rouvrir — pas ce nombre qu'il faudra deviner à la hausse sans mesure.Fichiers
persist/po-2024/coursia-ci.sliceMemoryHigh=20G,MemoryMax=22G,MemorySwapMax=0)persist/po-2024/coursia-waiters.service.d/10-sizing.confcoursia-waiters.serviceest le fichier d'ai-01 que les deux machines exécutent (byte-identique, sha256 vérifié)persist/coursia-runner-start.shCOURSIA_RUNNER_CGROUP_PARENTpersist/coursia-lean-start.shmemory-swap = memory,COURSIA_RUNNER_CGROUP_PARENTpersist/coursia-runner.servicestart 6→start 4persist/README.mdpo-2024/existepersist/coursia-ci.slicePérimètre : aucun fichier d'ai-01 n'est modifié. C'est la raison d'être du drop-in — éditer
coursia-waiters.servicepour descendre po-2024 descendrait ai-01 au prochain déploiement, sans que rien ne le signale.Déploiement (fait sur l'hôte, après merge du présent commit — cf. étape 5)
Ordre obligatoire, la slice d'abord :
assert_slicerefuse le démarrage si la slice déclarée est introuvable ou sansio.max.installde la slice +daemon-reload+start coursia-ci.sliceinstalldes wrappers et unitésdaemon-reloadTimeoutStopSec=900).[slice] mur agrege ACTIF : memory.high=... memory.max=...Le dry-run (
systemd-analyze verify) et la liste exacte des fichiers/valeurs sont postés sur le dashboard CoursIA avant toute écriture, conformément à la règle UAC/dry-run du 2026-08-27.Ce que cette PR ne fait PAS
myia-po-2024-fast-guardssous la slice — signalé, pas traité.Post-déploiement (08/10, ~01:40 heure locale) — confirmations + correctif associé
Déployé sur l'hôte après dry-run publié (
systemd-analyze verify+ liste fichiers/valeurs sur le dashboard CoursIA). Mesures complètes postées sur jsboige/Maintenance#76 (c.6049087196).CgroupParent=coursia-ci.slice. La jambe docker oscille 3-4 selon les jobs en vol.systemctl show:memory.high=21474836480,memory.max=23622320128,memory.swap.max=0,io.max=8:48 rbps=419430400 wbps=209715200;memory.current5,2-7,9 GiB sous le mur ;oom_kill 0;pswpoutgelé (swap stable à 1 069 Mo).Memory=MemorySwap=6442450944sur les deux slots.[slice] mur agrege ACTIFau journal des trois jambes (runner 01:17:50, lean 01:18:27, waiters 01:38:11).Correctif associé :
f9b1958caf8— wrapper waiters, chemin du dépôtLe premier restart post-déploiement a exposé un défaut préexistant du dépôt :
coursia-waiters-start.shportait le défaut/mnt/d/CoursIA— correct pour ai-01, faux pour po-2024 depuis la migration du 17/09 (/mnt/d/Dev/CoursIA) : la jambe waiters refusaitmaster.env illisibleet épuisaitStartLimitBurst. Le wrapper étant déployé à l'identique sur les deux sièges (les deuxExecStartpointent/usr/local/bin/coursia-waiters-start.sh), le défaut sonde désormais les deux racines documentées (persist/README.md) ; la surchargeCOURSIA_REPO_DIR/COURSIA_MASTER_ENVest inchangée. Déployé et vérifié : 6 waiters dans la slice.Découverte latérale pour ai-01 : l'épingle #16134 de la jambe waiters n'existait pas (les 12 anciens waiters dataient d'avant la garde) — geste
supervise.sh pinpassé. Et l'image vivante2.337.0(21/09) n'embarque pas la seconde barrière #16938 (wch_check_workdirappelé nu au lieu du gardeif !) : l'épingle a été ramenée à la paire cohérente image pour démarrer ce soir ; déployer #16938 exige pin forward +docker build+ restart roulé — signalé sur le dashboard.Preuves
test_supervise_guards.sh: 137 PASS / 0 FAIL après modifications (exécuté dans WSL, l'environnement cible).bash -npropre sur les deux wrappers modifiés.be4a9dc3…,ede4694d…,2465a973…) — le déploiement est prévisible.docker stats,free -m,systemctl, API GitHub runners : firsthand le 2026-10-08 sur po-2024.See #17322 (le 42, dont la prémisse a changé) · See #18691 (composition 6+2 du 01/10) · See #15574 (axe CPU, non traité ici) · See #15202 (règle des deux listes) · See #15091 (slice agrégée)
Amendement J+7 (2026-10-08) — verdict mesure, application de la regle
Le point de retour prevu par l'arbitrage CPU du 2026-10-01 (#15574 item 3, comment 5933689033) a ete joue le jour meme :
5 runners sur 6 au-dessus du seuil 5x : la regle s'applique — passage CPU 24 -> 18 avec right-sizing. Le right-sizing est la jambe lean (2 -> 1 slots, cap unitaire 6 Go / 6 vCPU INCHANGE — on reduit un nombre de slots, jamais un cap, regle #15202). La memoire suit le meme mouvement : budget 21 -> 15, composition 4x1536 + 6x512 + 1x6144 = 15 360 Mo sur 24 032 (marge 8 672 Mo), slice MemoryHigh 14G / MemoryMax 16G (deploiement a suivre : la slice vive porte encore 20G/22G).
COURSIA_RUNNER_BUDGET_GB(3 jambes + drop-in waiters)COURSIA_RUNNER_CPU_BUDGET(2 wrappers execution)ExecStartlean (coursia-lean.service)... 2... 1coursia-runner-work-lean-2ExecStart ... 2+ restart)Fichiers touches :
coursia-runner-start.sh(blocs budget memoire + CPU),coursia-runner.service(commentaire historique),coursia-lean-start.sh(budget + CPU + cgroup-parent),coursia-lean.service(ExecStart + commentaires),po-2024/coursia-ci.slice(valeurs + arithmetique),po-2024/coursia-waiters.service.d/10-sizing.conf(21 -> 15),persist/README.md+persist/coursia-ci.slice(references croisees).Runbook retour arriere :
ExecStart ... 2+ budget 21 + slice 20G/22G sur les trois jambes, puis restart (le volume lean-2 reste chaud, la reconstruction n'est pas due).Temoins :
test_supervise_guards.shrejoue sur le worktree apres amendement (resultat dans les checks de cette PR) ; mesure J+7 archiveej7_variance.jsoncitee au dashboard.🤖 Generated with Claude Code