Chasseur de Bogues
Une affirmation sans test qui échoue est une supposition. Tout ce que cette compétence signale est prouvé par un test observé rouge avant la correction et vert après ; tout ce qu'elle ne peut pas prouver est abandonné. C'est l'idée entière, et la raison pour laquelle sa sortie mérite d'être lue.
Elle modifie l'arbre de travail, ajoute des fichiers de test, et par défaut, commit.
- Comment effectuer chaque étape — reference.md. Lisez-le avant les étapes 4 à 7, avant de rédiger un rapport, et avant de commiter.
- Tests de mutation, étape 3 à étape 9 — mutation.md. Lisez-le avant de commencer un mutant.
Le contrat
- Chaque bogue corrigé a un test de régression qui a été observé rouge sur le code non corrigé et vert après la correction.
- Chaque candidat qui ne peut pas être rendu rouge, ou qu'un second opinion réfute, est abandonné — et son test est supprimé, jamais laissé en échec.
- Tout ce qui est réel mais hors de portée ou non testable est signalé, non corrigé.
- La suite de tests complète ne se termine pas moins bien qu'elle n'a commencé.
Liste de contrôle du workflow
- [ ] Étape 0 : Définir le périmètre — diff staged uniquement
- [ ] Étape 1 : Triage — ce commit mérite-t-il une revue ?
- [ ] Étape 2 : Référence — exécuter la suite avant de toucher à quoi que ce soit
- [ ] Étape 3 : Trouver des candidats (modèle fort, accessibilité requise) ; sous-agents de mutation à côté là où les fonctions modifiées ont des tests
- [ ] Étape 4 : Prouver — écrire le test, l'exécuter, exiger un rouge correspondant
- [ ] Étape 5 : Réfuter — un second opinion tente de tuer chaque bogue prouvé, et vérifie chaque test survivant et chaque affirmation de code mort
- [ ] Étape 6 : Corriger (question de prévention, confinement de périmètre)
- [ ] Étape 7 : Vérifier — nouveaux tests verts ; la suite complète une fois, avant l'étape 9
- [ ] Étape 8 : Itérer — dos à dos, jusqu'à 3, sans demander ; jamais de 4ème
- [ ] Étape 9 : Rapporter une fois à la fin ; demander à l'utilisateur chaque décision ouverte (sélecteur — écrit n'est pas demandé) ; puis commiter (avec l'en-tête de prose quand prose est installé) ou laisser pour révision — ou, sous "l'appelant commit", terminer par le bloc de `scripts/caller-result.sh`
Ne jamais exécuter ceci depuis un hook git pre-commit. Il écrit des fichiers, ajoute des tests, et commit — tout cela entre en conflit avec le verrou d'index de git. Il s'exécute avant que le commit ne soit créé, et le commit a lieu à l'étape 9.
Un hook compagnon surveille les commits qui ne sont jamais passés par ici : après chaque commande, il demande à git si HEAD a bougé et si le nouveau commit porte un en-tête Bug-hunter:. Donc l'en-tête est le seul marqueur qui compte — pas de variable d'environnement, rien à retenir, et l'enregistrement vit dans le commit lui-même où git log peut l'auditer.
Le hook pose également une seconde question pour tout en-tête qui n'est pas lui-même une note d'omission — 0 bugs trouvés et abandonné ... inclus, pas seulement ceux signalant une correction : un en-tête Bug-hunter-Tree correspond-il à l'arbre qui a réellement atterri ? Cette liaison est ce que scripts/mint-trailer.sh produit lorsqu'il est exécuté sur l'arbre stagé réel, juste avant le commit — voir étape 9 pour savoir comment. Un en-tête Bug-hunter: peut être un véritable en-tête git avec exactement le bon libellé et être encore une phrase rappelée pour avoir lu ce fichier, plutôt qu'une produite en exécutant une partie de celui-ci — c'est la seule forme que la vérification de présence de chaîne ne peut pas attraper, et celle pour laquelle cette liaison existe.
Un commit qui atterrit sans en-tête Bug-hunter:, ou avec un en-tête dont la liaison Bug-hunter-Tree ne correspond pas, est nommé dans un rapport, avec le dépôt dans lequel il se trouve. Le rapport vous envoie à la section ci-dessous et ne donne aucune commande pour corriger le commit : le hook ne peut pas voir où vous vous trouvez, et le commit qu'il nomme n'est souvent pas votre HEAD.
Si vous êtes un agent sur le point de commiter
Si une autre compétence réalise vos commits et exécute cette compétence avant chacun d'eux, laissez cette compétence commencer par "commit ceci" ; exécutez-la toujours pour "vérifie les bogues de ceci". Si ce tour a déjà énoncé un sujet de commit, utilisez ce sujet inchangé. Ne faites qu'ajouter des en-têtes.
Chaque commit que vous créez passe par cette compétence et porte un en-tête Bug-hunter:. Pas quand on vous le demande par son nom — à chaque fois. Un commit avec du code obtient la chasse. Un commit avec seulement de la documentation, des spécifications, des tests ou du formatage saute la chasse, pas la compétence. "Commit ceci", "commit mes modifications", "finalise et commit", ou votre propre décision de commiter après avoir terminé une tâche signifient tous : stagez la modification, exécutez cette compétence, puis commitez. Le triage (étape 1) décide si un commit donné mérite une révision, donc l'exécuter toujours est peu coûteux quand cela ne s'applique pas.
Exécutez-la vous-même, dans votre propre session. L'agent qui a écrit la modification exécute cette compétence. Ne confiez pas l'exécution entière à un sous-agent qui démarre ensuite ses propres chercheurs, réfuteurs et agents de mutation : l'exécution a besoin d'un orchestrateur qui reste vivant pour collecter les survivants et reprendre les agents, et un délégué imbriqué ne cesse de terminer son tour pendant que ses enfants s'exécutent. Déléguer les passes uniques, comme le disent les étapes, est la façon dont elle est conçue pour fonctionner.
Ne contournez pas cette compétence
Un titre, pas cinq règles, parce qu'un agent cherchant un moyen de sortir d'une vérification trouve systématiquement la couture entre des règles énoncées séparément. Chaque ligne ici a été ajoutée après qu'un agent ait contourné la règle qu'elle ferme.
1. Dites laquelle vous faites, à voix haute, à chaque fois. Une ligne dans la réponse que l'utilisateur peut voir : "exécution de bug-hunter sur N fichiers", ou "saut de bug-hunter — ". Pas dans votre raisonnement — dans la réponse. Sauter sans rien dire ressemble exactement à l'exécuter et ne rien trouver. Un saut déclaré peut être annulé en quatre mots ; un non déclaré est une décision que vous avez prise pour eux. Si vous sautez, le commit porte aussi l'en-tête — commit-with-trailer.sh -F msg.txt "ignoré — <raison>", comme à l'étape 9. Les deux, pas l'un ou l'autre. Sous l'appelant commit, le saut va au script de résultat à la place (Quand l'appelant commit).
2. Ne demandez jamais la permission de l'exécuter. Le déclencheur est une propriété du code, pas un moment : si du code a été écrit depuis la dernière passe qui est revenue propre, une passe est due. Avant un commit, entre les itérations, après une correction demandée par l'utilisateur, après un refactoring, après un commit qui a déjà atterri — pas de cas séparés, tous "du code a été écrit". Une liste de moments invite à chercher le moment qui n'est pas sur la liste.
3. Annoncer ne compte que si vous avez déjà commencé. "C'est ce qui s'exécute ensuite, sauf si vous voulez vous arrêter ici" · "Je vais lancer ça si vous êtes satisfait" · "les corrections ont besoin de leur propre passe — voulez-vous que je l'exécute ?" Chacun termine le tour sans que la vérification ne s'exécute, ce qui rend la décision aussi clairement que de la demander. Si vous décrivez une exécution au futur, vous ne l'avez pas commencée, et c'est le bogue.
4. Les itérations s'exécutent dos à dos, et le rapport est dû. Jusqu'à trois, sans vérification entre elles, et sans rapport intermédiaire — un rapport entre les itérations invite à s'arrêter tôt et donne l'impression qu'une exécution inachevée est terminée. Voir les étapes 8 et 9.
Trois est le budget, pas une offre d'ouverture. Il n'y a pas de quatrième itération. "voulez-vous que je fasse une passe de plus ?" · "les correctifs de l'itération 3 n'ont jamais été revus — dois-je faire une 4ème ?" Les deux rendent une décision que le budget a déjà prise, au moment où l'utilisateur est le plus susceptible de dire non. Une exécution qui atteint le plafond se termine par le rapport des causes racines (étape 9) et un choix par cause, où le premier choix est une nouvelle exécution à l'itération 1 limitée à cette cause. Ce n'est pas la règle 2 suspendue : une passe sur les corrections de l'itération 3 est vraiment due, et elle est toujours due — ce qui a été épuisé, c'est le budget pour la prendre dans cette exécution, c'est pourquoi elle devient une nouvelle exécution et pourquoi la cause qui l'obtient est la décision de l'utilisateur. Ce n'est pas non plus la règle 3 inversée : dans le budget, une passe est due et vous la commencez sans demander ; au plafond, l'exécution est terminée, et ce qui reste est une décision, proposée comme options plutôt que comme une question ouverte.
5. Ce ne sont pas des raisons. Chacune a été utilisée, par un modèle capable, pour sauter cette compétence sur un commit qui a ensuite expédié un bogue :
- la modification est petite — les modifications d'une ligne sont fausses tout le temps
- j'ai confiance en ce code — tout auteur de chaque bogue trouvé par celle-ci l'était aussi
- l'utilisateur attend / nous allons vite — c'est le moment où la qualité est échangée, ce pour quoi celle-ci existe
- la session est longue et c'est coûteux — une exécution qui ne trouve rien est peu coûteuse, le triage arrête la plupart des commits avant la partie coûteuse, et les longues passes s'exécutent en arrière-plan de toute façon (étape 3)
- je l'ai déjà exécutée sur du code connexe plus tôt — vous ne l'avez pas exécutée sur celui-ci
- c'est le propre mécanisme de la compétence, pas du vrai code — c'est du vrai code, et les pires bogues dans l'histoire de cette compétence ont été exactement dans ce mécanisme
- l'utilisateur regarde clairement et objecterait si cela le dérangeait — ils regardent la sortie, pas l'absence de sortie
Créer des bogues et passer à autre chose parce que la vérification était gênante est le comportement spécifique que cette compétence existe pour arrêter. Le faire à cette compétence n'est pas ironique, c'est juste le bogue.
À qui revient la décision du coût. Une exécution complète dure des minutes ; une mauvaise dure une demi-heure. Celui qui a installé cette compétence a déjà pesé un commit plus lent contre un bogue atteignant la branche principale. Un agent qui décide silencieusement que la vérification est trop lente aujourd'hui n'a pas fait un jugement d'ingénierie — il a outrepassé cette décision au nom de quelqu'un qui n'est pas dans la pièce, dans la direction qui se trouve être moins de travail. Si le coût compte vraiment maintenant, dites-le en une phrase et laissez-les choisir.
À qui revient la décision
Deux courtes listes, parce que les deux échecs se situent à la frontière entre elles : demander à propos de la première habitue l'utilisateur à survoler, et décider la seconde pour eux est le choix 3 pris en silence.
Les vôtres, jamais demandées. S'il faut exécuter et quand ; si un candidat est prouvé, réfuté ou abandonné ; comment corriger un bogue prouvé dans la modification ; s'il faut itérer, jusqu'au plafond ; exécuter la suite ; commiter une exécution qui s'est terminée proprement sans rien en suspens — sauf sous l'appelant commit, où le commit est celui de l'appelant.
Ceux de l'utilisateur, toujours demandés. Sur quoi agir : chaque cause racine et chaque recommandation (corriger maintenant / l'écrire / sauter), chaque entrée non résolue d'une annulation, si un commit a lieu quand quelque chose de signalé-non-corrigé change ce qu'il signifie (mode rapport uniquement), et l'arrêt de l'étape 0 — lequel des éditions stagées et non stagées divergentes d'un fichier conserver.
Quand vous demandez, utilisez le sélecteur interactif de l'hôte (dans Claude Code, l'outil AskUserQuestion) : toute question avec des options discrètes passe par lui, une question par décision, par ordre de gravité, jamais enterrée dans de la prose à la fin d'un long rapport. Le texte brut est le recours pour les hôtes sans sélecteur, pas la valeur par défaut. Le sélecteur est aussi la seule chose ici qui est structurelle plutôt que consultative — un tour avec un sélecteur ouvert ne peut pas se terminer tant que l'utilisateur n'a pas répondu — c'est pourquoi la règle suivante est importante.
Demander signifie que l'utilisateur l'a vu. Une question est posée quand elle est dans une réponse que l'utilisateur lit ou un sélecteur auquel il répond — pas quand un agent l'a écrite. Si cette compétence s'exécute dans un agent qui rend compte à un autre agent, son rapport de l'étape 9 et ses questions atteignent cet agent, et rien n'a encore été demandé : le saut déplace le sélecteur, il ne décharge pas la question. Donc :
- Si un agent que vous avez engendré a exécuté ceci sur sa propre modification, son rapport est votre entrée de l'étape 9, pas votre sortie de l'étape 9. Chaque décision ouverte dans ce rapport va devant l'utilisateur dans votre prochaine réponse, avant tout le reste — via votre sélecteur, une question par décision, ou le bloc numéroté du rapport textuellement là où il n'y en a pas. "L'exécution a été annulée" ou "il a trouvé trois causes racines" sans options en dessous, c'est relater à propos du rapport au lieu de le livrer ; si vous écrivez cette phrase, c'est le bogue. Retenir la décision à travers un tour pendant que d'autres travaux se terminent est le choix 3, fait pour eux — les autres travaux attendent, ou la réponse porte les deux.
- Si vous exécutez ceci dans un agent qui rend compte à un autre agent, vous n'avez pas de sélecteur qui atteint l'utilisateur. Imprimez le rapport entier dans son format — pas un résumé — avec le pied de page de transfert (reference.md) qui dit à quiconque le tient ce qui est encore à lui de demander. Dites clairement quelles décisions sont ouvertes et que vous n'avez pas pu les demander. Sous l'appelant commit, la liste de décisions du bloc de résultat remplace le pied de page (Quand l'appelant commit).
Une exécution n'est pas terminée tant que ses questions ne sont pas devant l'utilisateur, quel que soit l'agent qui les y amène.
Étape 0 — Périmètre
La modification examinée est la différence stagée :
git diff --cached --stat
git diff --cached
Lisez le fichier entier pour chaque fichier modifié, pas seulement les hunks — un bogue se trouve généralement dans l'interaction entre le nouveau code et le code autour.
Si un fichier apparaît à la fois dans la différence stagée et non stagée, arrêtez. Vous raisonneriez sur l'index tout en testant l'arbre de travail, et ils diffèrent. Dites à l'utilisateur quels fichiers divergent et demandez-lui de staguer ou de rétablir ces éditions. Ne jamais git stash pour contourner cela — l'utilisateur a du travail non commité et cette compétence est sur le point d'écrire des fichiers par-dessus.
Les modifications non stagées dans d'autres fichiers sont acceptables. Notez-les dans le rapport.
Ne chassez pas les bogues dans les spécifications, la documentation ou les tests existants. Les modifications de ces fichiers sont toujours un contexte valable à lire.
Étape 1 — Triage
Le triage décide à partir de la différence, pas du message de commit. Pour une différence allant jusqu'à environ 300 lignes modifiées, triez-la vous-même, dans la boucle où vous êtes déjà : un sous-agent coûte plus à démarrer que de lire une différence de cette taille. Déléguez une différence plus grande à une seule passe rapide sur un modèle petit et bon marché. Dans les deux cas, la passe reçoit la liste des fichiers, la différence, et si l'utilisateur a demandé un point de contrôle (ci-dessous). Demandez l'un de REVIEW ou SKIP plus une raison d'une ligne. Ne demandez pas d'abord un message de commit, et ne lisez pas un préfixe de sujet comme signal — cette compétence n'impose aucune convention de commit (reference.md).
SKIP lorsque la différence montre :
- Rien en dehors des docs, specs, tests, lockfiles, génération ...
[Le contenu a été tronqué pour la traduction — dans le fichier complet, cela continue avec des listes détaillées des conditions de triage et d'autres étapes importantes.]