Skip to content

fix(ci,#17255): Test 37 borne le silence, plus la duree - #17258

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/17255-test37-budget-race
Sep 22, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/17255-test37-budget-race

Conversation

@jsboige

@jsboige jsboige commented Sep 21, 2026

Copy link
Copy Markdown
Owner

Grain: LIGHT/test -- lane myia-po-2026:CoursIA -- prev: LIGHT/test #17254

Quoi: Test 37 de test_supervise_guards.sh etait flaky parce que son filet anti-blocage (timeout 60) faisait double emploi comme exigence de vitesse. Il borne desormais le silence (progression des cycles) et non la duree : une machine lente n'est plus lue comme une machine bloquee. Les trois assertions restent intactes.
Preuve: banc a un seul facteur variant, deux armes de duree identique (62 s / 64 s) qui rendent des verdicts opposes (§Mesure).
Perimetre: 1 fichier, +34/−2. Hors scope : le second symptome de l'issue (stderr bruite par wc -c < <fichier absent>, benin), qui est un sujet distinct.

La cause, dans le code

Le stub docker de Test 37 arrete la boucle sur un compteur evenementiel (STUB_STOP_AFTER=70 -> touch $STUB_STOP_FILE) : les 70 cycles doivent donc avoir lieu, quelle que soit la machine. Le timeout --kill-after=2 60 qui enveloppe supervise.sh n'est, dans l'intention, qu'un filet anti-blocage.

Mais l'assertion juste en dessous est if [ "$n" -eq 70 ], avec n = lignes du journal de cycles. Si 70 cycles de travail CPU pur depassent 60 s, le filet tue le superviseur avant le 70e cycle et l'assertion tombe — pour une raison qui n'a rien a voir avec ce qu'elle teste (l'imputation de n, le plafond, l'absence de valeur negative/nulle). Le filet etait devenu une exigence de performance deguisee.

Les mesures de l'issue (0,86 a 1,0 s/cycle selon les runs, valeurs entrelacees entre les deux armes) disent exactement cela : le budget est pile a la frontiere.

Mesure — un seul facteur varie

Emulation deterministe d'une machine plus lente : le stub sleep de Test 37 n'attend pas (il journalise seulement), on lui ajoute un sleep reel de 0,45 s. Les 70 cycles passent alors de ~30 s (mesure au repos sur cette machine) a ~61 s, soit le regime des auteurs. Aucune charge machine globale.

arme duree verdict Test 37
origin/main 62 s FAIL — « attendu 70 respirations, obtenu 68 »
ce correctif 64 s PASS — « 70 cycles effectivement deroules (obtenu 70) »
ce correctif, au repos 30 s PASS — 70 cycles

Deux armes de duree quasi identique (62 s et 64 s) rendent des verdicts opposes. C'est ce qui qualifie le correctif : il n'a pas deplace une constante (60 -> 140, ce qui n'aurait fait que reculer la frontiere et laisser le meme defaut en place pour une machine encore 2x plus lente), il a change le critere. Les 70 cycles sont forces par le stub, donc le processus se termine seul ; seule une absence de progres est desormais punie.

Regle de lecture appliquee : on synchronise sur un etat observable, pas sur une duree.

Ce qui change

( export PATH=... ; exec bash supervise.sh start 1 ... ) &   # exec : le pid EST supervise.sh
sup_pid=$!
t37_seen=0; t37_quiet=0
while kill -0 "$sup_pid" 2>/dev/null; do
  sleep 1
  <compte les lignes de sleep25.log>
  <progres -> remise a zero du compteur de silence>
  <silence >= T37_HANG_SECS (defaut 20 s) -> kill -9 + motif sur stderr>
done
wait "$sup_pid"

Deux details qui comptent, et qui mordraient :

  • exec : sans lui, le pid surveille serait celui de la coquille ( ... ), pas celui de supervise.sh — le watchdog ne surveillerait rien.
  • Le watchdog tourne dans le parent, jamais dans le sous-shell : la-bas sleep est le stub de Test 37 — il ne dort pas (boucle a vide) et il journalise dans SLEEP_LOG, le fichier meme que compte l'assertion. Un watchdog ecrit la aurait pollue la mesure qu'il surveille.

Un vrai blocage est desormais detecte en 20 s (au lieu de 60 s), et sans jamais dependre de la vitesse de la machine.

Assertions : inchangees

n -eq 70, plafond 24 des le cycle 4, et absence de valeur negative/nulle sont repris tels quels. Aucune n'est affaiblie : le banc ci-dessus montre la premiere toujours capable d'echouer (arme origin/main).

Hors perimetre, nomme

Le second symptome de l'issue — supervise.sh: line 1452: ...: No such file or directory sur stderr, du au wc -c < <fichier absent> dont l'erreur de redirection precede le 2>/dev/null porte par wc — est benin (le || echo 0 fait son travail) et distinct. Il n'est pas corrige ici.

Closes #17255

🤖 Generated with Claude Code

Test 37 de test_supervise_guards.sh etait flaky : son filet anti-blocage
(`timeout --kill-after=2 60`) faisait double emploi comme exigence de
vitesse. Le stub `docker` arrete la boucle sur un compteur evenementiel
(STUB_STOP_AFTER=70), donc les 70 cycles DOIVENT avoir lieu quelle que soit
la machine ; mais quand ils depassent 60 s, le filet tue le superviseur
avant le 70e cycle et `[ "$n" -eq 70 ]` tombe -- pour une raison sans
rapport avec ce qu'il teste.

Remplace le deadline de duree par un watchdog de PROGRESSION dans le shell
parent : kill -9 seulement apres ${T37_HANG_SECS:-20} s sans nouveau cycle.
Les trois assertions sont reprises telles quelles (n -eq 70, plafond 24 des
le cycle 4, jamais negatif/nul).

Le watchdog tourne dans le PARENT, jamais dans le sous-shell : la-bas
`sleep` est le stub de Test 37 -- il ne dort pas et journalise dans
SLEEP_LOG, le fichier meme que compte l'assertion. `exec` fait du pid du
sous-shell celui de supervise.sh, sinon on surveillerait une coquille vide.

Banc, un seul facteur varie (le stub `sleep` recoit un sleep reel de
0,45 s pour emuler une machine plus lente) : origin/main = FAIL a 62 s
(« attendu 70, obtenu 68 »), correctif = PASS a 64 s, correctif au repos =
PASS a 30 s. Deux armes de duree quasi identique rendent des verdicts
opposes : c'est le critere qui a change, pas la constante.

Hors perimetre (nomme dans la PR) : le stderr bruite par
`wc -c < <fichier absent>` dans supervise.sh, benin et distinct.

Closes #17255

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions github-actions Bot added variation-tag-missing PR sans tag Grain: <TIER>/<GENRE> (variation-protocol) trivial-diff-advisory Diff trivial : grain META mecanique sans fournee ni exception ecrite (#15740) labels Sep 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Trivial-diff advisory (#15740, non bloquant).
genre test dans la famille META (docs/guard/ledger/readme/test) + diff de 36 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

Copy link
Copy Markdown
Contributor

Grain tag obligatoire (#10045, bloquant).

Grain tag absent (no Grain: / in body).

Pour passer ce gate, le body doit porter en tete une ligne de la forme :

Grain: <DEEP|MED|LIGHT>/<genre> -- lane <machine:workspace> -- prev: <TIER>/<GENRE> #<PR>

Le <genre> doit figurer dans l'enumeration §1 de variation-protocol.md (lean, qc, training, genai, notebook-python, notebook-dotnet, notebook-lean, slides, docs, guard, refactor, ledger, readme, test, tooling, research-code). Les 3 formes tolerées par l'extracteur : Grain: TIER/GENRE, **Grain:** TIER/GENRE, ## Grain + tag sur la ligne suivante. La lane doit suivre le format <machine>:<workspace> (cf. lane-claim-protocol.md).

@github-actions

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.

@github-actions github-actions Bot removed the variation-tag-missing PR sans tag Grain: <TIER>/<GENRE> (variation-protocol) label Sep 21, 2026
@jsboige

jsboige commented Sep 22, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2026:CoursIA-3
pr: 17258
head: b5d354f
complete: true
body: read
comments-reviewed: 3
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: cc26f80dc98bd35bf751799f1e33f52073eb0c724e9fb416da6ccfab38b51b7f
diff-files: 1
diff-additions: 34
diff-deletions: 2
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

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.

2 participants