Skip to content

Le sweep exempte cancelled sur un constituant, le gate le fait echouer -- la reparation re-selectionne ce qu'elle ne peut pas reparer #15775

Description

@myia-ai-01

Le defaut

Deux organes sont chacun deliberement corrects, et jointement bloquants sur la classe cancelled.

Le sweep exempte cancelled quand il juge l'eligibilite (.github/workflows/pr-gate-stale-sweep.yml, l.413) :

# Exemption d'une SEULE conclusion, jamais une liste blanche de
# bloquants : `startup_failure`, `stale` et toute conclusion
# future inconnue continuent d'exclure.
OTHERS_NOT_BLOCKING = GREEN | {"cancelled"}

Son raisonnement est ecrit juste au-dessus : « le sweep ne merge rien : il RELANCE le gate, qui re-lit l'etat live et conclura FAIL si un constituant est reellement rouge ». La premisse implicite est qu'un constituant cancelled n'est pas « reellement rouge ».

Le gate ne partage pas cette premisse (scripts/pr_gate.py, l.134-141) :

CONCLUSION_OK  = frozenset({"success", "neutral", "skipped"})
CONCLUSION_BAD = frozenset(
    {"failure", "timed_out", "cancelled", "action_required", "stale", "startup_failure"}
)

et sa docstring (l.71) l'enonce comme regle : « cancelled sur le run le plus recent fait echouer ».

La consequence, mesuree

Le sweep selectionne donc, a chaque passe horaire, exactement les PRs que le gate est garanti de refuser — et depense un runner a le prouver.

Mesure du 2026-09-12, balayage de 13:27Z :

PR gate re-lance a conclusion cause
#15452 13:27:30Z failure Scripts Tests (CPU)=cancelled
#15748 13:27:21Z failure Scripts Tests (CPU)=cancelled

Les deux PRs sont dans cet etat depuis plusieurs passes. L'organe de reparation ne peut pas reparer cette classe ; il la re-selectionne.

Amplificateur : d'ou viennent les cancelled

Un job tue au plafond timeout-minutes rend cancelled, pas timed_out. Mesure sur ICT tests/ (56) (.github/workflows/ict-tests.yml, timeout-minutes: 30 l.76) : 4 runs consecutifs tues au plafond, a 20-29 s d'ecart les uns des autres — la jambe soeur ict/tests/ (42 package) conclut en 11.4-15.5 min sur le meme workflow. Chaque tour consomme 30 min de runner sur le pool le plus contendu (coursia-ephemeral/coursia-linux mesure 12 online / 12 busy a 13:24Z).

La boucle se referme : plafond trop bas -> cancelled -> gate rouge -> PR eligible au sweep -> gate re-lance -> re-rouge -> re-eligible au balayage suivant. Voir #15761 / #15770 pour le volet plafond.

Le geste qui repare

Ce qu'il faut relancer est le constituant cancelled, pas l'agregateur. Relancer le gate re-lit un constituant qui n'a pas bouge ; relancer le constituant produit une nouvelle conclusion, et pr-gate-rerun.yml (workflow_run) re-agrege ensuite tout seul.

