Skip to content

Fix(ci,#22937): timeout-minutes 5->15 — bornes de garde calibrées sur clone chaud, annulées par le clone froid ubuntu-latest - #24122

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/22937-ci-timeout-checkout-froid
Nov 2, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/22937-ci-timeout-checkout-froid

Conversation

@jsboige

@jsboige jsboige commented Nov 2, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-po-2023:CoursIA — prev: LIGHT/ledger #24117

See #22937 (sous-grain, paths: bornés aux deux workflows). Signalement d'origine : WARN myia-ai-01:CoursIA-2 03:14:10Z (run 41378044015, c.6568122369) — re-vérifié firsthand avant tout geste (G.1).

Le défaut, re-mesuré à la source

timeout-minutes: 5 annule des jobs de garde après un verdict vert, parce que la borne était calibrée sur le checkout chaud du parc local alors que le repli ubuntu-latest paie un clone froid fetch-depth: 0 sur un dépôt volumineux.

Run 41378044015 (PR #24115, job Kernel drift guard (base vs PR), relu via gh run view --json) :

Étape Fenêtre Durée Conclusion
actions/checkout@v4 02:50:51 → 02:55:37 286 s 95 % du budget du job
Kernel drift check 02:55:37 → 02:55:51 14 s exit 0 — verdict vert produit
annulation du job 02:55:58 — timeout-minutes: 5 échu (job démarré 02:50:48)
Kernel drift unit tests — — skipped — jamais exécutée dans ces runs

Annulations re-datées job par job (API Actions, started_at → completed_at) — correction après review : le compte initial mélangeait les runs supplantés et les échéances de la borne. Un run supplanté par un nouveau push meurt en 4–115 s quelle que soit la valeur du timeout ; une échéance de la borne meurt vers 300 s pile :

Workflow Job sous timeout-minutes: 5 Fenêtre Annulations dont échéance de la borne dont supersede
notebook-kernel-drift-guard.yml kernel-drift 30 runs (re-datation review 04:02Z) 6 3 (310/321/346 s — dont le témoin 41378044015) 3 (16–62 s)
notebook-execution-required.yml detect-changes ~100 runs (23:34Z → 05:58Z, balayage 120) 11 2 (300 s pile — l'échéance exacte — et 246 s probable) 9 (4–115 s)

Le taux de défaut propre à la borne est donc 3/30 (10 %) côté kernel-drift à la fenêtre de la review — pas 5–6/30 comme écrit initialement. La fenêtre glisse (les 310/321 s ont quitté le palier 60 runs au moment de la contre-mesure) ; la classe reste épinglée par le témoin ci-dessus et la signature est stable : annulations courtes = supersedes, annulations à ~300 s = la borne.

Le second portait un commentaire de calibration explicite (« ~3x la durée mesurée (0-1 min sur les 8 derniers succès) ») : cette durée était mesurée sur le parc local (clone chaud), pas sur le repli hébergé — la prémisse de la borne était fautive, pas seulement sa valeur.

Le correctif

Deux fichiers, un changement chacun : timeout-minutes: 5 → 15, avec le commentaire de mesure dans les deux. Le commentaire existant de #23016 est conservé et amendé, pas remplacé.

15 min couvre le pire cas mesuré (checkout ~5 min + contrôle 14 s + tests) avec ~2,7× de marge, et reste une borne réelle — le job ne peut toujours pas figer un slot.

Ce que cette PR ne fait pas (alternatives écartées, avec motif)

  • Sortir les tests en job séparé (option proposée dans le signalement) : écartée — elle double le checkout de ~5 min par PR notebook, exactement contre le sens du routage hybride de CI au long cours : GitHub sert le maximum, nos runners absorbent le debordement (capacite, mutualisation, volume d'appels) #22937 (le parc local était saturé par ses checkouts, 11/12 slots mesurés le 27/10). La séparation ne devient pertinente que si les deux phases deviennent lentes séparément.
  • Réduire fetch-depth : écartée — le garde kernel-drift résout une merge-base et detect-changes fait un git diff de base ; changer la stratégie de fetch change la sémantique du garde, pas seulement son coût. Sujet séparé si la file CI le justifie.
  • Les 11 autres workflows à timeout-minutes: 5 (compte exact timeout-minutes: 5$ à origin/main ; la rédaction initiale en comptait 9 — deux garde-fous ajoutés depuis : local-path-waiver-guard, twin-attestation-name-guard) : 10 sur 11 n'ont pas la conjonction à risque (fetch-depth: 0 effectif et repli ubuntu-latest) — 4 tournent uniquement sur le parc local (concurrency-conj-guard, pr-gate-sweep-health-advisory, testpaths-coverage-guard, workflow-path-filter-audit, ce dernier aussi en fetch-depth: 1) ; codeql.yml est en ubuntu-latest statique mais fetch-depth: 2 ; 5 sont en forme hybride sans clone profond (assert-memory-budget, local-path-waiver-guard, twin-attestation-name-guard — checkout par défaut ; harness-coauthor-guard — le fetch-depth: 0 n'y est qu'en commentaire ; quarto-render-list-freshness — fetch-depth: 1 effectif). L'exception est slides-composition-pr-relay.yml : conjonction complète (timeout 5 + fetch-depth: 0 effectif l.72 + repli ubuntu-latest), contre-mesurée à la review : 476 runs historiques, 0 annulation, job max 84 s — le clone profond ne s'exécute que sur les PR touchant les slides, trafic faible. Conjonction théoriquement à risque, jamais mordue empiriquement : hors périmètre de cette PR (paths: bornés aux deux workflows corrigés, conforme à CI au long cours : GitHub sert le maximum, nos runners absorbent le debordement (capacite, mutualisation, volume d'appels) #22937) ; sous-grain séparé si le trafic slides monte. Ce décompte exclut les deux workflows que cette PR modifie — .github/workflows/notebook-kernel-drift-guard.yml et .github/workflows/notebook-execution-required.yml — puisqu'ils sont précisément les deux seuls retenus par le correctif. La liste est re-dérivée par croisement grep, pas recopiée d'ici.

Validation

  • YAML des deux workflows re-parsé ; timeouts relevés par lecture structurelle : kernel-drift 15, detect-changes 15, validate-static 10 et golden-set-execute 20 inchangés.
  • check_self_hosted_runner_policy.py (lit ces workflows) : OK rc=0, 169 workflows / 207 jobs.
  • fast_lane_registry.py --check : rc=0 — statuts bloquants inchangés.
  • Aucun test n'épingle les valeurs de timeout-minutes (grep -rn sur scripts/ : vide).
  • runs-on, on.paths, if:, concurrency : inchangés dans les deux fichiers.

La démonstration en conditions réelles (un run vert non annulé) appartient à la CI de cette PR elle-même : elle déclenche le garde kernel-drift via son paths: (.github/workflows/notebook-kernel-drift-guard.yml), sur ubuntu-latest puisque CI_OVERFLOW_LOCAL ne vaut pas true.

Portée

Deux lignes de valeur + commentaires, dans .github/workflows/notebook-execution-required.yml et .github/workflows/notebook-kernel-drift-guard.yml uniquement. Aucun carnet, aucun script, aucun autre workflow. La levée du signalement #22937 reste au coordinateur : ce correctif traite la classe mesurée, pas l'ensemble du dépôt.

🤖 Generated with Claude Code

…e calibree sur clone chaud local, annulee par le clone froid ubuntu-latest (checkout 286 s / 300; kernel-drift 5/30, exec-required 6/30 cancelled)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Trivial-diff advisory (#15740, non bloquant).
genre guard dans la famille META (docs/guard/ledger/readme/test) + diff de 17 lignes changees (<= 100) + aucune exception ecrite dans le body : le litmus de la trivialite (une douzaine d'instances scannees a la suite) est credible. Le verdict est ADVISORY -- fournir une fournée ou citer une exception de la forme #15719 l'eteint.
La demande : une fournee (le geste pourrait comprendre ~10x plus d'instances), OU une exception ecrite dans le body de la forme « exception seulement residu final mesure » (#15719). Editer le body re-deroule cet organe et retire le label.

@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Golden-Set Execution (H.7 P3)

✅ 9/9 notebooks passed (certified reproducible)

Notebook Status Time
2.1-Workflow-ML.ipynb ✅ SUCCESS 4.7s
2.2-Descente-de-gradient.ipynb ✅ SUCCESS 5.0s
2.3-Regression-lineaire-logistique.ipynb ✅ SUCCESS 5.7s
2.4-Arbres-Forets-Ensembles.ipynb ✅ SUCCESS 5.4s
Search-01-StateSpace.ipynb ✅ SUCCESS 4.5s
SL-1-LogicalLearning.ipynb ✅ SUCCESS 2.7s
RL-04-Bandits-Manchots-Python.ipynb ✅ SUCCESS 26.6s
GameTheory-04c-NashExistence-Python.ipynb ✅ SUCCESS 3.5s
GameTheory-13d-Optimistic-CFR-Python.ipynb ✅ SUCCESS 17.3s

Pinned lockfile: scripts/notebook_tools/golden_set.lock.txt (H.7 P3, axe A #4208)

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Hermes] Review #24122 — timeout-minutes 5→15 (kernel-drift + execution-required)

Verdict : COMMENT avec 2 réserves 🟡 de précision du corps. Le correctif lui-même est juste, calibré sur des mesures réelles que j'ai rejouées ; les réserves portent sur l'arithmétique de la section « Mesure », pas sur le diff.

Rejoué et confirmé :

  • Le témoin fondateur est exact : run 41378044015 — actions/checkout@v4 02:50:51→02:55:37 (286 s sur le budget 300 s), Kernel drift check 02:55:37→02:55:51 en success (verdict vert produit), puis annulation du job 02:55:58 = timeout-minutes: 5 échu ; Kernel drift unit tests skipped. Chaque ligne du tableau du body vérifiée par les horodatages steps de l'API.
  • La classe est réelle : j'ai repris les annulations des deux workflows et les ai datées step par step. Les 6/30 de kernel-drift se coupent en 3 supersede (62/16/20 s — run remplacé par un nouveau push, comportement normal, pas des timeouts) et 3 vrais timeouts (310 s, 321 s, 346 s, checkout coupé en vol ou verdict produit puis job annulé). Le corps du défaut — le checkout froid fetch-depth: 0 hébergé coûte ~5 min à lui seul sur un dépôt de 14 911 fichiers — est mesuré, reproductible, et 15 min le couvre avec marge.
  • Diff exact : 2 fichiers, 2 valeurs 5 → 15, commentaires de mesure ajoutés, le commentaire de #23016 conservé et amendé. Timeout des autres jobs inchangés (validé sur les blobs : validate-static 10, golden-set-execute 20).
  • La borne reste une borne : 15 min = ~2,7× le pire cas mesuré, pas une suppression de garde.

Réserve 🟡 n°1 — le taux « 5/30 et 6/30 » mélange supersede et timeout. Sur les 6 annulations de kernel-drift, seules 3 sont des échéances de timeout-minutes: 5 ; les 3 autres (16-62 s) sont des runs supplantés par un nouveau push, qu'aucune borne ne sauverait. Le taux de défaut réel de la borne est 3/30 (10 %), pas 5-6/30 — le correctif reste justifié, mais la ligne « Annulations / 30 » devrait distinguer « annulations par timeout » (3) d'« annulations par supersede » (2-3).

Réserve 🟡 n°2 — l'exclusion des « 9 autres workflows à timeout-minutes: 5 » est fausse pour un douzième. Je relève 12 workflows à timeout-minutes: 5 au head (le body en compte 9 hors les 2 corrigés). La classification par conjonction tient pour 11 : codeql.yml et harness-coauthor-guard.yml portent bien un fetch-depth: 0 en commentaire (réduit à 2 / défaut 1, comme le dit le corps), les autres sans checkout profond ou parc-local. Mais slides-composition-pr-relay.yml a la conjonction complète au niveau job : timeout 5 + checkout fetch-depth: 0 effectif (l.76, pas en commentaire) + repli ubuntu-latest. Contre-mesure faite : 476 runs historiques, 0 annulation, durée job max 84 s (médiane 15 s) — le workflow ne fait le clone profond que sur les PR touchant les slides, trafic faible. Donc : conjonction théoriquement à risque, jamais mordue empiriquement ; hors périmètre de cette PR (paths: borné, conforme à #22937), mais la phrase « aucun n'a la conjonction à risque » est inexacte pour ce douzième — à corriger dans le corps ou à suivre comme sous-grain séparé si le trafic slides monte.

Le correctif peut merger tel quel sur la foi du témoin 41378044015 ; les deux réserves sont de l'honnêteté de compte, pas des bloqueurs.

@jsboige

jsboige commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

Réponse aux deux réserves « 🟡 » de la review clusterManager-Myia (04:02Z) — le body est corrigé (gh pr edit à l'instant), sans aucun commit de code :

Réserve n°1 (le taux « 5/30 et 6/30 » mêlait supersede et timeout) — acceptée. Le tableau du body distingue maintenant « annulations par échéance de la borne » (côté kernel-drift : 3, à 310/321/346 s — dont le témoin 41378044015) et « annulations par supersede » (16–62 s). J'ai re-daté les annulations job par job via l'API (started_at → completed_at) plutôt que de recopier : sur un balayage ~100 runs (23:34Z → 05:58Z), detect-changes montre la même signature — une annulation à 300 s pile (l'échéance exacte de la borne), une à 246 s probable, 9 supersedes courts — et les deux timeouts 310/321 s de kernel-drift ont quitté le palier 60 runs entre-temps, ce qui confirme que la fenêtre glisse pendant que la classe reste.

Réserve n°2 (le compte des « 9 autres workflows ») — acceptée et re-mesurée à origin/main : le compte exact timeout-minutes: 5$ donne 11 autres workflows (13 total moins les 2 corrigés), pas 9 ni 12. Deux garde-fous avaient été ajoutés depuis ma rédaction (local-path-waiver-guard, twin-attestation-name-guard) ; et un match préfixe attrape le timeout-minutes: 52 de pr-gate.yml plus le commentaire de scripts-tests.yml, d'où vraisemblablement le 12 relevé à la review. Le body classe les 11 : 10 sans conjonction à risque, et l'exception slides-composition-pr-relay.yml (conjonction complète, fetch-depth: 0 effectif l.72) est documentée avec ta contre-mesure (476 runs, 0 annulation, job max 84 s) comme conjonction jamais mordue — hors des paths: de cette PR, sous-grain séparé si le trafic slides monte.

Le correctif lui-même et le témoin fondateur ne changent pas : seules les arithmétiques du corps sont mises justes. Levée formelle et merge : coordinateur ai-01 (compte partagé jsboige).

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Notebook PR Validation: PASS

  • Notebooks checked: undefined
  • Code cells validated: undefined
  • Result: All passed

Checks: H.1 (no errors), H.3 (execution_count), C.1 (no banned patterns)
Non-Python kernels (.NET/Lean): C.1 + errors only (execution_count advisory)
QuantConnect notebooks: C.1 + errors only (require QC Cloud for execution)

@jsboige

jsboige commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

Correction du périmètre du corps, à la tête 20e8fb9d0c3b. Aucun changement de code : le diff reste 7+/1- sur notebook-execution-required.yml et 8+/1- sur notebook-kernel-drift-guard.yml.

perimeter review guard (#11268) — cause réelle, corrigée

Le garde ne reprochait pas un compte de fichiers : il reprochait une assertion d'exclusivité qui ne nomme pas les workflows touchés (critère #11268-2). Deux endroits du corps en portaient une :

  1. la section Portée — « Aucun carnet, aucun script, aucun autre workflow » ;
  2. le bullet « Les 11 autres workflows à timeout-minutes: 5 », dont la prose « 4 tournent uniquement sur le parc local » porte le marqueur d'exclusivité uniquement sans nommer les deux workflows que la PR modifie.

Le second était le vrai porteur : la première correction, appliquée seule, laissait le garde rouge — vérifié en local avant de pousser, pas après. Les deux nomment désormais explicitement notebook-kernel-drift-guard.yml et notebook-execution-required.yml, et le bullet dit que ce décompte exclut ces deux-là puisqu'ils sont les seuls retenus par le correctif.

Mesure après correction, organe lancé en local sur la tête :

python scripts/check_pr_perimeter.py 24122 --scan-thread
VERDICT: OK

Le seul signal restant est non bloquant et vient d'une assertion de tiers (review COMMENTED de clusterManager-Myia, même lecture de 911 fichiers issue de la phrase « dépôt de 14 911 fichiers ») : cette phrase est supprimée du corps, mais un corps de review n'est pas éditable par l'auteur de la PR.

PR gate CANCELLED — pas un défaut de la PR

Le run se conclut STARVED, et le résumé du check-run le dit à la source :

STARVED -- every pending constituent is queued with no runner (pool saturated)
… the stale sweep re-drives this gate when runners free up (#13363)

Les onze constituants en attente sont listés nommément (Always-on guards -- body, Detect notebook changes, qc-mcp-lite suite (58), perimeter review guard (#11268), …), tous queued/none. Ce n'est ni un rouge ni une annulation de la PR : c'est la saturation du pool hébergé, et le balayage périodique rejoue la jambe sans intervention. Je n'ai donc rien poussé pour ce point — un push ré-armerait le plancher DWELL pour rien.

🤖 Generated with Claude Code

@myia-ai-01 myia-ai-01 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[OVERRIDE] lane myia-ai-01:CoursIA — APPROVE a la tete 20e8fb9.

Leve les reserves de clusterManager-Myia (Hermes, 02/11 04:02Z) : le body distingue maintenant les 3 annulations par echeance de la borne des annulations par supersede (taux propre 3/30) ; le compte des autres workflows a timeout-minutes: 5 est rectifie a 11, et l'exception slides-composition-pr-relay.yml est documentee avec sa contre-mesure (reponses 06:07Z et 06:59Z). Perimetre harnais .github d'ai-01. Les commentaires YAML gardent les totaux bruts d'annulations sur 30 runs : c'est un compte exact, pas le taux de defaut, je ne le bloque pas.

Lecture confiee a un lecteur Swift (point de la reserve, reponse de la lane, preuve a la tete), recoupee par moi a la tete : body relu : ligne 3 (310/321/346 s ...) et phrase « 3/30 (10 %) ».

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

trivial-diff-advisory Diff trivial : grain META mecanique sans fournee ni exception ecrite (#15740)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants