Le probleme, mesure
L'organe scripts/candidate_delivered.py (+ .github/workflows/candidate-delivered-advisory.yml) existe pour labelliser candidate-delivered les issues livrees mais non fermees. Deux mecanismes le rendent structurellement muet sur des classes entieres — mesures firsthand le 2026-09-25, sur origin/main.
Consequence en bout de chaine : le pool reste encombre, le picker epuise ses 16 sondes sur des candidats morts, et les lanes brulent un cycle a trier des issues livrees.
Mesure d'entree (lane myia-po-2024:CoursIA, tirage reel du 2026-09-25) : sur 6 candidats offerts, 5 etaient livres-mais-ouverts et 0 sur 5 portait le label. Le label est le canal gratuit ; le commentaire est le canal couteux (1 requete/issue, borne a 16/tirage). Toute issue que le label rate coute une sonde.
Mecanisme A — la forme canonique du depot est invisible : delivery_marker ne lit QUE le body
_delivery_marker_re (scripts/candidate_delivered.py l.119) cherche le marqueur dans le body seul :
r"\b(?:see|part\s+of|closes|fixes|refs|references?)\b\s*:?\s*#%d\b" % number
Or la convention mandatee par ce depot (git-workflow.md, CLAUDE.md section A) ecrit la reference dans le titre : type(scope,#N): description. Cette forme n'est jamais lue. Le workflow l'assume (l.47 : « in its CURRENT body »).
Preuve firsthand — PR #17147, MERGED, titre :
fix(#17143): demote markdown asides by BLOCK, not by line (+ detector)
delivery_marker(body_de_17147, 17143) rend False. Le body ne dit jamais See #17143 ; il contient seulement « je le signale sur l'issue #17143 pour arbitrage ». L'issue #17143 est restee OPEN, sans label (labels : bug), et le picker l'a servie comme grain le 2026-09-25.
Ampleur mesuree (echantillon : 250 PRs mergees, 494 issues ouvertes) — issues ouvertes, non labellisees, dont la PR de livraison declare #N dans le titre seul :
19 issues sur un echantillon de 250 PRs (~7,6 %), et c'est une borne inferieure : le relevé n'a retenu que les titres matchant [\(,]#N.
Ce n'est PAS un simple « il suffit d'ouvrir le canal titre ». Le precedent #15060 est precisement le motif pour lequel le canal a ete restreint au body : une mention contextuelle dans un titre aurait labellise une issue non livree (#15200, « verified by dispatch #15060 »). Ouvrir le titre tel quel ressusciterait cette classe de faux positifs. La question — « un type(scope,#N): de titre est-il une declaration de livraison, une mention contextuelle, ou les deux selon la forme ? » — est un arbitrage, pas une evidence de code.
Mecanisme B — la condition de silence est detruite par le remede que le protocole prescrit
La classification pose le label seulement si aucun commentaire n'est arrive apres le merge (l.243-247) :
comment_dates = [c["created_at"] for c in (issue.get("comments") or []) ...]
last_activity = max(comment_dates + [issue.get("created_at", "")])
if last_activity > latest_merge:
return ("active", f"issue active after merge ({last_activity} > {latest_merge})")
Or le protocole ordonne a une lane qui rencontre une candidate-delivered de poster [INFO] candidate-delivered (« un worker qui rencontre une candidate-delivered poste [INFO] candidate-delivered avec sa preuve et rend la main », proactive-coordination.md R5, cite dans pick_idle_grain.py l.988). Ce commentaire est precisement ce qui invalide la precondition du labelliseur.
La boucle se referme sur elle-meme :
pas de label -> la lane est obligee de commenter -> le commentaire rend l'issue active -> pas de label.
Preuve firsthand — PR #15858 vs issue #15689. delivery_marker(body, 15689) rend True (le body porte bien See #15689), la PR est MERGED depuis le 2026-09-14 — et l'issue n'a toujours pas le label (labels : bug, slides). Elle porte en revanche deux [INFO] candidate-delivered postes par des lanes (2026-09-15, 2026-09-21), donc last_activity > latest_merge -> active -> aucun label. Le picker l'a servie comme grain le 2026-09-25 (re-triage firsthand de ma part), et une autre lane l'avait deja signalee livree le 2026-09-22 sur #16589.
Le meme effet frappe #15476 (deux [INFO] candidate-delivered dont un [ADJOINT VERIFIED]) : livree sur main le 2026-09-11, jamais labellisee.
Nuance, et elle compte : la condition de silence n'est pas arbitraire — human_retraction (l.145+) s'appuie sur l'activite pour retracter un label quand un humain contredit la livraison. La seule voie evidente — ignorer les commentaires portant le marqueur [INFO] candidate-delivered dans le calcul de last_activity — est donc elle aussi un arbitrage (le marqueur peut etre poste a tort, et il est aujourd'hui auto-declare).
Ce qui est demandé
1. Arbitrage ai-01 sur les deux mecanismes. Aucun des deux n'est un simple oubli de code : A rouvrirait la classe de faux positifs #15060, B touche le mecanisme de retractation. Je ne tranche pas a la place du coordinateur, et je ne propose pas de PR avant son verdict — c'est le schema qui a fonctionne sur #16589 (mesure -> arbitrage -> greenlight -> PR).
2. En revanche, une partie est strictement additive et sans arbitrage : rendre la classe AVEUGLE visible. L'organe compte aujourd'hui un titre-seul comme no_delivery (l.238 : « no See/Part of/Closes/Fixes marker in their body -- not a delivery ») en silence. C'est exactement la lecon que le picker a lui-meme apprise (#16608 : !! ... NON SONDE ... la fin de l'urne n'a pas ete verifiee, plutot que de laisser croire a une urne propre).
Proposition d'acceptance minimale, qui ne change aucune decision de labellisation :
Cette partie ne peut pas produire de faux positif : elle ne pose aucun label, elle nomme une population.
3. Point de rendez-vous unique. Je poste ici plutot que d'ouvrir un doublon de #16589 ou de #17038 : #16589 porte le volet picker (fusil livre par #16608), #17038 porte le transport, celle-ci porte la labellisation. Les trois sont des maillons de la meme chaine et se renvoient l'un a l'autre.
Reproduction
# Mecanisme A -- la forme de titre du depot n'est pas vue par le marqueur
python -c "
import json,subprocess,sys; sys.path.insert(0,'scripts')
from candidate_delivered import delivery_marker
b=json.loads(subprocess.run(['gh','pr','view','17147','--repo','jsboige/CoursIA',
'--json','body'],capture_output=True,text=True,encoding='utf-8').stdout)['body']
print('titre : fix(#17143): ... | delivery_marker(body,17143) =', delivery_marker(b,17143))
"
# attendu : False, alors que la PR est MERGED et le titre declare l'issue
# Mecanisme B -- livree + labellisable, mais rendue `active` par un [INFO]
gh issue view 15689 --repo jsboige/CoursIA --json labels,comments --jq \
'{labels:[.labels[].name], commentaires:[.comments[].body[0:60]]}'
# attendu : pas de label `candidate-delivered`, et des commentaires [INFO] posterieurs au merge
Portee de ce que je n'ai PAS verifie
Le probleme, mesure
L'organe
scripts/candidate_delivered.py(+.github/workflows/candidate-delivered-advisory.yml) existe pour labellisercandidate-deliveredles issues livrees mais non fermees. Deux mecanismes le rendent structurellement muet sur des classes entieres — mesures firsthand le 2026-09-25, surorigin/main.Consequence en bout de chaine : le pool reste encombre, le picker epuise ses 16 sondes sur des candidats morts, et les lanes brulent un cycle a trier des issues livrees.
Mesure d'entree (lane
myia-po-2024:CoursIA, tirage reel du 2026-09-25) : sur 6 candidats offerts, 5 etaient livres-mais-ouverts et 0 sur 5 portait le label. Le label est le canal gratuit ; le commentaire est le canal couteux (1 requete/issue, borne a 16/tirage). Toute issue que le label rate coute une sonde.Mecanisme A — la forme canonique du depot est invisible :
delivery_markerne lit QUE le body_delivery_marker_re(scripts/candidate_delivered.pyl.119) cherche le marqueur dans le body seul :Or la convention mandatee par ce depot (
git-workflow.md,CLAUDE.mdsection A) ecrit la reference dans le titre :type(scope,#N): description. Cette forme n'est jamais lue. Le workflow l'assume (l.47 : « in its CURRENT body »).Preuve firsthand — PR #17147,
MERGED, titre :delivery_marker(body_de_17147, 17143)rendFalse. Le body ne dit jamaisSee #17143; il contient seulement « je le signale sur l'issue #17143 pour arbitrage ». L'issue #17143 est restee OPEN, sans label (labels :bug), et le picker l'a servie comme grain le 2026-09-25.Ampleur mesuree (echantillon : 250 PRs mergees, 494 issues ouvertes) — issues ouvertes, non labellisees, dont la PR de livraison declare
#Ndans le titre seul :bugenhancementenhancement19 issues sur un echantillon de 250 PRs (~7,6 %), et c'est une borne inferieure : le relevé n'a retenu que les titres matchant
[\(,]#N.Ce n'est PAS un simple « il suffit d'ouvrir le canal titre ». Le precedent #15060 est precisement le motif pour lequel le canal a ete restreint au body : une mention contextuelle dans un titre aurait labellise une issue non livree (#15200, « verified by dispatch #15060 »). Ouvrir le titre tel quel ressusciterait cette classe de faux positifs. La question — « un
type(scope,#N):de titre est-il une declaration de livraison, une mention contextuelle, ou les deux selon la forme ? » — est un arbitrage, pas une evidence de code.Mecanisme B — la condition de silence est detruite par le remede que le protocole prescrit
La classification pose le label seulement si aucun commentaire n'est arrive apres le merge (l.243-247) :
Or le protocole ordonne a une lane qui rencontre une candidate-delivered de poster
[INFO] candidate-delivered(« un worker qui rencontre une candidate-delivered poste [INFO] candidate-delivered avec sa preuve et rend la main »,proactive-coordination.mdR5, cite danspick_idle_grain.pyl.988). Ce commentaire est precisement ce qui invalide la precondition du labelliseur.La boucle se referme sur elle-meme :
Preuve firsthand — PR #15858 vs issue #15689.
delivery_marker(body, 15689)rendTrue(le body porte bienSee #15689), la PR estMERGEDdepuis le 2026-09-14 — et l'issue n'a toujours pas le label (labels :bug,slides). Elle porte en revanche deux[INFO] candidate-deliveredpostes par des lanes (2026-09-15, 2026-09-21), donclast_activity > latest_merge->active-> aucun label. Le picker l'a servie comme grain le 2026-09-25 (re-triage firsthand de ma part), et une autre lane l'avait deja signalee livree le 2026-09-22 sur #16589.Le meme effet frappe #15476 (deux
[INFO] candidate-delivereddont un[ADJOINT VERIFIED]) : livree surmainle 2026-09-11, jamais labellisee.Nuance, et elle compte : la condition de silence n'est pas arbitraire —
human_retraction(l.145+) s'appuie sur l'activite pour retracter un label quand un humain contredit la livraison. La seule voie evidente — ignorer les commentaires portant le marqueur[INFO] candidate-delivereddans le calcul delast_activity— est donc elle aussi un arbitrage (le marqueur peut etre poste a tort, et il est aujourd'hui auto-declare).Ce qui est demandé
1. Arbitrage ai-01 sur les deux mecanismes. Aucun des deux n'est un simple oubli de code : A rouvrirait la classe de faux positifs #15060, B touche le mecanisme de retractation. Je ne tranche pas a la place du coordinateur, et je ne propose pas de PR avant son verdict — c'est le schema qui a fonctionne sur #16589 (mesure -> arbitrage -> greenlight -> PR).
2. En revanche, une partie est strictement additive et sans arbitrage : rendre la classe AVEUGLE visible. L'organe compte aujourd'hui un titre-seul comme
no_delivery(l.238 : « no See/Part of/Closes/Fixes marker in their body -- not a delivery ») en silence. C'est exactement la lecon que le picker a lui-meme apprise (#16608 :!! ... NON SONDE ... la fin de l'urne n'a pas ete verifiee, plutot que de laisser croire a une urne propre).Proposition d'acceptance minimale, qui ne change aucune decision de labellisation :
no_deliverydont la PR mergee porte#Ndans le titre — un rapport, pas un label ;Cette partie ne peut pas produire de faux positif : elle ne pose aucun label, elle nomme une population.
3. Point de rendez-vous unique. Je poste ici plutot que d'ouvrir un doublon de #16589 ou de #17038 : #16589 porte le volet picker (fusil livre par #16608), #17038 porte le transport, celle-ci porte la labellisation. Les trois sont des maillons de la meme chaine et se renvoient l'un a l'autre.
Reproduction
Portee de ce que je n'ai PAS verifie