Skip to content

bug(picker): base_inherited classe « cause sur main » un rouge d'infra que main ne porte pas — la lane est dissuadée du rejeu qui le répare #17154

Description

@jsboige

Symptôme

pick_idle_grain.py déclare Scripts Tests (CPU) « imputé à la base — pas le vôtre, pas réparable par la lane — tâche COORDINATEUR » sur la foi d'une corroboration ≥ 2 lanes distinctes (règle #13545/#14537, implémentée autour de scripts/pick_idle_grain.py:2076 et exposée dans base_inherited).

Or main est vert sur cette jambe. La corroboration inter-lanes ne prouve pas une cause commune sur main ; elle prouve une cause commune, qui peut être une instabilité d'exécution.

Mesure firsthand (2026-09-21)

Surface Scripts Tests (CPU)
main bf212573c0 (run 35548767997, 00:46:41Z) success
PR #16612 fail
PR #17136 fail
PR #17141 fail
PR #16971 fail
PR #17144 / #17142 (mesurées après rejeu) non en échec

Deux annotations de check-run, tirées de deux PRs distinctes, montrent que les causes sont d'exécution, pas de code :

Le second cas est déjà tracké (#16288, OPEN). Le premier ne l'est pas.

Conséquence mesurée, et pourquoi ce n'est pas cosmétique

Le libellé dit à la lane deux choses fausses dans ce cas :

  1. « pas le vôtre » — vrai au sens du diff, mais la conséquence pratique est qu'aucune action n'est demandée ;
  2. « pas réparable par la lane » — faux : un gh run rerun <run_id> --failed à tête constante lève le rouge. Vérifié le 2026-09-21 sur fix(#17066): Search-09d — retitrer 10 lectures uniformes (tranche 17) #17144 : après rejeu, le PR gate rend [pr-gate] settled: 81 check(s) green, et le seul rouge restant est le minuteur DWELL.

La lane est donc dissuadée du seul geste qui répare. Le rouge s'installe, la PR reste bloquée, et elle finit par remonter dans le red du picker comme grain de réparation — c'est-à-dire que le cycle suivant de la lane est consommé à re-découvrir un rouge qu'un rejeu aurait levé. C'est le mécanisme même du « résidu de vieilles PRs » que le prompt /continue décrit.

Cause précise dans l'organe

inherited est construit par nom de check sur ≥ 2 lanes distinctes. Aucune des deux mesures décisives n'est prise :

  • l'état du même check sur la tête de la branche par défaut (main) — mesurable, et ici concluant :
  • la nature du rouge (une mort de runner et un kill watchdog ne sont pas des verdicts de test).

Le commentaire du code assume d'ailleurs l'ambiguïté pour un cas voisin (#15764, ligne ~2096) : « la coexistence d'un constituant COUPÉ dans le rollup n'établit PAS la causalité ». Le même raisonnement s'applique ici : plusieurs PRs qui tombent ensemble n'établissent pas que la cause est sur main.

Correctif proposé

Avant de classer un nom de check en base_inherited, exiger en plus de la corroboration ≥ 2 lanes que le même check soit rouge sur la tête courante de main :

  • rouge sur main → base_inherited (formulation actuelle, correcte : cause sur la branche par défaut, réparateur unique = coordinateur) ;
  • vert sur main → infra d'exécution : classe distincte, avec le message et le geste adaptés — « rejeu de la jambe (gh run rerun <run_id> --failed), à tête constante, sans ré-armer DWELL ». Ne pas router vers le coordinateur, qui n'a rien à réparer.

Un seul appel gh api .../commits/<main-sha>/check-runs fournit la mesure.

Ce que cette issue ne dit pas

Références

Activity

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

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions