Quand pick_idle_grain.py assigne la reparation d'une PR rouge, il propose trois gestes, dans cet ordre :
gh pr update-branch <N> : rejoue les checks sur une tete fraiche.
- conflits : rebaser sur origin/main,
--force-with-lease [...]
- corriger la substance, pousser, et REPONDRE par ecrit [...]
Aucun des trois ne leve un blocage adjacency (G-VAR-3, #11170). La lane qui suit le conseil boucle.
Mesure
scripts/ci/variation_adjacency_guard.py expose exactement trois entrees :
--body-file FILE # le corps de la PR
--comments-file FILE # les commentaires, pour le marqueur [G-VAR-3 OVERRIDE]
--merged-prs-file FILE # la sequence mergee, pour resoudre le predecesseur reel
Ni le diff, ni la base, ni le SHA de tete n'entrent dans le predicat. Un update-branch ou un rebase ne modifie aucune de ces trois entrees : le verdict revient bit-pour-bit identique.
Execute le 2026-09-01T04:47Z sur deux PRs reellement tenues, a leur tete du moment, sans rien modifier :
| PR |
verdict |
| #13949 |
guard_pass=False blocking=True genre=guard prev=guard prev_pr=13940 |
| #13951 |
guard_pass=False blocking=True genre=guard prev=guard prev_pr=13940 |
Le geste 3 (« corriger la substance, pousser ») est le plus trompeur des trois : il existe une correction, mais elle n'est pas dans le code — elle est dans le genre du grain suivant. Un lecteur qui lit « corriger la substance » ira relire son diff, ou il n'y a rien a trouver.
Portee mesuree
Au moment de la mesure, 13 PRs ouvertes sont tenues par adjacency sur les 25 rouges mesurables — la cause dominante, devant tag_required (5), lane_claim (3), perimeter (2), prev_guard (1), fastlane (1).
Repartition par lane : myia-po-2026:CoursIA 6 · myia-po-2026:CoursIA-2 4 · myia-ai-01:CoursIA 2 · myia-ai-01:myia-open-webui 1.
Ce n'est donc pas un cas de bord : c'est la premiere cause de rouge de la flotte, et c'est celle dont le conseil de reparation est faux.
Ce que le conseil devrait dire
L'organe resout le predecesseur sur la sequence mergee (prev_source: merged-sequence), pas sur le champ prev: declare. La consequence est actionnable et vaut d'etre ecrite :
Chaque merge d'un grain d'un AUTRE genre laisse passer exactement une PR de la file.
Le remede est donc « produire un grain d'un autre genre », jamais « pousser ». Et le retag est nommement interdit (§2 : « piochez un grain d'UN AUTRE genre, ne retaguez pas le meme travail ») — un conseil de reparation qui ne le rappelle pas invite au contournement qu'il devrait fermer.
Note : l'organe dit deja la bonne chose dans son propre message d'echec (« piochez un grain d'UN AUTRE genre »). C'est le picker qui, en re-emballant le rouge dans sa liste generique de trois gestes, ecrase ce message par un conseil faux. Le defaut est dans la couche qui resume, pas dans celle qui mesure.
Acceptance
- Quand la cause d'un rouge est
adjacency, le picker n'affiche pas les trois gestes generiques ; il affiche le remede propre a cette cause (produire un grain d'un autre genre) et rappelle l'interdit de retag.
- Un test epingle le cas : entree = une PR bloquee par
adjacency, sortie = ne contient pas update-branch.
- Le controle positif du meme test : une PR rouge pour une cause reparable par push (
PR gate sur un vrai echec de test) continue d'afficher les trois gestes. Sans lui, la correction pourrait supprimer le conseil pour tout le monde et le test passerait quand meme.
Ce qui n'a pas ete mesure
Je n'ai pas lu le code du picker qui compose ce bloc de conseil — le verdict porte sur ce qu'il affiche (reproduit sur deux lanes) et sur ce que l'organe d'adjacence consomme (lu dans son --help et execute). Je n'ai pas verifie si d'autres causes (lane_claim, prev_guard) souffrent du meme re-emballage ; c'est plausible et non mesure.
Quand
pick_idle_grain.pyassigne la reparation d'une PR rouge, il propose trois gestes, dans cet ordre :Aucun des trois ne leve un blocage
adjacency(G-VAR-3, #11170). La lane qui suit le conseil boucle.Mesure
scripts/ci/variation_adjacency_guard.pyexpose exactement trois entrees :Ni le diff, ni la base, ni le SHA de tete n'entrent dans le predicat. Un
update-branchou un rebase ne modifie aucune de ces trois entrees : le verdict revient bit-pour-bit identique.Execute le 2026-09-01T04:47Z sur deux PRs reellement tenues, a leur tete du moment, sans rien modifier :
guard_pass=False blocking=True genre=guard prev=guard prev_pr=13940guard_pass=False blocking=True genre=guard prev=guard prev_pr=13940Le geste 3 (« corriger la substance, pousser ») est le plus trompeur des trois : il existe une correction, mais elle n'est pas dans le code — elle est dans le genre du grain suivant. Un lecteur qui lit « corriger la substance » ira relire son diff, ou il n'y a rien a trouver.
Portee mesuree
Au moment de la mesure, 13 PRs ouvertes sont tenues par
adjacencysur les 25 rouges mesurables — la cause dominante, devanttag_required(5),lane_claim(3),perimeter(2),prev_guard(1),fastlane(1).Repartition par lane :
myia-po-2026:CoursIA6 ·myia-po-2026:CoursIA-24 ·myia-ai-01:CoursIA2 ·myia-ai-01:myia-open-webui1.Ce n'est donc pas un cas de bord : c'est la premiere cause de rouge de la flotte, et c'est celle dont le conseil de reparation est faux.
Ce que le conseil devrait dire
L'organe resout le predecesseur sur la sequence mergee (
prev_source: merged-sequence), pas sur le champprev:declare. La consequence est actionnable et vaut d'etre ecrite :Le remede est donc « produire un grain d'un autre genre », jamais « pousser ». Et le retag est nommement interdit (§2 : « piochez un grain d'UN AUTRE genre, ne retaguez pas le meme travail ») — un conseil de reparation qui ne le rappelle pas invite au contournement qu'il devrait fermer.
Note : l'organe dit deja la bonne chose dans son propre message d'echec (« piochez un grain d'UN AUTRE genre »). C'est le picker qui, en re-emballant le rouge dans sa liste generique de trois gestes, ecrase ce message par un conseil faux. Le defaut est dans la couche qui resume, pas dans celle qui mesure.
Acceptance
adjacency, le picker n'affiche pas les trois gestes generiques ; il affiche le remede propre a cette cause (produire un grain d'un autre genre) et rappelle l'interdit de retag.adjacency, sortie = ne contient pasupdate-branch.PR gatesur un vrai echec de test) continue d'afficher les trois gestes. Sans lui, la correction pourrait supprimer le conseil pour tout le monde et le test passerait quand meme.Ce qui n'a pas ete mesure
Je n'ai pas lu le code du picker qui compose ce bloc de conseil — le verdict porte sur ce qu'il affiche (reproduit sur deux lanes) et sur ce que l'organe d'adjacence consomme (lu dans son
--helpet execute). Je n'ai pas verifie si d'autres causes (lane_claim,prev_guard) souffrent du meme re-emballage ; c'est plausible et non mesure.