mutant-diff

Par n8n-io · n8n

Exécute les tests de mutation Stryker sur les fichiers source modifiés dans la branche courante (par rapport à origin/master) dans les packages vitest. Une seule commande pour « mon travail tient-il face aux mutations ? » avant de pousser. Trie les fichiers dont le score est passé sous le seuil et propose d'invoquer n8n:mutant-fix sur ceux-ci. À utiliser quand l'utilisateur dit /mutant-diff, « mute ce que j'ai changé », « vérifie mes changements », ou vient de terminer l'écriture d'une fonctionnalité et veut un retour avant la fusion.

npx skills add https://github.com/n8n-io/n8n --skill mutant-diff

Mutate ce que j'ai changé

Ferme la boucle locale de développement. Une seule commande pour exécuter Stryker sur chaque fichier source modifié que la branche actuelle a touché (vs origin/master) dans un package mutation-eligible, puis signaler les échecs qui ont besoin d'être renforcés.

Quand l'utiliser

  • L'utilisateur dit /mutant-diff, "mutate the files I changed", "check my changes", "did my tests stick"
  • En cours de fonctionnalité : le dev veut un retour pré-fusion avant de pousser
  • Pré-PR : moins cher que d'attendre le cron nocturne

Ne pas utiliser :

  • Pour un seul fichier spécifique (/n8n:mutant-score <path> est plus rapide)
  • Après que l'utilisateur ait déjà exécuté /n8n:mutant-fix (qui appelle mutant-score en interne pour vérification — exécuter les deux à nouveau gaspille du calcul)

Les fichiers modifiés dans les packages jest (nodes-base, cli, db, …) et dans @n8n/expression-runtime sont automatiquement ignorés — voir étape 1.

Entrées

  • Base par défaut : origin/master. Remplacez par --base <ref> si vous comparez avec une autre branche (ex. --base HEAD~5).
  • Scope par défaut : packages/**/src/**/*.ts, réduit aux packages mutation-eligible (vitest) à l'étape 1.

Étapes

1. Identifier les fichiers source modifiés et éligibles

git diff --name-only origin/master...HEAD -- 'packages/**/src/**/*.ts'

(... est correct — trois points signifient « depuis la divergence de la branche par rapport à la base », ce que nous voulons.)

Si git fetch n'a pas été exécuté récemment, suggérez à l'utilisateur d'exécuter git fetch origin master en premier ; sinon la ref de base est obsolète.

Filtrez :

  • **/*.d.ts (déclarations, aucun comportement)
  • **/*.stories.ts (scaffolding Storybook)
  • Les fichiers index.ts (barrels)
  • interfaces.ts, types.ts, constants.ts (faible valeur, même filtre que le picker utilise)
  • fichiers dans des packages non-éligibles : pour chaque fichier modifié, trouvez son package (répertoire ancêtre le plus proche avec un package.json). Conservez le fichier uniquement si ce package a un vitest.config.* et n'est pas @n8n/expression-runtime (moteur isolated-vm — bloqué sur DEVP-257). Supprimez les packages jest avec une note d'une ligne : skipped (jest): packages/cli/src/....

2. Surface le plan à l'utilisateur

Imprimez la liste filtrée avant d'exécuter quoi que ce soit. Chaque exécution Stryker prend 1–5 minutes ; l'utilisateur doit confirmer s'il y en a beaucoup.

Found N changed source files to mutate (J skipped: jest / expression-runtime):
  - packages/workflow/src/foo.ts
  - packages/@n8n/crdt/src/bar.ts
  ...

Estimated runtime: ~M-K minutes (M minutes minimum if every Stryker run is fast).
Proceed? (skill default: yes if N ≤ 3, ask if N > 3)

Si la liste filtrée est vide : rapportez « No mutation-eligible source files changed vs $base — nothing to mutate. » et arrêtez. Quittez proprement.

