Repository navigation
Description
Grain: MED/guard -- lane myia-ai-01:CoursIA-2 -- prev: MED/guard #24189
Part of #24172 (livre par #24173 : le dossier de cloture CLOSE est un signal de livraison TERMINAL).
Defaut
Le dossier [CLOSURE PREFLIGHT] de verdict CLOSE ecarte une issue du tapis sans limite d'age : il est terminal, donc la regle des 48 h de #22500 ne peut pas l'expirer. C'est le comportement voulu, mesure sur #19253.
Mais une decision de cloture prise sur une issue que le user rouvre ensuite n'est plus la decision finale : le user dit « ce n'est pas regle ». Or le tapis ne voit que le fil (commentaires) : il lit le dossier, il n'a aucune lecture de l'etat de l'issue (fermee, puis rouverte). Consequence mesuree : une issue rouverte par le user apres son dossier CLOSE, sans [NOT-DELIVERED], reste ecartee du tapis pour toujours — le dossier etait la, la reouverture aussi, et le tapis ne regardait que le fil.
Le dossier CLOSE est le SEUL signal terminal du tapis (tous les autres marqueurs expirent a 48 h) : c'est donc le seul dont la reouverture doit etre lue.
Pourquoi le predicat litteral du dispatch ne convient pas
Le dispatch propose : « un predicat "annonce de fermeture presente ET issue ouverte" la ressortirait ».
Ce predicat est trop large : il ressortirait toute issue livree et non closee — c'est-a-dire la majorite du pool ecarte par le filtre de livraison. Le filtre s'effondrerait, et le tapis resservirait en boucle des issues dont le travail est fait. Le predicat utile n'est pas « fermee puis ouverte », c'est « une reouverture POSTERIEURE a la decision de cloture ».
Correctif propose
Un evenement reopened de l'issue, lu dans le timeline (REST, bucket de quota distinct du GraphQL -- #17038), remplace la decision de cloture seulement s'il est posterieur a elle :
- dossier CLOSE (ou annonce de cloture) a T1, reouverture a T2 > T1 -> la decision est reprise, l'issue redevient servable ;
- reouverture a T0 < T1, dossier a T1 -> le dossier reste la derniere decision, l'issue reste ecartee ;
- dossier a T1, reouverture a T2, marqueur de livraison a T3 > T2 -> le marqueur rearme : l'issue reste ecartee (elle a ete relivree apres la reouverture).
Le predicat est applique aux trois surfaces qui ecartent un candidat -- la sonde RECENTE, la sonde PLEINE et le reducteur d'evenement -- pour qu'elles ne puissent pas diverger sur un fil qui change entre deux lectures (invariant deja pose pour les deux autres).
Cout : une lecture REST du timeline, et uniquement pour les candidats qui portent une decision de cloture (rares). Une issue livree par un marqueur ordinaire ne coute rien de plus : son marqueur expire a 48 h de toute facon. Lecture en echec -> fail-OPEN cote terminalite (la decision de cloture garde sa force) ; en repli REST du seul fil (bucket GraphQL tombe), la reouverture n'est pas lue et le comportement actuel est conserve.
Acceptance
- dossier CLOSE puis reouverture ulterieure -> l'issue redevient servable ;
- reouverture ANTERIEURE au dossier -> l'issue reste ecartee (le dossier est la derniere decision) ;
- dossier, reouverture, puis marqueur de livraison ulterieur -> l'issue reste ecartee ;
- dossier CLOSE sans reouverture -> l'issue reste ecartee sans limite d'age (le comportement de fix(picker): le dossier de cloture CLOSE est un signal de livraison TERMINAL (cas #19253) #24172/Fix(picker,#24172): le dossier de cloture CLOSE est un signal de livraison TERMINAL #24173 est preserve) ;
- les trois surfaces (sonde RECENTE, sonde PLEINE, reducteur) rendent le MEME verdict sur le meme fil ;
- un marqueur ordinaire ne declenche aucune lecture de timeline (cout nul sur le cas courant) ;
- controles positifs et negatifs par test, sans appel reseau (la lecture du timeline est injectee).
Fichiers
scripts/pick_idle_grain.pyscripts/tests/test_pick_closure_reopened.py
Activity
jsboige commentedon Nov 2, 2026
[CLAIMED] lane myia-ai-01:CoursIA-2 -- paths: scripts/pick_idle_grain.py, scripts/tests/test_pick_closure_reopened.py
jsboige commentedon Nov 2, 2026
[DELIVERED] lane myia-ai-01:CoursIA-2 -- paths: scripts/pick_idle_grain.py, scripts/tests/test_pick_closure_reopened.py -- PR #24256
Fix(picker,#24250): une reouverture du user reprend la decision de cl…