tdd (Matt Pocock)
Entwickelt Features und behebt Bugs testgetrieben mit Red-Green-Refactor und Integrationstests.
mattpocock tdd: Kein Lift, wenn der Prompt bereits test-first verlangt, und etwa 1.7x die Tokens
Codex CLI · gpt-6-astra
22.7 / 30
Lift gegenüber ohne Skill: +0.00 · Situativ · 18 Läufe
Situativ: der Lift +0.00 liegt unter +1.0. Für „Empfohlen“ sind insgesamt 22/30, eine Ausgabequalität von 3.5 und ein Lift von +1.0 nötig.
SOTA
BestandenGetestet mit Codex.
Gilt für Codex, Claude Code
Codex CLI 0.166 (SOTA-Stufe): 18 bewertete Läufe. Ein Bestehen hier deckt gemäß unserer Stufenregel auch Claude Code ab; über die zweite Stufe sagt es nichts aus.
Punktzahlen
Jede Dimension reicht von 0 bis 5, und die sechs ergeben zusammen die Gesamtpunktzahl von 30. 5 ist in jeder Dimension besser. Kosten 5 bedeutet günstig und schnell. Installation 5 bedeutet einfach.
- Trigger-Zuverlässigkeit
- 5.0
- Lift gegenüber ohne Skill
- 2.0
- Ausgabequalität
- 4.7
- Token- und Zeitkosten
- 2.0
- Installation und Portabilität
- 4.0
- Sicherheit
- 5.0
Sicherheitsprüfung
SicherStatischer Scan: 0 CRITICAL / 0 HIGH / 0 MEDIUM. Manuelle Prüfung: Sicher in einer Sandbox ohne Netzwerk auszuführen (keine Befunde). Ein sauberer Scan beweist nicht, dass ein Skill sicher ist.
Installieren
npx skills@latest add mattpocock/skills --skill tdd
Fixierter Commit: 4ae2317ddb22b046e26455e4f9c9b3aaaf62212d
Getestet: 2026-11-02
Was wir getestet haben
- Eine Funktion nach einer präzisen Spezifikation implementieren — slugify(text, max_length=None) in slug.py (Python 3, nur Standardbibliothek) mit TDD implementieren. Spezifikation: Text kleinschreiben; jede Folge von Zeichen, die keine ASCII-Buchstaben oder -Ziffern sind, durch ein einzelnes '-' ersetzen; führende und abschließende '-' entfernen; ein leeres Ergebnis…
- Eine kleine zustandsbehaftete Klasse implementieren — ratelimiter.py schreiben (Python 3, nur Standardbibliothek) test-first (red-green-refactor) mit class RateLimiter(limit, window_seconds, clock=time.monotonic): ein Sliding-Window-Limiter pro Schlüssel. allow(key) gibt True zurück und zeichnet den Aufruf auf, wenn weniger als limit…
- Einen Rundungsfehler beheben — Kunden sagen, cart_total in cart.py sei manchmal einen Cent daneben im Vergleich zu unserem Buchhaltungssystem, das bei jedem Schritt kaufmännisch auf den Cent rundet (jede Zeilensumme, die rabattierte Zwischensumme und die Steuer). Beispiel: cart_total([(1.005, 1)]) sollte 1.09 zurückgeben und…
Vorteile
- Der Skill wurde erkannt, ohne genannt zu werden: Skill-Datei in 6/6 Treatment-Läufen gelesen.
- Hohe absolute Qualität mit dem Skill: 4.67 von 5.
Nachteile
- Kein messbarer Lift gegenüber ohne Skill (+0.00, im Rauschen).
- Ein Ein-Satz-Prompt erzielte 4.67 gegenüber 4.67 mit dem Skill (+0.00).
- Verbraucht 1.7x die Tokens von ohne Skill.
- Testhinweis: Der Ein-Satz-Arm (6 Läufe) wurde später auf einem anderen Rechner als Kontroll- und Treatment-Arm ergänzt.
- n=2 pro Aufgabe und Variante; Unterschiede unter etwa 1 Punkt sind Rauschen.
Bewertung
Codex CLI 0.166 (gpt-6-astra, niedriges Reasoning) auf einem Mac-Testrechner, einem frischen temporären Projekt und temporären HOME/TMPDIR/Caches pro Lauf; Skill installiert (Treatment) oder nicht vorhanden (Kontrolle) oder nicht vorhanden mit der Kernanforderung des Skills in einem an den Prompt angehängten Satz (One-Liner-Gruppe); 2 Läufe pro Gruppe und Aufgabe; Netzwerk aus; Schreiben nach /tmp blockiert. Die Prompts nennen den Skill nie (außer der unten genannten Formulierung). Da die Beschreibung dieses Skills nur auslöst, wenn nach TDD / test-first gefragt wird, sagen die Prompts das („using TDD“, „test-first (red-green-refactor)“, „Do it test-first“). Dieselben Worte erhält die Kontrollgruppe, der Test prüft also, ob der Skill eine einfache TDD-Anfrage verbessert.
Drei-Arm-Vergleich
| Variante | Durchschnittsnote (0-5) | Tokens pro Lauf |
|---|---|---|
| Ohne Skill | 4.67 | 86k |
| Ein-Satz-Prompt | 4.67 | 178k |
| Mit Skill | 4.67 | 146k |
Gemessen mit Codex CLI über 18 Läufe, bewertet durch regelbasierte Prüfungen ohne LLM-Richter. Gesamt 22.7 / 30, Urteil Situativ.
Offenlegung: Der Ein-Satz-Arm (6 Läufe) wurde später auf einem anderen Rechner als Kontroll- und Treatment-Arm ergänzt.
Urteil: Situativ (22.7 / 30). Quelle: mattpocock/skills, skills/engineering/tdd, gepinnt auf Commit 4ae2317. Installation: npx skills@latest add mattpocock/skills --skill tdd. Lizenz: MIT (Repo-LICENSE).
Was es ist
Der Skill tdd aus Matt Pococks Skills-Repo (engineering/tdd): der Red-Green-Zyklus plus zwei Referenzdateien dazu, was ein guter Test ist und wann man mockt. Etwa 570 Wörter in SKILL.md; reines Markdown, keine Skripte. Er triggert, wenn der Nutzer testgetriebenes Arbeiten möchte.
So haben wir getestet
Codex CLI 0.166 (gpt-6-astra, low reasoning) auf einem Mac-Testgerät, pro Lauf ein frisches temporäres Projekt und temporäre HOME/TMPDIR/Caches, Skill installiert (Mit-Skill-Gruppe) oder nicht vorhanden (Kontrollgruppe) oder nicht vorhanden, aber mit der Kernanforderung des Skills als einem an den Prompt angehängten Satz (Ein-Satz-Gruppe), 2 Läufe pro Gruppe und Aufgabe, Netzwerk aus, Schreibzugriffe auf /tmp blockiert. Die Prompts nennen den Skill nie (außer der unten genannten Formulierung).
Da die Beschreibung dieses Skills nur triggert, wenn der Nutzer TDD / test-first verlangt, sagen die Prompts das auch („using TDD“, „test-first (red-green-refactor)“, „Do it test-first“). Dieselben Worte erhält die Kontrollgruppe, der Test prüft also, ob der Skill eine schlichte TDD-Anfrage verbessert.
- Eine Funktion nach präziser Spezifikation implementieren — Implementiere
slugify(text, max_length=None)in slug.py (Python 3, nur Standardbibliothek) mit TDD. Spezifikation: Text in Kleinbuchstaben umwandeln; jede Folge von Zeichen, die keine ASCII-Buchstaben oder -Ziffern sind, durch ein einzelnes '-' ersetzen; führende und abschließende '-' entfernen; ein leeres Ergebnis… - Eine kleine zustandsbehaftete Klasse implementieren — Schreibe ratelimiter.py (Python 3, nur Standardbibliothek) test-first (red-green-refactor) mit der Klasse
RateLimiter(limit, window_seconds, clock=time.monotonic): ein Sliding-Window-Limiter pro Schlüssel.allow(key)gibt True zurück und zeichnet den Aufruf auf, wenn weniger alslimit… - Einen Rundungsfehler beheben — Kunden sagen,
cart_totalin cart.py liege manchmal um einen Cent neben unserem Buchhaltungssystem, das bei jedem Schritt kaufmännisch auf den Cent rundet (jede Zeilensumme, die rabattierte Zwischensumme und die Steuer). Beispielsweise sollte cart_total([(1.005, 1)]) 1.09 zurückgeben und…
Die Bewertung erfolgt programmatisch (versteckte Tests / Trefferquote bei eingebauten Problemen / Constraint-Prüfungen / Rendern+OCR, wo relevant), 0–5 pro Lauf. Kein LLM-Richter hat eine Punktzahl entschieden.
Ergebnisse
Der Ein-Satz-Prompt für die dritte Gruppe: "Arbeite test-first in vertikalen Scheiben: Schreibe einen fehlschlagenden Test über die öffentliche Schnittstelle, bestätige, dass er fehlschlägt, schreibe den minimalen Code zum Bestehen, wiederhole das Ganze und refaktoriere erst, wenn alles grün ist; schreibe nicht alle Tests im Voraus."
| Aufgabe | Punktzahl Kontrolle | Ein-Satz | Mit Skill | Token Kontrolle | Token Ein-Satz | Token mit Skill | Skill gelesen |
|---|---|---|---|---|---|---|---|
| t1-slugify | 5.0 | 5.0 | 5.0 | 79k | 184k | 135k | 2/2 |
| t2-ratelimiter | 5.0 | 5.0 | 5.0 | 99k | 183k | 169k | 2/2 |
| t3-cart-bugfix | 4.0 | 4.0 | 4.0 | 79k | 164k | 133k | 2/2 |
Durchschnitt: 4.67 ohne vs. 4.67 mit Skill (Delta +0.0). Token pro Lauf: 86k vs. 146k (1.70x); Zeit 50s vs. 67s. Ein-Satz-Gruppe: 4.67 (Zuwachs des Skills gegenüber dem Ein-Satz-Prompt: +0.0; Zuwachs des Ein-Satz-Prompts gegenüber ohne Skill: +0.0); Token des Ein-Satz-Prompts 178k pro Lauf, der Skill kostet also 0.82x so viel wie der Ein-Satz-Prompt.
Was dabei herauskam
- Da der Prompt bereits test-first verlangte, tat die Kontrollgruppe es ebenfalls: Bei den beiden Bauaufgaben bestanden alle Läufe beider Gruppen alle Prüfungen, einschließlich „Test vor der Implementierung geschrieben“. Der Skill fügte dort nichts Messbares hinzu.
- Bei der Bugfix-Aufgabe (Cart-Rundung) behoben alle vier Läufe mit und ohne Skill den Fehler und bestanden die versteckten Tests, und alle vier scheiterten an derselben Prozessprüfung: Fix oder Test kamen im selben Schritt wie das jeweils andere, statt zuerst ein fehlschlagender Test. Der Skill änderte daran nichts.
- Der Skill wurde in 6/6 Mit-Skill-Läufen gelesen. Er ließ den Agenten viel mehr Arbeit erledigen (24–26 Befehle statt 8–10 bei den Bauaufgaben) für dasselbe Ergebnis: etwa 1.7x Token.
- Die Korrektheit bei den versteckten Tests lag in beiden Gruppen bei 100%.
- Ein-Satz-Version (test-first in vertikalen Scheiben, ein fehlschlagender Test nach dem anderen): Durchschnitt 4.67, identisch mit Kontrolle und Skill, bei 178k Token pro Lauf gegenüber 86k für die Kontrolle (2.1x) und 146k für den Skill. Die Ein-Satz-Agenten führten im Schnitt 27 Befehle pro Lauf aus gegenüber 9 bei der Kontrolle und 23 beim Skill, weil sie die Testschleife wiederholt durchliefen.
- Jede Gruppe schrieb in allen Läufen ihre eigenen Tests und bestand alle versteckten Tests; Tests vor der Implementierung wurden in allen drei Gruppen in 4 von 6 Läufen erfüllt, die Anfrage „test first“ auf Prompt-Ebene leistete also bereits, wofür der Skill gedacht ist.
Bewertung nach Dimensionen
| Dimension | Punktzahl | Begründung |
|---|---|---|
| 1_output_quality | 4.67 | Durchschnitt 4.67/5 mit Skill (programmatische Prüfungen, siehe Tabelle pro Aufgabe). |
| 2_lift_vs_no_skill | 2.0 | +0.00 Punkte gegenüber 4.67 ohne Skill (n=2 pro Aufgabe; unter etwa 1 Punkt ist Rauschen). |
| 3_trigger | 5.0 | Skill-Datei in 6/6 Mit-Skill-Läufen gelesen. |
| 4_instructions_portability | 4 | |
| 5_efficiency | 2 | 1.70x Token (146k vs. 86k pro Lauf) und 1.34x Zeit (67s vs. 50s). |
| 6_safety_hygiene | 5 |
Grenzen dieses Tests
- Jeder Test-Prompt verlangte selbst TDD, was der Kontrollgruppe den Großteil des Nutzens gibt; ein Nutzer, der das nicht verlangt, würde gar kein Triggern der Skill-Beschreibung sehen.
- Nur kleine Python-Aufgaben; die Testqualität wurde nicht bewertet.
- n = 2 pro Gruppe und Aufgabe: Unterschiede unter etwa 1 Punkt sind Rauschen.
- Regelbasierte Bewertung misst nur, was die Prüfungen sehen können; Geschmack oder ob ein Ergebnis das bestmögliche ist, lässt sich so nicht beurteilen.
Sicherheit
Siehe security.md. Scan: 0 CRITICAL / 0 HIGH / 0 MEDIUM. Urteil: sicher ausführbar (Sandbox ohne Netzwerk). Ein sauberer Scan beweist nicht, dass ein Skill sicher ist.
Fazit
Auf eine test-first-Anfrage hin erzielt dieser Skill bei kleinen Aufgaben keinen Zusatznutzen: Kontrolle, Ein-Satz-Version und Skill erreichten alle 4.67, während der Skill 1.7x und der Satz 2.1x die Token der Kontrolle verbrauchten. Er kann helfen, Tests über eine längere Sitzung hinweg verhaltensorientiert zu halten, was wir nicht gemessen haben.
Transkript
Laufprotokoll: tdd (Codex CLI, network off, per-run temp HOME/TMPDIR, one row per graded run.) Spalten: Aufgabe, Gruppe-Lauf, Punktzahl (0-5), Tokens, Sekunden, bestandene Prüfungen, vom Agenten geöffnete Skill-Dateien. t1-slugify control-1: Punkte 5.0, Tokens 78904, Sek. 50.3, Prüfungen 3/3, nichts geöffnet t1-slugify control-2: Punkte 5.0, Tokens 79205, Sek. 47.1, Prüfungen 3/3, nichts geöffnet t1-slugify oneliner-1: Punkte 5.0, Tokens 199600, Sek. 74.7, Prüfungen 3/3, nichts geöffnet t1-slugify oneliner-2: Punkte 5.0, Tokens 168650, Sek. 68.2, Prüfungen 3/3, nichts geöffnet t1-slugify treatment-1: Punkte 5.0, Tokens 144538, Sek. 57.6, Prüfungen 3/3, geöffnet tdd t1-slugify treatment-2: Punkte 5.0, Tokens 126047, Sek. 50.7, Prüfungen 3/3, geöffnet tdd t2-ratelimiter control-1: Punkte 5.0, Tokens 99439, Sek. 60.2, Prüfungen 3/3, nichts geöffnet t2-ratelimiter control-2: Punkte 5.0, Tokens 99611, Sek. 54.3, Prüfungen 3/3, nichts geöffnet t2-ratelimiter oneliner-1: Punkte 5.0, Tokens 159969, Sek. 70.9, Prüfungen 3/3, nichts geöffnet
18 Läufe, 3 Artefakte
Beispielausgabe
SOTA · With the skill: test_slug.py (t1-slugify, run 1, Codex)
import unittest from slug import slugify class SlugifyTests(unittest.TestCase): def test_hard_cuts_first_word_when_it_exceeds_limit(self): self.assertEqual(slugify('Supercalifragilistic', 5), 'super') def test_truncates_at_word_boundary(self): self.assertEqual(slugify('Hello, World!', 8), 'hello') def test_normalizes_text(self): self.assertEqual(slugify('Hello, World!'), 'hello-world') def test_preserves_only_ascii_letters_and_digits(self): self.assertEqual(slugify(' -- CAFÉ_42\t中文 / Test!! '), 'caf-42-test') def test_lowercases_before_filtering(self): self.assertEqual(slugify('\u212aELVIN'), 'kelvin') def test_keeps_slug_that_fits_limit(self): for limit in (11, 20, None): with self.subTest(limit=limit): self.assertEqual(slugify('Hello, World!', limit), 'hello-world') def test_keeps_complete_words_without_trailing_separator(self): for limit, expected in ((3, 'one'), (4, 'one'), (6, 'one'), (7, 'one-two'), (8, 'one-two')): with self.subTest(limit=limit): self.assertEqual(slugify('one two three', limit), expected) def test_hard_cuts_long_first_word_even_with_later_words(self): self.assertEqual(slugify('Supercalifragilistic hello', 5), 'super') def test_applies_limit_to_fallback(self): self.assertEqual(slugify('', 2), 'n') def test_empty_normalized_text_has_fallback(self): for text in ('', ' !!! ', '中文'): with self.subTest(text=text): self.assertEqual(slugify(text), 'n-a') if __name__ == '__main__': unittest.main()