모든 스킬

tdd (Matt Pocock)

레드-그린-리팩터링과 통합 테스트를 통해 테스트를 먼저 작성하며 기능을 만들고 버그를 고칩니다.

mattpocock tdd: 프롬프트가 이미 테스트 우선을 요구한 경우 향상이 없었고, 토큰은 약 1.7배 사용했습니다

상황에 따라안전

Codex CLI · gpt-6-astra

22.7 / 30

스킬 없이 대비 향상폭: +0.00 · 상황에 따라 · 18회 실행

상황에 따라: 향상폭 +0.00가 +1.0 미만. 추천이 되려면 총점 22/30, 출력 품질 3.5, 향상폭 +1.0이 필요합니다.

SOTA

통과

Codex로 테스트

커버 대상 Codex, Claude Code

Codex CLI 0.166 (SOTA 티어): 채점된 실행 18회. 여기서 통과하면 티어 규칙에 따라 Claude Code도 커버되지만, 두 번째 티어에 대해서는 아무것도 말해주지 않습니다.

점수

각 차원은 0~5점이며 여섯 차원을 더하면 30점 만점의 총점이 됩니다. 모든 차원에서 5가 가장 좋습니다. 비용 5는 저렴하고 빠름, 설치 5는 쉬움을 뜻합니다.

트리거 신뢰도
5.0
스킬 없이 대비 향상폭
2.0
출력 품질
4.7
토큰 및 시간 비용
2.0
설치 및 이식성
4.0
안전성
5.0

보안 리뷰

안전

정적 스캔: CRITICAL 0 / HIGH 0 / MEDIUM 0. 수동 검토: 네트워크가 차단된 샌드박스에서 실행 안전(발견 사항 없음). 스캔이 깨끗하다고 해서 스킬이 안전하다는 증거는 아닙니다.

설치

npx skills@latest add mattpocock/skills --skill tdd

출처

고정 커밋: 4ae2317ddb22b046e26455e4f9c9b3aaaf62212d

테스트일: 2026-11-02

테스트한 과제

  • 명세에 따라 함수 구현 — slug.py에 slugify(text, max_length=None)를 TDD로 구현하세요(Python 3, 표준 라이브러리만 사용). 명세: 텍스트를 소문자로 바꿉니다. ASCII 문자나 숫자가 아닌 문자가 연속된 구간은 하나의 '-'로 바꿉니다. 앞뒤의 '-'를 제거합니다. 결과가 비어 있으면…
  • 작은 상태 저장 클래스 구현 — ratelimiter.py를 테스트 우선(레드-그린-리팩터) 방식으로 작성하세요(Python 3, 표준 라이브러리만 사용). 클래스는 RateLimiter(limit, window_seconds, clock=time.monotonic)이며, 키별 슬라이딩 윈도 리미터입니다. allow(key)는 호출 수가 limit보다 적으면 True를 반환하고 호출을 기록합니다…
  • 반올림 버그 수정 — 고객들은 cart.py의 cart_total이 회계 시스템과 비교해 가끔 1센트 어긋난다고 합니다. 회계 시스템은 각 단계(각 라인 합계, 할인된 소계, 세금)에서 0.5를 올리는 방식으로 센트 단위 반올림합니다. 예를 들어 cart_total([(1.005, 1)])은 1.09를 반환해야 하는데…

장점

  • 스킬 이름을 언급하지 않았는데도 적용되었습니다. 스킬 사용군 실행 6/6회에서 스킬 파일을 읽었습니다.
  • 스킬 사용 시 높은 절대 품질: 4.67/5.

단점

  • 스킬 없이보다 측정 가능한 향상 없음(+0.00, 노이즈 범위 안).
  • 한 문장 프롬프트는 4.67점, 스킬 사용은 4.67점(+0.00).
  • 스킬 없이보다 토큰을 1.7배 사용합니다.
  • 테스트 참고: 한 문장 프롬프트군(6회 실행)은 대조군·스킬 사용군과 다른 머신에서 나중에 추가되었습니다.
  • 과제·그룹당 n=2이며, 약 1점 미만의 차이는 노이즈입니다.

