Refactor Scan
Détecter, ne jamais écrire. Propose ce sur quoi on pourrait travailler ensuite et remarque ce qui s'est déjà résolu depuis le dernier passage — ne crée jamais de ticket, ne décide jamais d'un résultat. refactor-design crée des tickets pour ce qui est choisi ; refactor-learn agit sur ce que cette compétence détecte.
Processus
1. Vérifier les préconditions
- Pas de dépôt git → arrêter le passage, le signaler, ne rien proposer.
- Cinq tickets ouverts
refactor:candidateou plus → arrêter, ne rien proposer de nouveau ; laisser le travail existant se terminer d'abord.
2. Reprendre d'abord le travail en attente
Lire le champ Pending candidates du fichier bookkeeping.md des Notes de Refactoring (skills/continuous-refactoring/references/refactoring-bookkeeping.md). S'il nomme un ticket, un passage précédent de refactor-design l'a créé mais a été interrompu avant qu'une demande de fusion ne suive. Proposer exactement ce ticket et s'arrêter — terminer le travail en attente prime sur la proposition de nouveau travail.
3. Détecter l'état fermé/fusionné des éléments mémorisés
Obtenir l'ensemble mémorisé — docs/agents/issue-tracker.md nomme un tracker natif par étiquette (GitHub, GitLab) → chaque ticket ouvert refactor:candidate, résolu en sa demande de fusion liée via la référence croisée native ticket↔PR de fermeture du tracker (le Closes #<n> que refactor-implement étape 5 met déjà sur une MR de livraison) ; un ticket sans PR liée n'a rien à réconcilier à cette étape. Sinon → chaque entrée dans merge-requests.md des Notes de Refactoring. Pour chacune, vérifier le tracker externe/git : la MR est-elle toujours ouverte, le ticket est-il toujours ouvert ?
Pas de gh/glab (ou autre API/token de forge) disponible → passer à la réconciliation uniquement par git au lieu de sauter cette étape (ne jamais essayer d'installer gh/glab ici non plus — traiter leur absence exactement comme le déclencheur de ce repli) : skills/refactor-scan/references/git-only-reconciliation.md. Pas de remote du tout (git remote -v vide) → la variante locale uniquement du même fichier — un candidat mémorisé peut avoir été fusionné ou rejeté par un humain travaillant purement en local, conformément à opening-a-merge-request.md section "Aucune forge/remote disponible".
-
Fusionné → un constat : livré.
-
Fermé sans fusion → un constat : refusé — noter si les commentaires de fermeture donnent une raison structurelle du mainteneur (hors périmètre) ou non.
-
Toujours ouvert, avec une activité de relecture (une revue ou un commentaire) plus récente que le dernier commit de la branche → un candidat à reprendre, pas un constat — personne n'a encore décidé quoi que ce soit, cela a juste besoin d'un autre regard. Accès API disponible → lire aussi l'état réel de la revue avec le timestamp (
gh pr view <n> --json reviews,reviewDecisionou équivalent) — ne pas s'arrêter à "quelque chose a changé" :CHANGES_REQUESTED, non traité (pas de commit plus récent que la revue) → toujours un candidat à reprendre, mais transmettre les commentaires/corps de la revue avec, pas seulement la branche —refactor-implementétape 1 lit et traite ce retour spécifique, pas seulement réexamine la branche de zéro.- Un commentaire, ou une revue
APPROVEDsans retour bloquant → la gestion générique existante du candidat à reprendre ; rien d'autre à attacher.
Le transmettre de la même manière que l'étape 2 transmet une entrée
Pending candidates: directement àrefactor-implement, en contournantrefactor-prioritize/refactor-design(il a déjà une conception et une MR ouverte ; seule la boucle de correction s'applique —refactor-implementétape 1 supporte déjà la reprise d'une branche existante). Pas d'accès API (repli git uniquement) → l'état de la revue reste indisponible exactement comme documenté dansgit-only-reconciliation.md; cet affinement ne s'applique pas là. -
Toujours ouvert, rien n'a changé → pas de constat.
Vérifier aussi chaque entrée dans out-of-scope/<node>.md des Notes de Refactoring nommant une condition **Bloqué par :** PHP >= X.Y (tooling_tree.py's detect_nodes() le rapporte directement lorsqu'il est exécuté ; à la main, comparer avec le require.php/config.platform.php actuel du composer.json de la cible) — si la version actuelle de PHP de la cible satisfait désormais la condition, un constat : ce rejet est annulé. Pas de champ Bloqué par :, ou condition toujours non satisfaite → jamais un constat.
Transmettre chaque constat à refactor-learn — cette compétence ne fait que remarquer ; elle ne marque jamais rien done/wontfix et n'écrit jamais elle-même dans out-of-scope/ des Notes de Refactoring.
3b. Détecter les candidats étiquetés extérieurement
Accès API disponible (pas le repli git uniquement) → interroger aussi les tickets ouverts refactor:candidate qui ne sont pas déjà pris en compte : pas l'entrée Pending candidates de l'étape 2, pas l'ensemble mémorisé de l'étape 3 (un ticket avec une demande de fusion liée est déjà en vol). Ce qui reste est un candidat qu'un humain (ou un autre processus) a étiqueté directement, que cette boucle n'a jamais conçu ni implémenté — en fonctionnement normal, les propres candidats de la suite sont toujours couverts par l'un de ces deux, donc rien de plus n'est nécessaire pour distinguer "les nôtres" de "ceux des autres". Transmettre chacun comme une proposition, la même liste à laquelle les propositions de l'arbre d'outillage de l'étape 4 se joignent — refactor-prioritize les classe à côté de tout le reste selon ses facteurs habituels ; ils concourent sur leurs propres mérites, ne sautent jamais la file d'attente simplement pour exister. Pas d'accès API (repli git uniquement) → sauter cette étape entièrement, git seul ne peut pas énumérer les tickets par étiquette.
4. Proposer les nœuds de l'arbre d'outillage
Sauter si l'étape 2 a déjà proposé un candidat en attente.
Exécuter python3 skills/refactor-scan/references/tooling_tree.py <dépôt-cible> et lire le champ next du JSON — l'ensemble réel, actuellement non bloqué, les nœuds rejetés (une entrée existante dans out-of-scope/<node>.md des Notes de Refactoring) déjà exclus, prendre tel quel le nombre d'entrées qu'il contient. Pas roadmap (une simulation prospective, pas des options réelles aujourd'hui). Lire aussi withheld : les nœuds qui autrement seraient dans next mais attendent un parent recommandé non décidé — chaque entrée nomme le(s) parent(s). Pas de python3, ou non autorisé → envoyer un sous-agent avec le prompt de skills/refactor-scan/references/tree-walk-prompt.md ({N}=all) — il parcourt les mêmes documents d'arbre manuellement (lit d'abord le champ Fulfilled nodes de bookkeeping.md des Notes de Refactoring pour éviter de re-dériver l'état mis en cache, saute tout nœud avec une entrée hors périmètre) ; pas de mécanisme de sous-agent → exécuter ses étapes vous-même en ligne.
- Nœuds d'outillage ordinaires (
loop-config, et nœuds de spécialisation de langage, par ex.skills/refactor-scan/references/php-tooling-tree.md) — proposés par leur Nom (jamais l'identifiant brut) ; chacun est déjà entièrement spécifié dans son document d'arbre. structural-scan— proposé une fois que chaque nœud avec une arêteresolvedvers lui est résolu (rempli, ou explicitement rejeté sousout-of-scope/des Notes de Refactoring) :editorconfigà la racine générique, plus le propre nœud d'agrégation de la spécialisation de langage active (PHP :php-structural-scan), lui-même résolu une fois que chacun de ses propres parents résolus est résolu (skills/refactor-scan/references/tooling-tree.md). Seulstructural-scanest jamais proposé de cette manière —php-structural-scanest une pure tuyauterie, jamais un candidat. Le proposer est simplement le nommer ; le parcours de la base de code a lieu dansrefactor-design, seulement pour le nœud effectivement choisi.- Aucun arbre de langage reconnu :
structural-scanattend toujourseditorconfig, la feuille racine générique — pas immédiatement proposable simplement parce qu'aucun arbre spécifique à un langage ne s'applique.
Sortie
Transmise par l'orchestrateur, simplement :
- Quelle précondition a arrêté le passage, le cas échéant — rien ci-dessous ne s'applique à ce passage.
- Constat (éventuellement vide) →
refactor-learn. - Un candidat à reprendre, si détecté → directement à
refactor-implement, en contournantrefactor-prioritize/refactor-design. - Propositions — le candidat en attente seul, ou chaque Nom de nœud actuellement non bloqué (jamais les identifiants bruts, jamais en majuscules) plus tout candidat étiqueté extérieurement de l'étape 3b, ou rien →
refactor-prioritize. Chaque nœud actuellement non bloqué (parents requis remplis, non rejeté, chaque parent recommandé déjà décidé) — jamais un sous-ensemble tronqué par priorité. Avec cela, nommer chaque nœudwithheldet le(s) parent(s) qu'il attend (par ex. "Rector : Type Coverage Set — attend : PHP CS Fixer").
Critère de complétion
Les constats (le cas échéant) transmis à refactor-learn, un candidat à reprendre (le cas échéant) transmis directement à refactor-implement, les propositions (le cas échéant) transmises à refactor-prioritize — ou une précondition a arrêté le passage et le rapport indique laquelle. Jamais un nœud avec des entrées au-delà de structural-scan dans la même liste.