Si N > 8 : refusez et demandez à l'utilisateur de réduire le scope (une ref de base différente, ou invoquez par fichier). Exécuter 8+ mutations séquentiellement est une session de 30+ minutes qui devrait être un choix délibéré.

3. Exécuter les tests de mutation par fichier

Pour chaque fichier du plan, invoquez pnpm mutate <repo-relative-path> (le package est déduit du chemin). Capturez le score par fichier à partir de la ligne de résumé ✓ / ✗ que mutate.mjs affiche sur stderr — ne relisez pas summary.json (il est écrasé à chaque exécution, et se trouve dans le propre package du fichier).

Après que chaque exécution soit terminée, imprimez une ligne :

✓ packages/workflow/src/foo.ts        95.12% (39/41 killed)   GREEN
✗ packages/@n8n/crdt/src/bar.ts       54.83% (17/31 killed)   RED  — 13 survivors, top: ConditionalExpression, EqualityOperator

Si une exécution Stryker échoue brutalement (sortie 3, pas de summary.json), imprimez ! <file> Stryker failed — see stderr et passez au fichier suivant. N'abandonnez pas le lot entier.

4. Tableau de synthèse

Après que tous les fichiers aient été mutés, imprimez un tableau compact :

=== Mutation results: N files, M green, K red, J failed ===
| File                            | Score   | Verdict | Survivors |
|---------------------------------|---------|---------|-----------|
| packages/workflow/src/foo.ts    |  95.12% | GREEN   |         2 |
| packages/@n8n/crdt/src/bar.ts   |  54.83% | RED     |        13 |
| packages/workflow/src/baz.ts    |    n/a  | FAILED  |         - |

5. Proposez l'étape de renforcement sur le fichier rouge le pire

Si un fichier est revenu rouge :

The lowest-score red file is packages/@n8n/crdt/src/bar.ts (54.83%, 13 survivors). Run /n8n:mutant-fix <file> to triage them and write assertion changes? (suggesting; don't auto-invoke)

Suggérez un seul fichier à la fois — n8n:mutant-fix plafonne à 5 survivors par invocation, et réexécuter cette skill après des édits est bon marché.

Si tout est vert : rapportez-le et arrêtez. Aucun suivi nécessaire.

Forme de sortie

Trois sections livrables par invocation :

  1. Plan (avant d'exécuter) — liste des fichiers éligibles (+ nombre ignoré), temps d'exécution estimé
  2. Progression par fichier (pendant) — une ligne par fichier au moment de sa fin
  3. Tableau de synthèse + recommandation (après) — vue compacte

Ne déversez pas les payloads complets summary.json — chaque exécution mutate en écrit un dans <package>/reports/mutation/ (écrasé à chaque exécution). L'utilisateur peut lire le plus récent s'il veut des détails.

Contraintes

  • Packages vitest uniquement. Les packages jest et @n8n/expression-runtime sont filtrés à l'étape 1, pas mutés.
  • Max 8 fichiers par invocation. Au-delà, demandez à l'utilisateur de réduire.
  • N'auto-invoquez pas /n8n:mutant-fix. Suggérez, n'agissez pas. Même raison que les autres skills : chaque passage devrait être une étape humaine délibérée approuvée.
  • Pas de commits. Les édits atterrissent dans l'arborescence de travail ; l'utilisateur examine.
  • Pas de scores fabriqués. Si une exécution Stryker échoue, marquez FAILED dans le tableau — ne devinez jamais une valeur.

Suivis courants

  • "strengthen them all" → bouclez l'utilisateur via /n8n:mutant-fix, un fichier à la fois
  • "what changed?" → git diff origin/master...HEAD -- <file> pour le fichier en question
  • "ignore <pattern>" → réexécutez avec l'exclusion de l'utilisateur ajoutée au filtre

Connexe

  • n8n:mutant-score — version mono-fichier de cette skill
  • n8n:mutant-fix — étape naturelle suivante quand des rouges apparaissent

Skills similaires