리뷰

Codex CLI 0.166 (gpt-6-astra, low reasoning)을 Mac 테스트 머신에서 실행했고, 실행마다 새 임시 프로젝트와 임시 HOME/TMPDIR/캐시를 사용했습니다. 스킬 설치(스킬 사용군), 미설치(대조군), 미설치 상태에서 스킬의 핵심 요구사항만 한 문장으로 압축해 프롬프트에 덧붙인 경우(한 문장 프롬프트군)로 나눴으며, 과제·그룹당 2회씩 실행했습니다. 네트워크는 끄고 /tmp 쓰기는 차단했습니다. 프롬프트에는 스킬 이름을 언급하지 않았습니다(아래에 적은 경우 제외). 이 스킬의 설명은 사용자가 TDD / 테스트 우선을 요청할 때만 트리거되므로 프롬프트에 그렇게 명시했습니다("TDD로 진행", "테스트 우선(레드-그린-리팩터)", "테스트 먼저 진행"). 대조군에도 같은 문구를 넣었기 때문에, 이 테스트는 TDD를 요청한 평범한 프롬프트 위에서 스킬이 얼마나 개선하는지를 봅니다.

3개 그룹 비교

그룹평균 점수 (0-5)실행당 토큰
스킬 없음4.6786k
한 문장 프롬프트4.67178k
스킬 사용4.67146k

Codex CLI에서 18회 실행해 측정했고, LLM 심사 없이 규칙 기반 검사로 채점했습니다. 총점 22.7 / 30, 판정 상황에 따라.

참고: 한 문장 프롬프트군(6회)은 나중에 다른 머신에서 추가되어 대조군·스킬 사용군과 환경이 다릅니다.

판정: 상황에 따라 다름 (22.7 / 30). 출처: mattpocock/skills, skills/engineering/tdd, 커밋 4ae2317에 고정. 설치: npx skills@latest add mattpocock/skills --skill tdd. 라이선스: MIT (저장소 LICENSE).

어떤 스킬인가

Matt Pocock의 skills 저장소(engineering/tdd)에 있는 tdd 스킬입니다. 레드-그린 루프와, 좋은 테스트란 무엇인지와 언제 목을 사용할지를 다룬 참고 파일 두 개가 있습니다. SKILL.md는 약 570단어이며 순수 Markdown이고 스크립트는 없습니다. 사용자가 테스트 우선 작업을 원할 때 트리거됩니다.

테스트 방법

Codex CLI 0.166(gpt-6-astra, 낮은 추론)을 Mac 테스트 머신에서 실행했고, 실행마다 새 임시 프로젝트와 임시 HOME/TMPDIR/캐시를 사용했습니다. 스킬을 설치한 경우(스킬 사용군), 설치하지 않은 경우(대조군), 스킬의 핵심 요구사항을 한 문장으로 압축해 프롬프트 끝에 붙인 경우(한 문장 프롬프트군)로 나눴고, 작업마다 각 군 2회씩 실행했습니다. 네트워크는 끄고 /tmp 쓰기는 차단했습니다. 프롬프트에는 스킬 이름을 전혀 언급하지 않았습니다(아래에 적은 표현은 예외).