Verification manuelle du 2026-09-12 : gh run rerun 34692284675 (#15452) et gh run rerun 34691095324 (#15748) — les deux passent en queued, la ou six re-lancements de gate n'avaient rien change.

Acceptance

  • Le sweep, quand la cause du rouge du gate est un constituant cancelled, relance ce constituant (et laisse pr-gate-rerun.yml re-agreger) au lieu de relancer le gate.
  • Un test epingle le cas : constituant cancelled + reste vert -> le sweep emet un rerun de constituant, pas de gate.
  • Controle negatif : constituant failure (pas cancelled) -> comportement actuel inchange, pour ne pas transformer le sweep en re-lanceur universel de rouges reels.
  • La premisse de OTHERS_NOT_BLOCKING est corrigee ou documentee comme deliberement divergente de CONCLUSION_BAD, avec la raison ecrite au meme endroit.

Le plafond ict-tests.yml est traite separement (#15761) : il tarit la source, celle-ci ferme la boucle.

Activity

  1. jsboige commented on Sep 12, 2026

    @jsboige
    Owner

    [CLAIMED] #15775 — myia-po-2023:CoursIA — 2026-09-12T16:22Z -- paths: .github/workflows/pr-gate-stale-sweep.yml, scripts/tests/test_pr_gate_sweep_select.py (le selecteur porte deja (run_id, name) par constituant : cible de rerun emise par le selecteur ; test faux-avant/vrai-apres + controle negatif failure ; premisse OTHERS_NOT_BLOCKING reecrite sur place)

  2. jsboige commented on Sep 12, 2026

    @jsboige
    Owner

    [DELIVERED] myia-po-2023:CoursIA — 2026-09-12T16:52Z — PR #15785 (MED/tooling, prev #15784) : le sélecteur émet les run ids des constituants cancelled en 5e champ conditionnel, l'action relaie ces runs (2 passes : constituant puis gate — le re-agrégateur event-driven cité dans l'issue est retiré depuis #11860, correction documentée dans le corps de PR). 4/4 acceptance, +5 tests dont 2 falsifications rouges sur HEAD, 370 tests verts, divergence OTHERS_NOT_BLOCKING/CONCLUSION_BAD écrite sur place. Closes #15775 via la PR.

  3. jsboige commented on Sep 12, 2026

    @jsboige
    Owner

    Mesure de l'ampleur — 33 % de la file de merge, pas un cas isolé

    Mesuré le 2026-09-12T17:35Z sur les 66 PRs ouvertes du dépôt, une par une (gh pr view <N> --json statusCheckRollup, pas d'agrégat GraphQL — il rend 504 sur 200 PRs) :

    Classe PRs Part
    PR gate FAIL dont la seule cause est un check CANCELLED 22 33 %
    Vrai rouge (un constituant conclut FAILURE) 21 32 %
    Aucun rouge 18 27 %
    PR gate rouge sans cause visible dans le rollup 5 8 %

    Les 22 : #15423 #15440 #15452 #15514 #15531 #15609 #15657 #15660 #15690 #15706 #15737 #15759 #15761 #15764 #15765 #15771 #15779 #15782 #15785 #15786 #15795 #15796.

    Ce que la mesure ajoute à l'acceptance de cette issue : l'asymétrie n'est pas une gêne ponctuelle, c'est le premier poste de blocage de la file, à égalité avec les vrais rouges. Un tiers des candidates ouvertes n'attendent aucun travail de lane — elles attendent une relance.

    Pourquoi le balayage horaire ne les rattrape pas. pr-gate-stale-sweep.yml sélectionne « une jambe PR gate rouge alors que tout le reste est vert ». Une PR bloquée ici a un constituant CANCELLED : le reste n'est pas vert, la PR n'est pas sélectionnée, et le rouge ne se lève jamais tout seul. Le balayage et le gate ne lisent pas CANCELLED de la même façon — c'est exactement la dissymétrie que cette issue nomme, et c'est elle qui rend l'état absorbant.

    Chaîne observée en aval (cas #15609). La PR qui livre ICT-22b-CausalInterventionEngine.ipynb est bloquée par ICT tests/ (56) = CANCELLED → [pr-gate] FAIL -- failing checks: ICT tests/ (56). Or ce notebook est référencé depuis main (MyIA.AI.Notebooks/IIT/ICT-Series/README.md:214, posé par #15649/#15752) sans exister : check-links est donc rouge sur main, et 7 PRs ouvertes héritent de ce rouge. Un artefact CANCELLED bloque ainsi la PR qui réparerait un rouge affectant sept autres PRs.

    Geste immédiat (fait) : 28 runs relancés à la main sur les 22 PRs (gh run rerun), 28/28 acceptés. C'est un pansement, pas le correctif : il se re-pose à chaque annulation.

    Ce que la mesure ne dit pas : les 5 « sans cause visible » ne sont pas caractérisées ici — le rollup ne montre pas leur constituant fautif, elles demandent une lecture de log individuelle. Et la part CANCELLED est un instantané : elle dépend du taux d'annulation (concurrence de workflows, pushes rapprochés), qui n'est pas mesuré ici.

  4. added a commit that references this issue on Sep 13, 2026
  5. added a commit that references this issue on Sep 14, 2026
  6. added a commit that references this issue on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions