Tests de mutation — fichier unique
Encapsule pnpm mutate <file> et analyse summary.json dans une forme compacte et structurée, adaptée aux itérations suivantes de « renforcement des mutants survivants ». Fonctionne avec n'importe quel package vitest — pnpm mutate déduit le package du chemin.
Quand l'utiliser
- L'utilisateur invoque explicitement :
/mutant-score <path>, « test de mutation sur ce fichier », « vérifie l'efficacité de mes tests sur X » - L'utilisateur vient de modifier un fichier de test et veut savoir si ses assertions sont pertinentes
- Boucle de suivi après un verdict
red— alimenter la sortie structurée vers une itération de « correction »
N'utilisez pas cette skill pour :
- Les exécutions de mutation de tout le package ou du repo entier — fichier unique uniquement
- Les questions de couverture % (utilisez le workflow de couverture existant)
- Les packages jest (
nodes-base,cli,db) — le vitest-runner de Stryker couvre uniquement les packages vitest @n8n/expression-runtime— c'est le moteur isolated-vm (bloqué par DEVP-257)
Entrées
Un argument obligatoire : le fichier source à muter. Préférez un chemin relatif au repo — le package en est déduit :
packages/workflow/src/cron.ts(package déduit)packages/@n8n/crdt/src/utils.ts(package déduit)
Un chemin relatif au package seul (src/cron.ts) est ambigu — passez le chemin relatif au repo, ou ajoutez --package-dir <pkg>. Ne devinez pas le package.
Étapes
-
Résoudre la cible. N'importe quel package vitest fonctionne ;
pnpm mutatedéduit le package d'un chemin relatif au repo. Si le fichier se trouve dans un package jest ou@n8n/expression-runtime, signalez-le et arrêtez — ne fabriquez pas de sortie. -
Exécuter Stryker avec sortie réduite :
pnpm mutate <repo-relative-file> 2>&1 | tail -40tail -40élimine le spam de la barre de progression de Stryker ; les nombres pertinents + la liste des survivants atterrissent toujours dans les ~30 dernières lignes. Codes de sortie :0= réussi,1= sous le seuil (toujours valide, summary.json existe),2= erreur d'utilisation,3= échec de Stryker (pas de summary.json). -
Si code de sortie 3, affichez la queue réduite à l'utilisateur, suggérez de vérifier que les dépendances de l'espace de travail sont construites (
pnpm build), et arrêtez. Ne fabriquez pas de rapport. -
Lire le
reports/mutation/summary.jsondu package (par exemplepackages/workflow/reports/mutation/summary.json) — jamaisraw.json. raw.json fait plus de 600 Ko et n'est pas nécessaire pour la boucle de renforcement. summary.json contient déjà chaque mutant survivant avec sa localisation, son remplacement, le nom du mutateur et les noms des tests qui ont couvert la ligne. -
Limiter covering_tests à 3 par survivant. Si un mutant a été couvert par plus de 3 tests, conservez les 3 premiers et ajoutez
+N morecomme comptage. Les noms au-delà de 3 consomment des tokens sans ajouter de signal exploitable — la boucle de renforcement a besoin de savoir quel test étendre, pas tous. -
Calculer
minimum_kills_neededpour atteindre le seuil :killed_now = summary.overall.counts.killed + summary.overall.counts.timeout valid_total = killed_now + summary.overall.counts.survived + summary.overall.counts.noCoverage needed = ceil((threshold/100) * valid_total) - killed_nowCela indique à la boucle suivante le nombre minimum de survivants qu'elle doit tuer pour basculer de
redàgreen. Limiter au nombre de survivants. -
Produire la forme structurée décrite ci-dessous. Garder la prose à une seule ligne de titre ; le reste est le bloc JSON.
Forme de sortie
Une ligne de titre, puis un bloc JSON délimité. Rien d'autre — pas de préambule, pas de commentaire par survivant, pas de triage des risques (c'est le travail de la boucle suivante).
[red|green] <score>% (seuil <T>%) — <N> survivants ; besoin de tuer ≥<K> pour passer au vert.
```json
{
"verdict": "red",
"target": "packages/workflow/src/augment-object.ts",
"package": "n8n-workflow",
"score": 76.74,
"threshold": 80,
"delta_to_threshold": 3.26,
"minimum_kills_needed": 5,
"counts": {
"killed": 99,
"survived": 28,
"no_coverage": 2,
"timeout": 0
},
"survivors": [
{
"id": "77",
"mutator": "ConditionalExpression",
"location": "src/augment-object.ts:95:6",
"original": "value === null",
"replacement": "false",
"covering_tests": [
"augmentObject should handle null values",
"augmentObject should handle nested nulls"
],
"covering_tests_overflow": 0
}
]
}
```
Trier le tableau survivors par location (numéro de ligne croissant, puis colonne) pour que la boucle de renforcement les traite de haut en bas du fichier.
Contraintes
- Pas de raw.json — jamais le lire ou l'afficher. summary.json est la seule entrée.
- Pas de rapport HTML — ne pas
openraw.html ni coller de liens. Si l'utilisateur veut explorer visuellement, il demandera. - Pas de triage automatique — ne pas catégoriser les survivants par « bug réel » vs « assurance refactorisation ». C'est une étape d'analyse séparée qui doit se faire sur demande, pas par défaut. Garde le coût en tokens prévisible.
- Pas de « je vais régénérer les tests pour vous maintenant » — cette skill rapporte l'écart. Utilisez
n8n:mutant-fixsi vous voulez des modifications d'assertion.
Suites courantes (ne les faites que si demandé)
- L'utilisateur dit « correction de ces » → démarrer une boucle de renforcement en utilisant la sortie JSON comme entrée. Lire la source des covering_tests, proposer des modifications par mutant, relancer la skill pour vérifier.
- L'utilisateur dit « explique le survivant #N » → récupérer ce mutant de summary.json, afficher ses ~5 lignes environnantes du fichier source, pas d'analyse au-delà de ce que summary.json contient.
- L'utilisateur dit « quel est le seuil ? » → 80 % provisoire ; voir
scripts/mutation-health/README.mdpour la justification. - L'utilisateur dit « exécute-la sur les fichiers modifiés » → utiliser
n8n:mutant-diff(mute le diff vs origin/master).
Connexes
scripts/mutation-health/README.md— l'histoire d'observabilité plus large soutenue par BQscripts/mutation-health/stryker.default.mjs— la configuration Stryker par défaut ; un package peut l'écraser avec son proprestryker.config.mjs(par exemple,packages/workflowexclut le moteur isolated-vm)n8n:mutant-fix— l'équivalent du renforcement des survivants