이 스킬의 설명은 사용자가 TDD / 테스트 우선을 요청할 때만 트리거되므로, 프롬프트에 그렇게 적었습니다("using TDD", "test-first (red-green-refactor)", "Do it test-first"). 같은 표현을 대조군에도 주었으므로, 이 테스트는 스킬이 평범한 TDD 요청을 개선하는지를 봅니다.

  1. 정확한 명세로 함수 구현 — TDD를 사용해 slug.py에 slugify(text, max_length=None)를 구현하세요(Python 3, 표준 라이브러리만). 명세: 텍스트를 소문자로; ASCII 문자나 숫자가 아닌 문자의 연속 구간을 하나의 '-'로 바꿈; 앞뒤 '-' 제거; 빈 결과…
  2. 작은 상태 저장 클래스 구현 — RateLimiter(limit, window_seconds, clock=time.monotonic) 클래스로 ratelimiter.py(Python 3, 표준 라이브러리만)를 테스트 우선(레드-그린-리팩터)으로 작성하세요. 키별 슬라이딩 윈도 리미터입니다. allow(key)는 호출 수가 limit보다 적으면 True를 반환하고 호출을 기록…
  3. 반올림 버그 수정 — 고객은 cart.py의 cart_total이 회계 시스템과 비교해 가끔 1센트 어긋난다고 합니다. 회계 시스템은 각 단계(각 라인 합계, 할인된 소계, 세금)에서 센트 단위로 반올림(half-up)합니다. 예를 들어 cart_total([(1.005, 1)])은 1.09를 반환해야 하…

채점은 프로그램 방식(숨은 테스트, 심어 둔 문제 탐지, 제약 조건 검사, 해당되는 경우 렌더링+OCR)으로 실행당 0~5점입니다. 점수를 결정한 LLM 심사자는 없습니다.

결과

세 번째 군에 전달한 한 문장 프롬프트: "수직 슬라이스로 테스트 우선 작업을 하세요. 공개 인터페이스를 통한 실패하는 테스트를 하나 작성하고, 실패를 확인하고, 통과할 최소한의 코드를 작성하고, 반복하되 그린일 때만 리팩터하세요. 테스트를 한꺼번에 미리 작성하지 마세요."

작업대조군 점수한 문장 프롬프트스킬 사용대조군 토큰한 문장 프롬프트 토큰스킬 사용 토큰스킬 읽음
t1-slugify5.05.05.079k184k135k2/2
t2-ratelimiter5.05.05.099k183k169k2/2
t3-cart-bugfix4.04.04.079k164k133k2/2

평균 점수: 스킬 없이 4.67, 스킬 사용 시 4.67(델타 +0.0). 실행당 토큰: 86k 대 146k(1.70배), 시간 50초 대 67초. 한 문장 프롬프트군: 4.67(한 문장 프롬프트 대비 스킬의 이득: +0.0, 스킬 없는 경우 대비 한 문장 프롬프트의 이득: +0.0). 한 문장 프롬프트는 실행당 178k 토큰을 쓰므로, 스킬은 한 문장 프롬프트의 0.82배 비용입니다.

실제로 있었던 일

  • 프롬프트가 이미 테스트 우선을 요구했기 때문에 대조군도 그렇게 했습니다. 두 구현 작업에서는 두 군의 모든 실행이 '구현 전에 테스트 작성'을 포함해 모든 검사를 통과했습니다. 스킬은 거기서 측정 가능한 것을 더하지 않았습니다.
  • 버그 수정 작업(장바구니 반올림)에서는 스킬 유무와 관계없이 네 번의 실행 모두 버그를 고치고 숨은 테스트를 통과했지만, 네 번 모두 같은 프로세스 검사에서 실패했습니다. 실패하는 테스트를 먼저 두는 대신 수정이나 테스트가 다른 하나와 같은 단계에 도착했습니다. 스킬은 그것을 바꾸지 못했습니다.
  • 스킬은 스킬 사용군 6/6 실행에서 읽혔습니다. 같은 결과를 위해 에이전트가 훨씬 더 많은 작업을 하게 만들었습니다(구현 작업에서 명령 24~26회 대 8~10회). 토큰은 약 1.7배입니다.
  • 숨은 테스트 정확도는 두 군 모두 100%였습니다.
  • 한 문장 버전(수직 슬라이스로 테스트 우선, 한 번에 실패하는 테스트 하나): 평균 점수 4.67로 대조군·스킬과 동일했고, 실행당 178k 토큰으로 대조군 86k(2.1배), 스킬 146k를 썼습니다. 한 문장 프롬프트 에이전트는 테스트 루프를 반복해서 실행해 평균 27개 명령을 실행한 반면, 대조군은 9개, 스킬은 23개였습니다.
  • 모든 군이 모든 실행에서 자체 테스트를 작성하고 숨은 테스트를 모두 통과했습니다. 구현 전 테스트는 세 군 모두 6회 중 4회에서 충족되었으므로, 프롬프트 수준의 '테스트 우선' 요청이 이미 스킬의 목적을 달성했습니다.

