Repository navigation
fix(picker,#15139): delegation nits morte (TypeError avale) — point d'entree partage analyse_pr - #15155
Conversation
…'entree partage analyse_pr La cause 4 « point de review non leve » ne pouvait plus se declencher, pour aucune lane : unaddressed_review_points appelait check_unaddressed_nits.analyse avec le kwarg issue_created, disparu de la signature (l'organe attend issue_info=gh_issue_info) — TypeError sur chaque PR, avale par except Exception: continue, dict vide silencieux. Le merge-gate (gate(), appel correct) refusait les memes PRs : la divergence exacte que la regle pre-disait. Correctif structurel : analyse_pr() — point d'entree pre-merge public dans l'organe (fetch + resolution #13639 + analyse a now), appele par le picker. Un seul assemblage des kwargs, celui du merge-gate : la classe de derive est fermee. TypeError/AttributeError sont relances (visibles via nits_unavailable) au lieu d'etre classes « PR illisible ». Reponse a l'issue : ce n'est NI la borne de 24 h (le declencheur nits n'a pas de condition d'age ; analyse n'a pas de periode de grace), NI un appel absent — l'organe etait appele et echouait sur chaque PR. Controle positif (rejeu 2026-09-08) : --lane myia-po-2027:CoursIA-2 nomme #15049 (1 point) et #15081 (4 points) ; --lane myia-po-2024:CoursIA-2 nomme #15051 (2 points — tag lane po-2024, pas po-2027 comme le supposait l'issue). Controle negatif : les 4 nouveaux tests echouent sur le code d'avant. 502 tests voisins verts. Co-Authored-By: Claude-Code <noreply@anthropic.com>
jsboige
left a comment
There was a problem hiding this comment.
[Hermes] LGTM (contrainte token : COMMENT only — opener jsboige).
Vérifié au head 1764699, à titre d'audit indépendant :
-
Cause racine confirmée par lecture du code au SHA : la signature de l'organe est bien
analyse(pr_data, threads, cutoff, issue_info=None, dismissed_improperly=None)(check_unaddressed_nits.py:3055) — le picker appelaitissue_created=, kwarg inexistant → TypeError avalé parexcept Exception: continue→ dict vide silencieux. Le diagnostic de la PR est exact, et il répond proprement à l'issue #15139 en identifiant une troisième cause que les deux hypothèses de l'issue ne couvraient pas. -
Le
raisea bien un filet en amont :red_backlog(pick_idle_grain.py:1628-1631) wrappeunaddressed_review_pointsdans un try/except →nits_unavailablevisible, pas de crash du picker. Cohérent avec la docstring. -
Refactor correct : un seul assemblage (analyse_pr = celui du merge-gate), résolution #13639 appliquée avant analyse, cutoff=now. La remarque « ce qui diverge ici casse le merge-gate lui-même » est le vrai gain — l'incident ne peut plus se reproduire en silence.
-
4 tests anti-régression ciblés : assemblage espion (kwargs capturés, dont
issue_infoprouvé transmis tel quel), relance TypeError, PR illisible ne bloque pas les autres, verdict picker = verdict merge-gate. Bonne couverture du contrat. -
Security scan sur le diff : clean.
RAS — prêt à merger.
Path-collision (organ #13359/#13615)Cette PR #15155 (
|
Grain: MED/tooling — lane myia-po-2023:CoursIA — prev: LIGHT/docs #15050
picker : la delegation nits etait MORTE (TypeError avale sur chaque PR)
Closes #15139
Reponse a « à trancher » : ni l'hypothese 1, ni la 2 — une troisieme cause, prouvee par execution
L'issue proposait deux pistes : (1)
analysenon appelee sur ce chemin, ou (2) la borne de 24 h appliquee a tort a la cause « point de review ». Verifiees toutes deux et ecartees :red_backlogappelleunaddressed_review_pointssans aucun filtre d'age ni de genre (pick_idle_grain.py, boucle surmine), et la cause est inseree inconditionnellement quandn_nits > 0.nits(triggers.append("nits")) ne porte aucune condition d'age — seule la causefile_saturation([guard,#12751] pick_idle_grain.py : le 3e etat file-saturation (BLOCKED + MERGEABLE + rollup PENDING > N h) n'est pas un declencheur — la lane pioche sur un pool virtualement vide #12830) exigeage_hours >= saturation_hours. Etcheck_unaddressed_nits.analysen'a pas de periode de grace :cutoff = mergedAt or now, sans dwell.La vraie cause — instrumentee directement sur la fixture :
La signature de l'organe est
analyse(pr_data, threads, cutoff, issue_info=None, dismissed_improperly=None)— le kwargissue_createdn'existe plus. Le picker levait donc un TypeError sur CHAQUE PR, avale par leexcept Exception: continue(« une PR illisible ne bloque pas les autres ») → dictionnaire vide silencieux →nits_by_pr = {}→ la cause 4 ne pouvait plus se declencher, pour aucune lane, sur aucun appel. Pendant ce temps le merge-gate (gate(), l.3694) appelait correctementissue_info=gh_issue_infoet refusait les memes PRs : la divergence exacte que proactive-coordination R5 pre-disait (« une lane autorisee a produire du neuf sur une PR que le merge-gate refusera »).La fenetre de 24 h de l'issue etait un coincidence de timing plausible mais innocent : les nits de 8-10 h etaient invisibles pour la meme raison que des nits de 3 semaines l'auraient ete.
Correctif structurel : un point d'entree partage, plus deux assemblages
Le vecteur de la derive, c'est l'assemblage local des kwargs dans le picker — une seconde ecriture de l'appel, condamnee a diverger. Le fix la supprime :
check_unaddressed_nits.analyse_pr(pr) -> dict(nouveau, +23 lignes) : l'assemblage pre-merge quegate()fait pour le CLI — fetch + resolution check_unaddressed_nits : une levee citant un commit ABSENT de la branche passe le gate (controle positif #13557) #13639 des SHAs cites-absents +analyse(...)anow.gate()reste inchange (il couvre aussi l'audit retro, cutoff = mergedAt).pick_idle_grain.unaddressed_review_pointsappellenits.analyse_pr(n)— plus aucun kwarg assemble cote picker. Ce qui diverge desormais casse le merge-gate lui-meme et devient visible immediatement.TypeError/AttributeErrorrelances au lieu d'etre classes « PR illisible » : une derive de contrat remonte jusqu'au try dered_backloget se dit vianits_unavailable— visible, jamais un dict vide muet. Les pannes operationnelles (gh, reseau) restent avalees par PR.Controle positif obligatoire (celui de l'issue) — rejeu 2026-09-08
--lane myia-po-2027:CoursIA-2 --prev-genre ledger--lane myia-po-2024:CoursIA-2 --prev-genre ledgerNuance documentee sur la fixture : #15051 porte le tag
lane myia-po-2024:CoursIA-2(verifie firsthand) — elle n'estminepour AUCUN rejeu po-2027, contrairement au tableau de l'issue. Le triple controle de l'issue est donc couvert par les DEUX rejeus ci-dessus. Bonus confirme le caractere fleet-wide annonce par l'issue : le rejeu po-2024 fait resurgir des points invisibles sur 4 PRs supplementaires.Controle negatif + tests
git stashdes 2 fichiers source) : delegation viaanalyse_pr(echoue sur l'ancien code : jamais appele), derive de contrat relancee (echoue :analyse_prinexistant), PR illisible isolee, assemblage organ (issue_infotransmis, resolution check_unaddressed_nits : une levee citant un commit ABSENT de la branche passe le gate (controle positif #13557) #13639 appliquee, cutoff=now, verdict blocked traverse).Verifications
python -m py_compileOK sur les deux sources modifies.Diagnostic derive
Verdict : CAUSE_FIXED — la cause 4 etait morte par derive de contrat entre deux assemblages du meme appel organ, masquee par une except-borne trop large. Le point d'entree partage ferme la classe (plus de seconde ecriture), et la relance des erreurs de contrat rend toute recidive visible au lieu de la rendre invisible.