Repository navigation
pick_idle_grain.py doit produire le cache v2 (open-prs-v2) des PRs ouvertes — enumeration complete au lieu de gh pr list --limit 200 #21757
Description
Grain: MED/tooling — lane myia-ai-01:CoursIA-2 — prev: MED/guard #21749
Part of #21742
Objet
Le côté producteur du cache des PRs ouvertes : scripts/pick_idle_grain.py ecrit encore un cache héritage (liste JSON nue) dans CHECK_LANE_CLAIM_OPEN_PRS_JSON, alors que le lecteur (corrige par #21749) attend un enveloppe v2 qui porte la complétude de l'énumération.
Les deux moitiés ne parlent plus la même langue : après le merge de #21749, le cache produit par le tapis est lu comme absent.
Le défaut, mesuré
1. La liste est tronquée à la source. _build_open_prs_cache_for_belt() (scripts/pick_idle_grain.py:2496) fait :
gh pr list --state open --json number,title,headRefName,body,files,additions,deletions --limit 200
Mesure du 2026-10-21 sur jsboige/CoursIA : 362 PRs ouvertes, 200 dans la fenêtre → 162 PRs invisibles. Le cache écrit dans le tempfile porte donc une liste tronquée, et aucune marque de cette troncature.
2. Le lecteur v2 refuse ce cache — et le refuse à raison. #21749 introduisit _read_open_prs_cache() : une liste nue (format héritage) est traitée comme absente (elle ne porte aucune preuve de complétude), un cache v2 marqué complete: false lève OpenPrsIncompleteError → verdict UNKNOWN (fail-closed). C'est le comportement voulu : un cache tronqué ne doit pas pouvoir rendre un « Path is free ».
3. Conséquence : l'optimisation de #19643 est perdue. L'intérêt du cache de session était de fetch-er la liste une fois par passe de tirage et de la partager à tous les candidats (~6 s x N, N = 40+ candidats). Après #21749, chaque invocation de check_lane_claim.py retombe sur sa propre énumération complète (GraphQL paginé + refetch REST des PRs à liste de fichiers plafonnée) : N énumérations complètes au lieu d'une.
4. Le tapis a, lui aussi, un usage direct de cette liste tronquée. Au-delà du partage de cache, draw_unclaimed() s'appuie sur la liste des PRs ouvertes pour remplacer un candidat déjà couvert par une PR ouverte (#16589). Cette vérification-là consomme la liste tronquée : une PR ouverte hors fenêtre ne remplace pas son candidat, et la lane peut poser un claim sur un chemin déjà tenu — la classe exacte de collision que #21742 ferme côté lecteur.
Attendu
scripts/pick_idle_grain.py doit produire le format v2 (open-prs-v2), en réutilisant l'énumération complète déjà écrite par #21749 plutôt qu'en dupliquant un gh pr list --limit 200 :
| # | Attendu | Critère |
|---|---|---|
| 1 | Le cache écrit par le tapis porte l'enveloppe v2 (format, complete, count, prs) |
_read_open_prs_cache() de #21749 le lit sans lever |
| 2 | L'énumération est complète (pagination GraphQL jusqu'à hasNextPage: false, + refetch REST des PRs dont la liste de fichiers est plafonnée) |
complete: true n'est écrit que si la complétude est établie, pas supposée |
| 3 | Une énumération incomplète (délai, plafond franchi, erreur) écrit complete: false avec son motif — jamais complete: true par défaut |
le lecteur lève OpenPrsIncompleteError → verdict UNKNOWN, jamais un « Path is free » |
| 4 | La vérification « PR ouverte couvre le candidat » (#16589) consomme la même énumération complète | aucun candidat qui est couvert par une PR hors fenêtre ne peut être tiré |
| 5 | Aucun fetch dupliqué : le tapis réutilise l'énumération de #21749 au lieu de lancer son propre gh pr list |
une seule énumération par passe de tirage, pas une par candidat |
| 6 | Écriture atomique du cache (fichier temporaire + os.replace) |
un lecteur concurrent (le tapis appelle l'organe en parallèle) ne lit jamais un fichier à moitié écrit |
Contrainte de séquence
Ne pas implémenter avant le merge de #21749 (arbitrage du coordinateur, DM du 2026-10-21) : le lecteur v2 doit exister avant qu'un producteur v2 soit écrit, sinon le contrat n'est pas testable de bout en bout.
Au moment d'éditer scripts/pick_idle_grain.py, vérifier d'abord l'occupation du chemin :
python scripts/check_lane_claim.py 21742 --lane myia-ai-01:CoursIA-2 --paths scripts/pick_idle_grain.pySi une des PRs ouvertes le tient encore, attendre ; ne pas editer un chemin tenu.
Vérification attendue
- un test unitaire : un cache v2
complete: trueécrit par le tapis est relu parcheck_lane_claim.pysans fetch réseau (chemin cache pris) ; - un test unitaire : un cache v2
complete: falseproduit un verdict UNKNOWN, jamaisCLEAR; - un test : la liste tronquée ne peut pas rendre un chemin « free » (contrôle de non-régression du fail-closed de Fix(#21742): check_lane_claim -- enumeration complete des PRs ouvertes + verdict UNKNOWN fail-closed #21749).
Notes
- La création de cette issue fille est le livrable demandé au DM du 2026-10-21 (« Ouvre une issue fille de check_lane_claim --paths : --limit 200 sur 362 PRs ouvertes rend un faux « Path is free » (fail-open) #21742 pour que pick_idle_grain.py écrive le format v2 »).
- Le
--pathsdecheck_lane_claim.pyest le mode qui produit le faux « Path is free » : c'est le cœur de check_lane_claim --paths : --limit 200 sur 362 PRs ouvertes rend un faux « Path is free » (fail-open) #21742, traité côté lecteur par Fix(#21742): check_lane_claim -- enumeration complete des PRs ouvertes + verdict UNKNOWN fail-closed #21749 ; cette issue traite le côté producteur.
Activity
jsboige commentedon Oct 21, 2026
[CLAIMED] lane myia-ai-01:CoursIA-2 -- paths: scripts/pick_idle_grain.py, scripts/tests/test_pick_idle_grain.py
Grain: MED/tooling — lane myia-ai-01:CoursIA-2 — prev: MED/guard #21749
Issue fille de #21742 (côté producteur du cache des PRs ouvertes), ouverte à la demande du coordinateur (DM du 2026-10-21, point 3).
Séquence : l'implémentation attend le merge de #21749 (le lecteur v2 doit exister avant qu'un producteur v2 soit écrit). Au moment d'éditer, vérifier l'occupation du chemin avec
python scripts/check_lane_claim.py 21757 --lane myia-ai-01:CoursIA-2 --paths scripts/pick_idle_grain.py: si une PR ouverte le tient encore, attendre.Rien n'est modifié sur cette branche dans ce cycle : le claim est posé pour la suite, la livraison se fera après le merge de #21749.
feat(picker,#21757): write the v2 cache (completeness-aware) and deci…
myia-ai-01 commentedon Oct 26, 2026
[CLAIMED] lane myia-ai-01:CoursIA-2 -- cache v2 des PRs ouvertes produit par le tapis, enumeration complete sans gh pr list --limit 200 (pose au dispatch par ai-01, tour du 26/10 12:33Z)
(check_lane_claim #9774 -- server-stamped UTC; body timestamps are NOT authoritative. Release with
[RELEASED]when your PR lands.)