항목별 점수

항목점수이유
1_output_quality4.67

스킬 사용 시 평균 4.67/5점(프로그램 검사, 작업별 표 참조).

2_lift_vs_no_skill2.0

스킬 없이 4.67점 대비 +0.00점(작업당 n=2, 약 1점 미만의 차이는 노이즈).

3_trigger5.0스킬 사용군 6/6 실행에서 스킬 파일이 읽힘.
4_instructions_portability4
5_efficiency2토큰 1.70배(실행당 146k 대 86k), 시간 1.34배(67초 대 50초).
6_safety_hygiene5

이 테스트의 한계

  • 각 테스트 프롬프트 자체가 TDD를 요구해 대조군에 이득의 대부분을 주었습니다. 요청하지 않는 사용자라면 스킬 설명이 아예 트리거되지 않을 것입니다.
  • 작은 Python 작업만 사용했습니다. 테스트 품질은 채점하지 않았습니다.
  • 작업·군당 n = 2: 약 1점 미만의 차이는 노이즈입니다.
  • 규칙 기반 채점은 검사가 볼 수 있는 것만 측정합니다. 취향이나 결과가 최선인지는 판단할 수 없습니다.

보안

security.md를 참조하세요. 스캔: CRITICAL 0 / HIGH 0 / MEDIUM 0. 판정: 실행해도 안전(네트워크 비활성 샌드박스). 깨끗한 스캔 결과가 스킬의 안전성을 증명하지는 않습니다.

결론

테스트 우선 요청 위에서는 이 스킬이 작은 작업에서 추가 이득을 내지 못합니다. 대조군, 한 문장 버전, 스킬이 모두 4.67점이었고, 스킬은 대조군의 1.7배, 한 문장은 2.1배 토큰을 썼습니다. 더 긴 세션에서 테스트를 동작 중심으로 유지하는 데는 도움이 될 수 있지만, 그 부분은 측정하지 않았습니다.

트랜스크립트

실행 로그: tdd (Codex CLI, network off, per-run temp HOME/TMPDIR, one row per graded run.)
열: 작업, 그룹-회차, 점수(0-5), 토큰, 초, 통과한 검사, 에이전트가 연 스킬 파일.

t1-slugify control-1: 점수 5.0, 토큰 78904, 초 50.3, 검사 3/3, 연 파일 없음
t1-slugify control-2: 점수 5.0, 토큰 79205, 초 47.1, 검사 3/3, 연 파일 없음
t1-slugify oneliner-1: 점수 5.0, 토큰 199600, 초 74.7, 검사 3/3, 연 파일 없음
t1-slugify oneliner-2: 점수 5.0, 토큰 168650, 초 68.2, 검사 3/3, 연 파일 없음
t1-slugify treatment-1: 점수 5.0, 토큰 144538, 초 57.6, 검사 3/3, 연 파일 tdd
t1-slugify treatment-2: 점수 5.0, 토큰 126047, 초 50.7, 검사 3/3, 연 파일 tdd
t2-ratelimiter control-1: 점수 5.0, 토큰 99439, 초 60.2, 검사 3/3, 연 파일 없음
t2-ratelimiter control-2: 점수 5.0, 토큰 99611, 초 54.3, 검사 3/3, 연 파일 없음
t2-ratelimiter oneliner-1: 점수 5.0, 토큰 159969, 초 70.9, 검사 3/3, 연 파일 없음

18회 실행, 아티팩트 3개

샘플 출력

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()

Pro 보기