test-driven-development (obra/superpowers)
Implémente fonctionnalités et correctifs en test-first, en écrivant d'abord le test qui échoue.
superpowers test-driven-development : fait écrire le test d'abord à l'agent, et coûte environ 1.6 fois les tokens
Codex CLI · gpt-6-astra
24.0 / 30
Gain par rapport à sans skill : +1.00 · Recommandé · 18 exécutions
Recommandé : total 24.0/30 d'au moins 22, qualité de sortie 5.0 d'au moins 3.5 et gain +1.00 d'au moins +1.0.
SOTA
RéussiTesté avec Codex.
Couvre Codex, Claude Code
Codex CLI 0.166 (palier SOTA) : 18 exécutions notées. Une réussite ici couvre aussi Claude Code selon notre règle de palier ; elle ne dit rien du second palier.
Scores
Chaque dimension va de 0 à 5 et les six forment le total sur 30. 5 est la meilleure note dans chaque dimension. Coût 5 signifie bon marché et rapide. Installation 5 signifie facile.
- Fiabilité du déclenchement
- 5.0
- Gain par rapport à sans skill
- 3.0
- Qualité de sortie
- 5.0
- Coût en tokens et en temps
- 2.0
- Installation et portabilité
- 4.0
- Sécurité
- 5.0
Revue de sécurité
SûrScan statique : 0 CRITIQUE / 0 ÉLEVÉ / 0 MOYEN. Revue manuelle : sûr à exécuter dans un bac à sable sans réseau (aucun problème détecté). Un scan propre ne prouve pas qu'un skill est sûr.
Installer
npx skills@latest add obra/superpowers --skill test-driven-development
Commit épinglé: 2ce8aa15d05bd57213e6f746f953aafb7ded7a8b
Testé: 2026-11-02
Ce que nous avons testé
- Implémenter une fonction à partir d'une spec précise — Implémentez slugify(text, max_length=None) dans slug.py (Python 3, bibliothèque standard uniquement). Spec : mettre le texte en minuscules ; remplacer chaque suite de caractères qui ne sont pas des lettres ASCII ou des chiffres par un seul '-'; supprimer les '-' en début et en fin ; un résultat vide devient 'n…
- Implémenter une petite classe à état — Écrivez ratelimiter.py (Python 3, bibliothèque standard uniquement) avec la classe RateLimiter(limit, window_seconds, clock=time.monotonic) : un limiteur à fenêtre glissante par clé. allow(key) renvoie True et enregistre l'appel s'il y a moins de limit appels enregistrés dans les dernières…
- Corriger un bug d'arrondi — Les clients disent que cart_total dans cart.py est parfois à un centime près par rapport à notre système comptable, qui arrondit au centime supérieur à chaque étape (total de chaque ligne, sous-total remisé et taxe). Par exemple cart_total([(1.005, 1)]) devrait renvoyer 1.09 et…
Points forts
- Fait passer le score moyen de 4.0 à 5.0 par rapport à sans skill (+1.00).
- Le skill a été détecté sans être nommé : son fichier a été lu dans 6/6 exécutions avec skill.
- Fait mieux que la version en une phrase de sa propre règle de +0.33.
- Qualité absolue élevée avec le skill : 5.0 sur 5.
Points faibles
- Consomme 1.65 fois plus de tokens que sans skill.
- Réserve de test : le bras « prompt d'une phrase » (6 exécutions) a été ajouté plus tard, sur une machine différente de celles des bras de contrôle et avec skill.
- n=2 par tâche et par bras ; les écarts inférieurs à environ 1 point sont du bruit.
Avis
Codex CLI 0.166 (gpt-6-astra, low reasoning) sur un Mac de test, un projet temporaire neuf et des HOME/TMPDIR/caches temporaires à chaque exécution, skill installé (traitement) ou absent (contrôle) ou absent avec l'exigence centrale du skill compressée en une phrase ajoutée au prompt (groupe « prompt d'une phrase »), 2 exécutions par groupe et par tâche, réseau coupé, écritures dans /tmp bloquées. Les prompts ne mentionnent jamais le skill. La notation est programmatique (tests cachés / rappel d'éléments plantés / vérifications de contraintes / rendu+OCR le cas échéant), de 0 à 5 par exécution. Aucun juge LLM n'a décidé d'un score.
Comparaison à trois bras
| Bras | Score moyen (0-5) | Tokens par exécution |
|---|---|---|
| Sans le skill | 4.0 | 65k |
| Prompt d'une phrase | 4.67 | 127k |
| Avec le skill | 5.0 | 108k |
Mesuré avec Codex CLI sur 18 exécutions, noté par des contrôles basés sur des règles, sans juge LLM. Total 24.0 / 30, verdict Recommandé.
Divulgation : le bras « prompt d'une phrase » (6 exécutions) a été ajouté plus tard, sur une machine différente de celles des bras de contrôle et avec skill.
Verdict : Recommandé (24.0 / 30). Source : obra/superpowers, skills/test-driven-development, épinglé au commit 2ce8aa1. Installation : npx skills@latest add obra/superpowers --skill test-driven-development. Licence : MIT (LICENSE du dépôt).
Présentation
Le skill test-driven-development d’obra/superpowers. Sa description indique « à utiliser lors de l’implémentation de toute fonctionnalité ou correction de bug, avant d’écrire le code d’implémentation ». Environ 1 500 mots de Markdown (la « loi de fer » red-green-refactor, un tableau d’excuses pour éviter le test, une checklist de vérification) plus un fichier supplémentaire sur l’écriture de bons tests. Aucun script.
Méthode de test
Codex CLI 0.166 (gpt-6-astra, raisonnement faible) sur une machine de test Mac, un projet temporaire neuf et des HOME/TMPDIR/caches temporaires à chaque exécution, skill installé (groupe avec skill), absent (groupe témoin), ou absent avec l’exigence centrale du skill compressée en une phrase ajoutée au prompt (groupe « prompt en une phrase »), 2 exécutions par groupe et par tâche, réseau désactivé, écritures dans /tmp bloquées. Les prompts ne mentionnent jamais le skill.
- Implémenter une fonction à partir d’une spécification précise — Implémente
slugify(text, max_length=None)dans slug.py (Python 3, bibliothèque standard uniquement). Spécification : mettre le texte en minuscules ; remplacer chaque suite de caractères qui ne sont ni des lettres ASCII ni des chiffres par un seul '-' ; supprimer les '-' de début et de fin ; un résultat vide devient 'n… - Implémenter une petite classe à état — Écris ratelimiter.py (Python 3, bibliothèque standard uniquement) avec la classe
RateLimiter(limit, window_seconds, clock=time.monotonic): un limiteur à fenêtre glissante par clé.allow(key)renvoie True et enregistre l’appel si moins delimitappels ont été enregistrés dans les dernières… - Corriger un bug d’arrondi — Les clients disent que
cart_totaldans cart.py est parfois à un centime près par rapport à notre système comptable, qui arrondit au centime supérieur à chaque étape (total de chaque ligne, sous-total remisé et taxe). Par exemple cart_total([(1.005, 1)]) devrait renvoyer 1.09 et…
Le scoring est programmatique (tests cachés / détection des problèmes implantés / vérifications de contraintes / rendu + OCR le cas échéant), de 0 à 5 par exécution. Aucun juge LLM n’a attribué de score.
Résultats
Le prompt en une phrase donné au troisième groupe : « Applique strictement red-green-refactor : écris d’abord un test qui échoue et regarde-le échouer pour la bonne raison, écris l’implémentation minimale pour le faire passer, puis refactorise ; aucun code de production sans un test qui échoue d’abord. »
| Tâche | Score témoin | Prompt en une phrase | Avec skill | Tokens témoin | Tokens du prompt en une phrase | Tokens avec skill | Skill lu |
|---|---|---|---|---|---|---|---|
| t1-slugify | 4.0 | 5.0 | 5.0 | 62k | 134k | 108k | 2/2 |
| t2-ratelimiter | 4.0 | 5.0 | 5.0 | 63k | 147k | 97k | 2/2 |
| t3-cart-bugfix | 4.0 | 4.0 | 5.0 | 69k | 97k | 116k | 2/2 |
Score moyen : 4.0 sans le skill contre 5.0 avec (écart +1.0). Tokens par exécution : 65k contre 108k (1.65x) ; temps 55s contre 51s. Groupe « prompt en une phrase » : 4.67 (gain du skill sur ce prompt : +0.33 ; gain du prompt par rapport à l’absence de skill : +0.67) ; tokens du prompt : 127k par exécution, donc le skill coûte 0.85x le prompt en une phrase.
Ce qui s’est passé
- L’exactitude était identique : les suites de tests cachés ont réussi dans les 12 exécutions des deux groupes (12/12, 10/10 et 11/11 tests). Sur ces petites tâches, le skill ne change pas si le code fonctionne.
- Ce qu’il change, c’est l’ordre du travail. Dans les 6 exécutions avec skill, le fichier de test a été écrit à une étape antérieure à l’implémentation ; dans les 6 exécutions témoins, l’agent a écrit les tests et l’implémentation dans le même patch (ou a corrigé le bug d’abord et ajouté le test ensuite dans la tâche du panier). Dans l’exécution avec skill que nous avons relue (slugify), l’agent a écrit le test, l’a lancé pour le voir échouer, puis a écrit le code.
- Il se déclenche rien qu’à partir de la description : le fichier du skill a été lu dans 6/6 exécutions avec skill alors qu’aucun prompt ne mentionnait TDD.
- Il coûte plus cher : environ 1.65x les tokens par exécution (107k contre 65k) pour un temps réel similaire (51 s contre 55 s), car l’agent lit le skill et son fichier compagnon et exécute la boucle plusieurs fois.
- Version en une phrase (strict red-green-refactor, aucun code de production sans un test qui échoue) : moyenne 4.67, entre le témoin (4.0) et le skill (5.0), à 127k tokens par exécution, contre 65k pour le témoin (2.0x) et 108k pour le skill (le prompt coûte donc 1.2x le skill).
- Les tests ont été écrits avant l’implémentation dans 0 des 6 exécutions témoins, 4 des 6 exécutions du prompt et 6 des 6 exécutions du skill ; les deux exécutions manquantes du prompt concernent la tâche de correction du panier. Le skill est le seul groupe à l’avoir fait à chaque fois, et il l’a fait avec moins de commandes (10 par exécution) que le prompt (19).
Scores par dimension
| Dimension | Score | Pourquoi |
|---|---|---|
| 1_output_quality | 5.0 | Score moyen de 5.00/5 avec le skill (vérifications programmatiques, voir le tableau par tâche). |
| 2_lift_vs_no_skill | 3.0 | +1.00 point par rapport à 4.00 sans le skill (n=2 par tâche ; un écart inférieur à ~1 point relève du bruit). |
| 3_trigger | 5.0 | Fichier du skill lu dans 6/6 exécutions avec skill. |
| 4_instructions_portability | 4 | |
| 5_efficiency | 2 | 1.65x tokens (108k contre 65k par exécution) et 0.93x temps (51s contre 55s). |
| 6_safety_hygiene | 5 |
Limites de ce test
- Les tests cachés réussissent tous pour les deux groupes (plafond), donc le gain mesuré est la vérification de processus (test écrit avant l’implémentation) que nous calculons à partir du journal d’événements, pas une différence de résultat.
- Les tâches sont de petits exercices Python dans un seul fichier ; les dépôts plus gros, d’autres langages et la qualité des tests (par exemple le mutation testing) n’ont pas été testés.
- n = 2 par groupe et par tâche : un écart inférieur à ~1 point relève du bruit.
- Le scoring par règles mesure ce que les vérifications peuvent voir ; il ne peut juger du goût ni du caractère optimal d’un résultat.
Sécurité
Voir security.md. Scan : 0 CRITICAL / 0 HIGH / 0 MEDIUM. Verdict : exécution sans danger (sandbox sans réseau). Un scan propre ne prouve pas qu’un skill est sûr.
En résumé
Il fait ce qu’il annonce : c’est le seul groupe qui a écrit le test en échec en premier à chaque exécution (6/6, contre 0/6 pour le témoin et 4/6 pour la version en une phrase), pour 1.7x les tokens du témoin et 0.85x ceux de la version en une phrase. L’exactitude finale sur ces petites tâches était la même dans tous les groupes : le gain porte donc sur le processus, pas sur le code.
Transcription
Journal d'exécution : test-driven-development (Codex CLI, network off, per-run temp HOME/TMPDIR, one row per graded run.) Colonnes : tâche, groupe-exécution, score (0-5), tokens, secondes, vérifications réussies, fichiers de la skill ouverts par l'agent. t1-slugify control-1: score 4.0, tokens 62017, s 55.5, vérifications 2/3, rien ouvert t1-slugify control-2: score 4.0, tokens 62139, s 53.8, vérifications 2/3, rien ouvert t1-slugify oneliner-1: score 5.0, tokens 135535, s 52.9, vérifications 3/3, rien ouvert t1-slugify oneliner-2: score 5.0, tokens 134448, s 46.7, vérifications 3/3, rien ouvert t1-slugify treatment-1: score 5.0, tokens 118034, s 56.3, vérifications 3/3, ouvert test-driven-development t1-slugify treatment-2: score 5.0, tokens 97974, s 48.3, vérifications 3/3, ouvert test-driven-development t2-ratelimiter control-1: score 4.0, tokens 63363, s 46.1, vérifications 2/3, rien ouvert t2-ratelimiter control-2: score 4.0, tokens 63431, s 98.9, vérifications 2/3, rien ouvert t2-ratelimiter oneliner-1: score 5.0, tokens 140042, s 60.8, vérifications 3/3, rien ouvert
18 exécutions, 3 artefacts
Exemple de sortie
SOTA · With the skill: test_slug.py (t1-slugify, run 1, Codex)
import unittest from slug import slugify class SlugifyTests(unittest.TestCase): def test_normalizes_text(self): cases = [ ('Hello, World!', 'hello-world'), (' --ABC__123\t\nxyz!! ', 'abc-123-xyz'), ('café déjà vu 12٣', 'caf-d-j-vu'), ('İ X', 'i-x'), ('already-a-slug', 'already-a-slug'), ] for text, expected in cases: with self.subTest(text=text): self.assertEqual(slugify(text), expected) def test_empty_result_uses_fallback(self): for text in ('', '--- !\t', '中文', '😀'): with self.subTest(text=text): self.assertEqual(slugify(text), 'n-a') def test_length_limits_respect_word_boundaries(self): cases = [ ('Hello, World!', 8, 'hello'), ('Hello, World!', 11, 'hello-world'), ('Hello, World!', 20, 'hello-world'), ('Hello, World!', 5, 'hello'), ('Hello, World!', 6, 'hello'), ('one two three', 7, 'one-two'), ('one two three', 9, 'one-two'), ('Supercalifragilistic', 5, 'super'), ('Supercalifragilistic next', 5, 'super'), ('abc', 1, 'a'), ('abc', 0, ''), ('!!!', 1, 'n'), ('!!!', 2, 'n'), ('!!!', 3, 'n-a'), ] for text, limit, expected in cases: with self.subTest(text=text, limit=limit): self.assertEqual(slugify(text, limit), expected) def test_explicit_none_leaves_length_unlimited(self): self.assertEqual(slugify('Hello, World!', None), 'hello-world') if __name__ == '__main__': unittest.main()