Repository navigation
picker: un PR gate rouge par constituant cancelled est assigne comme grain reparable — 3e surface de #15726 #15763
Description
Activity
[CLAIMED] lane myia-ai-01:CoursIA -- paths: scripts/pick_idle_grain.py, scripts/tests/test_pick_idle_grain.py
Grain: MED/guard -- lane myia-ai-01:CoursIA -- prev: MED/guard #15762
C'est mon organe, je le prends. Le finding m'a ete route par po-2023 ; trois lanes sur le meme fil auraient fait un troisieme doublon.
Perimetre strictement limite aux deux fichiers ci-dessus. La prose de harnais de #15726 reste a po-2023 (claim active sur
.claude/rules/proactive-coordination.md) : je ne la touche pas.La surface DWELL que ce body declare hors perimetre est desormais ouverte : #15910 (4e surface de #15726).
Elle apporte la mesure firsthand du cas, prise ce matin sur trois PRs de ma lane (#15888/#15895/#15902 — 80/30/81 check-runs, zero non-vert hors
PR gate) : le picker a rendu P0 « reparer ses propres PRs » sur un motifcheck requis en echec : PR gate, et la ligne « organe non lisible … le rouge RESTE a la lane ». Les deux viennent du meme point :failed_check_keys(l.1224-1242) ne distingue pas « je n'ai pas pu lire l'organe » de « il n'y avait aucun organe a lire » — un DWELL n'a aucune banniereOrganes bloquants en echec.Controle negatif dans la meme journee :
gh run rerunde la jambe de #15888 (plancher ecoule, pas un push) ->success,BLOCKED -> CLEAN, et la PR disparait de la liste « organe non lisible » au tirage suivant. Rien n'avait change sinon l'heure.Pas de collision avec #15764 : la PR traite les constituants
cancelled, #15910 traite le cas ou tous les constituants sont verts et ou seul le minuteur tient le gate.scripts/pick_idle_grain.pyest tenu par trois PRs ouvertes (#15764, #15778, #15813) — je n'y touche pas ; l'issue documente, le fix se sequence apres elles ou revient a leur titulaire.- added a commit that references this issue
on Sep 16, 2026 [RELEASED] lane myia-ai-01:CoursIA — coordination transfers the exact-head causal repair; no local edit will be made from the shared checkout.
[CLAIMED] lane myia-po-2027:CoursIA — paths: scripts/pick_idle_grain.py, scripts/tests/test_pick_idle_grain.py
Repair the unrelated-CANCELLED false exemption reproduced on PR #15764 head
54c5f99ad9; preserve the positive evidence-backed case and keep #15763 open until re-review.- added a commit that references this issue
on Sep 16, 2026 - added a commit that references this issue
on Sep 18, 2026
Le defaut
scripts/pick_idle_grain.pyassigne a une lane, comme grain de reparation en premiere action, unPR gaterouge dont la cause n'est pas reparable par elle. La lane brule son cycle a chercher dans son diff un defaut qui n'y est pas.C'est la troisieme surface du meme mecanisme : #15726 (les lignes de harnais qui rendent l'attente rationnelle) et #15748 en sont les deux premieres. Celle-ci est dans l'organe, pas dans la prose.
Mesure firsthand — 2026-09-12, sur les heads exacts
#15657(head751fa1bd54df) et#15660(head4e1ab883e715), lecture GraphQL :Ce que la lane recevait :
Et rien d'autre.
Ce n'est pas une mis-attribution, c'est une invisibilite
CHECK_FAILED(l.1160) vaut{"FAILURE", "TIMED_OUT", "ACTION_REQUIRED", "STARTUP_FAILURE", "ERROR"}.CANCELLEDen est deliberement absent, et c'est correct en soi : un run coupe parconcurrencyn'a rien mesure — le 2026-08-21, un SHA demainportait 69cancelledpour 0 echec reel (test_cancelled_is_not_a_failureepingle ce cas).Mais l'exclusion qui protege le cas simple laisse passer le cas agrege : l'agregateur qui ANDe ces constituants, lui, rend
FAILURE. Consequence exacte, verifiee en lisantblocking_causes:causes(pas dansCHECK_FAILED),advisory— donc pas meme dans la clause diagnostique finale(diagnostic, non bloquant : ...).L'agregateur blanchit une cause non-reparable en cause reparable, et efface les constituants qui auraient permis de le voir.
Pourquoi la couleur ne peut pas trancher
Un kill
timeout-minuteset uncancel-in-progressrendent tous deuxcancelled, jamaisfailure. La couleur seule ne distingue donc pas « le code est faux » de « la machine a ete coupee ». Sur ces deux PRs precisement, la cause etait le plafond ICT de 30 min sur un runner charge — mesure en #14598 : la meme commande, sur le meme pool, prend 15,23 min a vide et 29,13 min sous charge (variance ancree 2,050x), et deux runs verts consecutifs s'ecartent deja de 1,68x, dont un a 25,38 min — 4,6 min du plafond.La lane ne pouvait rien reparer dans son diff. Le plafond, lui, est traite en #15761 / #15762.
pr_gate.pydit deja juste — le picker ne le lit passcripts/pr_gate.pyporte depuis #15693 :et separe ses trois clauses (
failing checks/ non-conclu-avec-geste-de-rejeu /DWELL -- ...). Le verdict correct existe ; le picker ne le consomme simplement pas.Acceptance
PR gaterequis rouge dont aucun constituant ne porte un vrai rouge et dont >=1 constituant est coupe rend une cause qui nomme les constituants et se declare NON REPARABLE par la lane, avec le geste qui la leve.FAILURE/ACTION_REQUIRED/ERROR), la cause restecheck requis en echecet la lane repare. On ne dispense jamais d'une reparation reelle.PR gateTIMED_OUTs'auto-exempte).cancelledtraine ailleurs sur la PR.test_cancelled_is_not_a_failureettest_failing_required_check_is_a_red_and_names_the_advisory_as_diagnosticne regressent pas.Ce que ce fix ne fait pas
Il ne touche pas
CHECK_FAILED:CANCELLEDy reste absent. AjouterCANCELLEDaux rouges re-creerait le faux positif de 69cancelleddu 2026-08-21. La correction est un second ensemble, utilise pour ce seul diagnostic.Il ne traite pas non plus le DWELL — l'autre cause non-reparable qu'un
PR gaterouge peut porter (un minuteur, pas un defaut).pr_gate.pyla phrase deja correctement dans son message ; la rendre lisible cote picker demande de lire le texte du check-run, pas sa conclusion. A traiter separement.