gated-tdd
Skill0 starsChanged 30 days agoMITView on GitHub
작은 작업 단위 TDD로 단위마다 커밋하고, 사용자는 AI가 대신 정할 수 없는 결정과 직접 해볼 수 있는 기능 묶음만 판정하는 개발 절차. 나머지는 기록과 알림을 남기고 자동으로 진행하며, main 병합은 사용자가 PR로 고른다. 기능마다 요구(인수 기준이 되는 시나리오)를 먼저 합의하고, 끝난 기능의 동작은 영역별 동작 명세에 쌓는다. 제품이 없으면 제품 명세와 골격부터 만든다. 사용자가 게이트 TDD 적용을 요청하거나 저장소 규칙이 이 방법론을 채택한 경우에 사용한다. 일반적인 기능 요청이나 AGENTS.md·상태 파일 같은 파일의 존재만으로 적용하지 않는다.
- Commits and pushes
In this repository10 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- archifySkill
- capture-compareSkill
- find-skillsSkill
- eli5Skill
- grill-me-plusSkill
- idea-bankingSkill
- jasoseo-coachSkill
- thinking-aloud-writingSkill
The file
Files
게이트 TDD 개발 절차
작은 단위를 테스트 먼저 만들고 단위마다 커밋한다. 사용자는 두 가지만 판정한다. AI가 대신 정할 수 없는 결정, 그리고 직접 해볼 수 있는 기능 묶음의 확인이다. 나머지는 기록과 알림을 남기고 묻지 않고 진행한다. main 병합은 사용자가 PR로 고른다. 사용자 대상 문서와 응답은 사용자의 언어로 쓴다. 보고는 4절의 두괄식·개조식 규칙을 따른다.
0. 세션 시작
- 명령은 모두 저장소 맨 위(
git rev-parse --show-toplevel)에서 실행한다. 세션이 하위 폴더(monorepo의 패키지 등)에서 열렸어도 스크립트와AGENTS.md는 맨 위에서 찾는다. 원격이 있으면git fetch --prune부터 한다. 다른 PC의 작업과 병합되어 지워진 브랜치가 반영된다. 그다음 배치를 본다.scripts/manual-review.mjs(gated-tdd/폴더 없이)가 있으면 1.9.0 전에 도입한 저장소다. 다른 작업 전에references/approval-gate.md의 "예전 배치에서 옮기기"부터 한다.scripts/gated-tdd/가 없으면 장치가 없는 저장소다. 6번에서 작업 유형을 고른 뒤 "1. 도입"부터 한다.- 그 밖에는
node scripts/gated-tdd/status.mjs를 실행하고 그 출력만 본다. 이 브랜치의 상태 파일 전체, 다른 브랜치의 대기 항목, 미뤄 둔 작업이 한 번에 나온다.
node scripts/gated-tdd/budget.mjs start로 세션 시작을 기록한다. 스크립트가 아직 없으면 도입에서 복사한 직후에 한다.node scripts/gated-tdd/manual-review.mjs hooks로 훅 네 개가 게이트를 실제로 부르고, 막으면 git까지 막히는지 확인한다.연결됨이 아닌 훅이 있으면 먼저 원인을 본다.core.hooksPath에.githooks가 아닌 값이 있거나 훅 도구 설정 파일(.husky/등)이 있으면, 도입 뒤에 다른 훅 도구가 들어온 것이다. "새로 clone하면" 줄로 자리를 되찾지 않는다. 되찾으면 그 도구의 lint가 꺼지고 다음 설치 때 다시 뒤집힌다.references/approval-gate.md의 "훅 자리"대로 이어 붙이는 안을 결정 보고(판정 ID도입-갱신)로 올린다.- 아니면(새로 clone한 저장소 등)
AGENTS.md의 "새로 clone하면" 줄대로 켜고 알린다. 그래도 안 되면 멈춰 알린다. scripts/gated-tdd/와.githooks/의 파일이 이 스킬의assets/와 다르면(줄 끝 차이는 무시) 옛 버전이다. 첫 보고에 한 줄로 알리고 진행 중인 작업은 막지 않는다. 갱신은 사용자가 고르면 따로 한다(references/approval-gate.md의 "스크립트를 새 버전으로 바꾸기")..gated-tdd.json에decide·tests를 직접 적었으면 그 목록에 빠진 새 기본값(lock 파일 등)도 같은 줄에 알린다. 갱신 전까지 빠진 항목은 에이전트가 보호 대상처럼 다룬다.
- 이 브랜치 상태 파일의 "판정 대기"·"확인 대기"를 실제 사용자 판정 기록·커밋과 대조한다. 판정이 확인되면
문서 갱신 지연으로 보고 다시 묻지 않는다. 확인되지 않은 확인 대기가 있으면 그 확인부터 요청하고,
확인 전에는 다음 묶음으로 넘어가지 않는다. 현재 작업의 검토·수정 요청은 먼저 수행한다.
다른 브랜치의 대기 항목과 미뤄 둔 작업은 첫 보고에 한 줄씩 적는다. 다른 브랜치의 확인 대기는 이 브랜치 작업을 막지 않는다.
"원격 브랜치가 지워짐"으로 나온 브랜치는 PR이 병합됐는지 확인한다(GitHub의 squash 병합은 main의 조상이 되지 않아 스크립트가 알 수 없다).
병합이 확인되면 그 로컬 브랜치를 지우고(
git branch -D <브랜치>) 알린다. 확인할 수 없거나 병합 없이 닫혔으면 지우지 않고 첫 보고에서 묻는다. - 과거 경위가 필요하면
docs/log/INDEX.md에서 한 줄을 고르고 그 항목 파일 하나만 연다. - 코드 탐색은 도구와 인덱스가 있으면 Graft를 먼저 쓴다(
graft ask "작업" --source,graft grep "식별자",graft callers 식별자 --depth all). 큰 변경 후graft build. 작업 유형을 고른다. 고른 유형과 근거는 첫 보고의 "내가 이해한 전제"에 쓴다. 신호가 겹쳐 모호하면 판정 질문 ①로 보고 사용자에게 묻는다.
유형 신호 시작 초기 개발 제품이 아직 없음 (빈 저장소, 또는 실행해 볼 제품이 없음) references/init-dev.md: 제품 명세 → 골격 → 기능 개발기능 개발 제품이 있고, 기능을 더하거나 사용자가 보는 동작을 바꿈 2절: 요구 → 계획 → 3절 사이클 작은 수정 제품이 있고, 요청이 분명하며(판정 질문 ① 아님, 버그면 원인도 분명함) 커밋 하나로 끝나고 판정 질문 ②③·보호 대상에 걸리지 않음. 화면이 바뀌어 기능 개발 신호와 겹쳐도 이 조건이 맞으면 작은 수정 references/maintenance.md: 요구·계획 없이 한 커밋. 커지면 버그 수정이나 기능 개발로 올림버그 수정 제품이 있고, 맞는 동작의 근거(동작 명세, 문서, 누구나 틀렸다고 보는 결과)가 있는데 지금 동작이 다름. 원인이 분명하지 않거나 작은 수정의 조건에 맞지 않음 references/maintenance.md의 "버그 수정": 재현 → 원인 → 영향도 → 대책, 버그 보고 한 번. 요구·계획 파일 없음리팩터링 사용자가 보는 동작은 그대로 두고 구조를 바꿈 (작은 수정이 아님) references/refactoring.md: 요구를 생략하고 2절의 계획부터. 대상이 없으면 후보를 보여 주고 고르게 함의존성 업데이트 제품이 쓰는 패키지의 버전을 올림 (기능 계획 안에서 더하는 패키지는 그 계획의 행) references/dependencies.md: 요구를 생략함. 패키지 하나면 결정 보고 한 번, 둘 이상이거나 코드를 고쳐야 하면 계획부터
1. 도입 (장치가 없는 저장소)
사용자가 도입이나 게이트 TDD 적용을 요청했으면 아래 파일 준비는 다시 묻지 않는다. 도입 커밋은 게이트 파일이
보호 대상이라 판정이 필요하므로, .gated-tdd.json 확정과 함께 결정 보고 한 번(판정 ID 도입)으로 받는다.
기존 규칙·훅은 보존하고 통합한다. 도입은 chore/gated-tdd 브랜치에서 한다. 초기 개발이면 references/init-dev.md의 순서를 따른다.
도입이 통과해 커밋하면 기능 작업을 기다리지 않고 바로 push하고 PR을 열어, 사용자가 병합을 고르게 한다(원격이 없으면 직접 병합을 고르게 한다).
도입은 작고 기능과 무관해서, 먼저 main에 들어가야 이후 기능 브랜치가 main에서 시작한다.
AGENTS.md: 절차를 옮겨 적지 않는다. 채택 선언과 이 저장소의 값만 둔다. 이 선언이 있어야 다음 세션의 에이전트가 스킬을 불러오고, 스킬과 함께references/도 따라온다.
다른 훅 도구에 이어 붙였으면 "새로 clone하면" 줄의## 개발 절차 이 저장소는 gated-tdd 절차를 채택했다. 코드를 바꾸는 작업(작은 수정 포함) 전에 Skill 도구로 `gated-tdd`를 불러 따른다. - 테스트: `<명령>` / 빌드: `<명령>` - 보호 대상: `.gated-tdd.json` - 상태와 문서: `docs/status/<브랜치>.md`(세션 시작에 `node scripts/gated-tdd/status.mjs`), `docs/` - 새로 clone하면: `git config core.hooksPath .githooks && git config merge.ff false && git config pull.ff only` (clone마다 켜야 한다) - main 반영: `git fetch` 후 `git merge origin/main`. rebase·cherry-pick·revert는 게이트 훅을 거치지 않아 쓰지 않는다. - 다른 스킬과의 순서: 계획·요구·TDD 절차는 gated-tdd가 맡는다. 다른 계획·명세 스킬의 문서(`docs/plans/`, `specs/` 등)는 만들지 않고, main에는 PR로만 병합한다.core.hooksPath부분을 그 도구를 켜는 명령(예:npm install)으로 바꾼다. 마지막 두 줄은 다른 도구·스킬이 같은 저장소에서 다른 방법을 권할 때 어느 쪽을 따를지 정하는 선언이라, 절차를 옮겨 적는 것으로 보지 않는다.CLAUDE.md: 첫 줄 "세션을 시작하면 저장소 맨 위에서node scripts/gated-tdd/status.mjs부터 실행한다.", 둘째 줄@AGENTS.md.AGENTS.md와CLAUDE.md는 저장소 맨 위에 둔다.- 상태 파일
docs/status/<브랜치>.md(브랜치 이름의/는-): 브랜치마다 따로 두어 브랜치를 동시에 진행해도 병합 때 부딪히지 않는다. 다른 브랜치의 상태 파일은 고치지 않는다. 내용은최종 갱신: YYYY-MM-DD, 지금(마지막 커밋· 판정 대기·확인 대기·다음 할 일), 자동 진행 내역(마지막 정지 보고 이후), 최근 3건(최신이 위), 미뤄 둔 작업. "지금"의- 판정 대기:·- 확인 대기:·- 다음 할 일:줄은status.mjs가 읽으므로 이름을 바꾸지 않는다. 브랜치의 첫 기록 때log-new.mjs가 틀을 만든다.- 정지 보고 전에 상태 파일만 커밋하고 push한다(
chore: <브랜치> 상태).status.mjs는 다른 브랜치와 다른 PC의 상태를 커밋된 것으로만 읽는다. 결정 문서와 로그는 그대로 판정 뒤에 커밋한다(5절). 병합을 멈춘 채 하는MERGE-main보고만 예외다. 병합 중에는 상태 파일만 따로 커밋할 수 없으므로 써 두기만 하고, 통과하면 병합 커밋에 함께 넣는다. - 브랜치 이름을 바꾸면(
git branch -m) 상태 파일 이름과 첫 줄도 새 이름으로 바꾼다. 안 바꾸면 다음 세션이 상태 파일을 찾지 못한다.
- 정지 보고 전에 상태 파일만 커밋하고 push한다(
docs/spec/제품 명세·기능 요구·버그 문서 ·docs/behavior/영역별 동작 명세 ·docs/plan/계획 ·docs/decision/결정 근거 ·docs/log/작업 이력(항목당 1파일, 이름은 날짜·작업·ID) ·docs/status/브랜치별 상태 ·docs/guide/운영법 ·docs/archive/끝난 단계. 폴더는 첫 파일을 쓸 때 만든다.log-new.mjs는docs/log/INDEX.md(아래 표 머리와| --- |구분선)가 있어야 돌아가므로, 도입의 첫 기록 전에 먼저 쓴다.docs/log/INDEX.md는 표| 항목 | 날짜 | 결론 | 상태 | 파일 |, 최신이 위.- 저장소에 이미 결정·명세·안내 문서 폴더(
docs/adr/,docs/decisions/등)가 있으면 비슷한 폴더를 새로 만들지 않고 그 폴더를 쓴다. 대응은AGENTS.md의 "상태와 문서" 줄에 적고(예: 결정 근거 →docs/adr/), 이 스킬이 가리키는 폴더는 그 대응으로 읽는다.docs/log/와docs/status/는 스크립트가 쓰므로 바꾸지 않는다.
- 저장소에 이미 결정·명세·안내 문서 폴더(
.gitattributes에 두 줄을 더한다.docs/log/INDEX.md merge=union은 두 브랜치가 같은 자리에 넣은 INDEX 줄을 병합 때 둘 다 남기고,.githooks/* text eol=lf는 Windows에서 훅 파일이 CRLF로 풀려 깨지는 것을 막는다.- 스크립트와 훅: 이 스킬의
assets/에서 복사하고references/approval-gate.md대로 설치·검증한다. Node.js 18 이상이 필요하다. 이미 다른 도구(husky 등)가 git 훅 자리를 쓰고 있으면 그 자리를 빼앗지 않고 이어 붙인다(같은 파일의 "훅 자리"). 포맷터·린터·타입 검사가 있으면 도입 브랜치에서 돌려 보고, 복사한 파일이 걸리면 그 도구의 제외 목록에 넣는다(같은 파일의 설치 5단계). .gated-tdd.json: 보호 경로·테스트 경로·보호 브랜치·예산 임계치를 이 저장소에 맞춰 제안하고 사용자가 확정한다. 초기 개발이면 기본값 내용(references/approval-gate.md의 예시)으로 만들고 골격 계획에서 맞춘다.- 테스트 도구는 고의 실패 시 0이 아닌 코드로 끝나는지 확인한다. 테스트 도구가 아직 없으면(초기 개발) 골격에서 한다.
제품은 있는데 테스트 도구가 없으면 도입에서 함께 들인다. 이후 모든 작업이 실패 테스트에서 시작하기 때문이다. 그 스택에서 흔히 쓰는 도구 하나를 골라
설치와 예시 테스트 하나를 도입 결정 보고에 넣는다(의존성 추가, 판정 질문 ③). 예시 테스트는 이미 있는 코드 하나의 고정 테스트(
references/characterization.md)로 쓰고, 테스트 명령을AGENTS.md에 적는다. 후보가 둘 이상이고 고르는 기준이 사용자 사정(팀이 익숙한 도구 등)에 달리면 같은 보고에서 묻는다.- 예시 테스트는 제품 코드를 고치지 않고 바로 부를 수 있는 작은 함수에 둔다. 도입 PR에 틈 만들기 같은 제품 코드 변경을 섞지 않는다. 도입이 통과하면 도입 커밋에 함께 넣는다. 실제로 고칠 코드의 고정은 그 작업의 브랜치에서 한다.
- 테스트를 돌리는 CI가 없으면 아래 "배포되는 코드" 규칙을 지킬 방법을 같은 보고에서 정한다. 무료로 쓸 수 있는 CI(공개 저장소의 GitHub Actions 등)가 있으면 워크플로 추가를 제안하고, 아니면 PR 보고에 로컬 테스트 결과를 붙이고 사용자가 그것을 보고 병합하는 방식으로 한다.
- 배포되는 코드는 PR에서 테스트를 통과한 코드여야 한다. 방법은 기존 배포 방식에 맞추고 계획이나 도입 보고에 쓴다.
- 배포를 CI(GitHub Actions 등)가 하면 재사용 워크플로 하나를 PR과 배포가 같이 쓴다.
- 플랫폼이 main을 직접 가져가 배포하면(Vercel, Netlify 등) 배포 방식은 바꾸지 않는다. 개발 변경은 PR로만 main에 들어가므로, PR 보고에 CI 결과를 붙이고 사용자가 CI 통과를 보고 병합하는 것으로 보장한다.
- 비용이 드는 저장소 설정을 기본으로 권하지 않는다. GitHub 브랜치 보호처럼 요금제에 따라 유료인 설정은 무료로 쓸 수 있을 때
(공개 저장소 등)만 선택 사항으로 안내한다.
directPush와 함께 켜면 GitHub가 main 직접 push를 거절하므로, 사용자 본인을 우회 허용에 넣어야 한다는 점을 같이 쓴다. - 플랫폼이 PR마다 미리보기 주소를 만들면 확인 지점의 해볼 곳으로 쓴다.
- main으로 바로 올리던 경로가 있는지 본다(블로그 글처럼 개발 절차 밖의 콘텐츠). 있으면 도입 후 막히는 일을 도입 보고에
쓰고,
.gated-tdd.json의directPush로 예외를 둘지 같은 보고에서 묻는다(references/approval-gate.md). - Claude Code면 예산 어댑터 설치 안내(
references/approval-gate.md)를 도입 결정 보고에 한 번 넣는다.
2. 요구와 계획: 구현 전에 합의
작은 수정과 버그 수정(references/maintenance.md)은 이 절을 거치지 않는다. 버그 수정은 버그 문서의 대책이 계획을 대신한다. 동작을 보존하는 유지보수(리팩터링, 의존성)는 1번 요구를
건너뛰고 2번 계획부터 한다(리팩터링은 references/refactoring.md, 의존성은 references/dependencies.md). 패키지 하나만 올리는 업데이트는 계획 없이 결정 보고 한 번으로 한다. 기능 ID는 계획을 쓸 때 정하고, 끝의 정의는 "기존 테스트가 모두 그대로 통과"(계획에서 판정받은 테스트 수정만 예외)와 작업의 목적(예: 보안 패치 반영)으로 쓴다.
바꿀 코드에 그 결과를 지키는 테스트가 없으면 고정 테스트를 먼저 둔다(3절 Red).
- 요구:
references/requirements.md대로 기능 요구docs/spec/<기능 ID>.md를 쓰고, 요구 보고 (판정 IDSPEC-<기능 ID>)를 한 뒤 멈춘다. 제품 명세가 있으면 기능 지도에서 그 기능의 자리를 확인하고, 범위나 기능 지도가 바뀌면 같은 보고에 넣는다(판정 질문 ②). - 계획: 요구가 통과하면
docs/plan/<기능 ID>-개발계획.md를 쓰고, 게이트·확인 지점·결정 목록을 계획 보고 한 번(판정 IDPLAN-<기능 ID>)으로 확정받은 뒤 사이클을 시작한다.
계획에 담는 것:
- 끝의 정의와 제외 범위: 기능 요구의 시나리오와 "하지 않을 것"에서 가져온다. 합의한 핵심을 빼고 완료로 치지 않는다.
- 작업 표:
| ID | 작업 | 선행 | 먼저 작성할 실패 테스트 / 완료 기준 | 게이트 | 보호 대상 변경 |. 실패 테스트는 기능 요구의 시나리오에서 나온다. 한 행은 혼자서 통과/실패를 판단할 수 있는 크기. ID는 영역 알파벳 + 번호(A01, B02 …). 고칠 코드에 테스트가 없으면 그 행의 작업 칸에 고정할 경로를 적는다(references/characterization.md). 게이트: 행마다 AI가 제안하고 사용자가 확정한다.
판정 질문 예이면 ① 선택: 합리적인 안이 둘 이상이고 정답이 사용자의 의도·우선순위·제약에 달렸나? 결정 ② 합의 변경: 계획·스펙·테스트 기대값·범위를 바꾸거나 모호한 요구를 해석하나? 결정 ③ 되돌리기 어려움: 스키마·데이터 삭제, 공개 API 계약, 인증·권한, 개인정보, 비밀값, 비용, 배포, 의존성 추가·업데이트? 결정 ④ 사람만 확인 가능: 화면·문구·사용감, 실제 계정·기기·외부 연동? 확인 지점에 묶음 전부 아니오, 완료 기준을 자동 검사로 증명 자동 결정 목록과 보호 대상 변경 칸에서 미리 판정받아 ①②③이 모두 풀리는 행은 자동으로 제안한다. 사용자가 실제 내용을 직접 보고 싶은 행은 결정으로 확정하면 된다.
- 결정 목록: 계획에서 미리 정할 수 있는 결정을 모아 한 번에 받는다. 지식·기능·보안·비용 네 갈래를 훑어
결정이 숨은 곳을 찾는다. Skill 도구에
grill-me-plus가 있으면 호출해 결정을 캐묻는다. 이때 결정은 그 스킬의DECISIONS.md가 아니라 이 계획의 결정 목록과docs/decision/에 적고, 미룬 결정은 결정 목록에미정으로 남긴다. 그 스킬이 말하는 "spike"는 조사 과제라는 뜻이라, 7절의 spike(동의를 받는 버리는 실험)와 섞지 않는다. - 보호 대상 변경: 그 행이 건드릴 보호 대상(
references/approval-gate.md의 "무엇을 막나")을 무엇을 어떻게 바꾸는지까지 적고, 근거(결정 목록 항목, 기능 요구의 바뀌는 동작)를 괄호로 단다. 예:package.json에pg추가 (D1, 그 설치가 만든 lock 파일 변경 포함), 기존 테스트 "댓글 버튼이 보인다"의 기대값을 "안 보인다"로 (요구의 바뀌는 동작). 계획이 통과하면 이 칸까지 판정받은 것이다. 리팩터링과 의존성 업데이트로 생기는 테스트의 기계적 수정(import 경로, 이름 변경 등 기대값·단언을 건드리지 않는 것)만은 개별 변경 대신 종류로 적는다(references/refactoring.md,references/dependencies.md). 패키지를 더하거나 올릴 때 목표 버전은 공개된 지 7일이 지난 것에서 고른다(references/dependencies.md). 보호 대상을 건드리지 않는 행은 비운다. - 확인 지점:
| 확인 지점 | 포함 행 | 해볼 흐름 | 결과 |표로 둔다.- 사용자 흐름 하나를 처음부터 끝까지 직접 해볼 수 있게 된 행에 둔다. 해볼 것이 없으면 두지 않는다.
- 뒤의 여러 행이 기대는 토대가 해볼 수 있는 상태가 되면 그 직후로 앞당긴다.
- 모호하거나 처음 다루는 영역은 짧게, 스펙이 분명하면 길게 잡는다. 계획은 기능 하나를 데이터부터 화면까지 관통하는 수직 슬라이스 순서로 짠다.
- 테스트 계층: 단위 / 통합(격리 fixture + 실제 빌드) / 브라우저(최종은 빌드 산출물 preview) / 실제 연동 / 배포 인수.
- 위험한 외부 연동은 앞쪽에 최소 실험으로 둔다. 실패하면 원인을 분류하고 대안을 먼저 제시한다.
3. 사이클
- Red: 기대 동작을 테스트로 먼저 쓰고 실패를 확인한다. 설치 실패·서버 미실행은 Red가 아니다.
사례가 여럿이면 한 사례씩. 설정 조사·외부 연결·문서 작업은 완료 기준으로 판정한다.
고칠 코드에 이번 변경이 닿는 결과를 지키는 테스트가 없으면, Red 전에
references/characterization.md대로 지금 결과를 고정 테스트로 붙잡아 따로 커밋한다. 테스트에서 부를 수 없는 코드면 같은 파일의 "틈 만들기"만 테스트보다 먼저 올 수 있다. 내부 호출 순서가 아니라 사용자가 보는 결과와 데이터 계약을 검증한다. - Green: 통과시키는 최소 구현. 기존 테스트의 기대값을 고치거나 지우거나 skip해야 하면 판정 질문 ②다.
- Refactor: 정리 후 해당 테스트와 영향받는 회귀 테스트를 다시 돌린다.
- 자동 검사: 변경 영향과 저장소 필수 게이트에 맞춰 수행한다. 요약 리포터로, 실패했을 때만 상세를 본다.
- 등급 재확인: 계획에 없던 ①②③이 생겼으면 결정으로 올린다. 실행 중에는 올리기만 한다(래칫). 내리거나 확인 지점을 미루려면 사용자 허락이 필요하다.
- 기록:
node scripts/gated-tdd/log-new.mjs "<ID>: <제목>" --gate 결정|확인|자동, 사유와 근거 테스트를 채운다. INDEX 결론 한 줄에는 "무엇이 문제였고 어떻게 정했는지"를 쓴다. 상태 파일의 "지금"·"최근 3건"을 갱신한다. 보호 대상 변경 칸이 있는 행은 사유에계획 판정: <근거>를 이때 쓴다. - 스테이징: 이 작업의 파일만
git add한다. 보호 대상 변경 칸이 있는 행은node scripts/gated-tdd/manual-review.mjs guarded로 걸리는 목록을 미리 본다. - 등급별 마무리
- 자동: 커밋하고, 진행 중에는 한 줄만 남기고 다음 단위로 간다.
- 확인 지점: 커밋하고 확인 보고 후 멈춘다. 확인 전에는 다음 묶음으로 넘어가지 않는다.
- 결정: 결정 보고 후 멈춘다. 판정 전에는 이 결정 위에 쌓지 않는다.
- 보호 대상 변경이 있으면(
guarded목록, 또는pre-commit이 막음) 그 행의 보호 대상 변경 칸과 스테이징된 변경을 대조한다. 칸 범위 안이면 계획 판정으로approve --for <행 ID>→ 커밋한다. 승인은 그 순간 스테이징된 파일 묶음에 붙으므로, 로그를 포함한 모든 파일을 먼저 쓰고 스테이징한 뒤 approve하고, approve와 커밋 사이에는 아무 파일도 고치지 않는다. 칸에 없거나 범위를 넘으면(적지 않은 패키지·테이블·열·테스트) 결정으로 올리고 결정 보고를 한다. 애매하면 넘은 것으로 본다. 칸이 종류로 적혀 있으면(테스트의 기계적 수정) 스테이징한 테스트 파일의 바뀐 줄을 더한 줄까지 하나씩 그 종류와 대조한다(references/refactoring.md의 "실행" 4단계).
- 예산: 커밋 출력에
[예산]줄이 있으면 6절대로 한다.
4. 보고
보고의 목적은 사용자가 방향을 판단하고 결정할 재료를 갖게 하는 것이다. 형식 상세, 예시, 보내기 전 점검은
references/report-format.md에 있다. 정지 보고를 쓰기 전에 그 파일을 연다.
- 읽는 사람: 마지막 정지 보고 이후의 대화를 보지 않은 사용자. 도구 결과·파일 내용으로만 알게 된 사실은 사용자가 모른다고 보고, 판정에 쓰이면 보고에 적는다. 보고 밖을 가리키는 말("그 문제", "기존 방식")을 쓰지 않는다.
- 두괄식: 첫 블록 "결론"만 잘라 읽어도 끝난 일, 필요한 판정, 판정에 영향을 주는 전제를 안다. 1~3개 bullet로 쓰고, 한 줄로 억지로 줄이지 않는다.
- 개조식 (한국어): 한 줄에 한 사실. 끝은 명사형(~함, ~됨, ~음, ~필요, ~예정, ~추정)으로 맺고 "~합니다", "~입니다", "~다"로 끝내지 않는다. 어미만 바꾸고 주어·대상·수치·조건·시제는 지우지 않는다. 판정 요청, 질문, 코드·명령·인용은 예외. 적용 범위: 보고, 진행 중 알림, 상태 파일, 로그. 운영가이드와 최종 보고서 본문은 평서문으로 쓴다.
- 우선순위: 판단 재료 > 짧음 > 중복 금지. 중복 금지는 같은 문장의 반복을 막는 규칙이지, 판정에 필요한 사실을 빼는 규칙이 아니다.
- 판정이 아닌 질문(요구 대화, 원격 연결 등)으로 멈출 때도 상태 파일이 있으면 "다음 할 일"에
사용자 답 대기: <질문 요약>을 쓴다. 세션이 끊겨도 다음 세션이 그 질문부터 이어 간다. - 정지 보고 순서: 결론 → 자동 진행 내역(ID, 결론 한 줄, 자동 사유, 커밋) → 계획 대비 위치 → 내가 이해한 전제 → 판단 재료 또는 확인 방법 → 자동 검사 → 판정 후 → 판정 요청.
- 결정 보고: 내가 이해한 전제(항목마다 확인됨/추정)는 반드시 쓴다. 쟁점마다 지금 정하는 이유, 선택(추천과 확신도), 버린 대안과 이유, trade-off, 모르는 것, 잘못 정했을 때의 비용. 판정 요청: "'통과' 또는 '수정: [문제와 원하는 변경]'".
- 확인 보고: 해볼 흐름을 "조작 → 기대 결과"로, 이번 묶음에서 바뀐 구조를 짧게. 전제가 바뀌었으면 전제도 쓴다.
- 자동 검사는 돌린 검사마다 통과·실패, 돌리지 않은 범위와 이유.
- 사용자에게 자동 검사 실행이나
git diff확인을 시키지 않는다. 에이전트가 하고 결과만 보고한다.
5. 판정 후
- 결정 통과: 로그 항목 제목, INDEX 상태 칸, 상태 파일의 "판정 대기"를
통과(수정이 있었으면통과 (수정 N건))로 고친다. 그다음 이 결정의 파일만git add→node scripts/gated-tdd/manual-review.mjs approve --for <ID>→ 커밋 → 작업 브랜치 push. 버그 보고(BUG-)의 통과 커밋은 실패하는 재현 테스트를 담고 있어 첫 고침 커밋까지 push하지 않는다(references/maintenance.md). 결정은 보고 전에 커밋하지 않는다(상태 파일만 예외, 1절). 행이 없는 결정의 ID는 도입도입, 예전 배치 옮기기와 훅 자리 바꾸기와 스크립트 갱신도입-갱신, 제품 명세SPEC-product, 기능 요구SPEC-<기능 ID>, 계획PLAN-<기능 ID>, 버그 대책BUG-<버그 이름>, 재현 장치CAPTURE-<버그 이름>, 피해 막기CONTAIN-<버그 이름>(references/maintenance.md), 실행 중 고정 테스트에서 생긴 결정<행 ID>-의심·<행 ID>-틈과 버그 재현에 필요한 구조 결정BUG-<버그 이름>-틈(references/characterization.md), 리팩터링 중 목표 구조로 갈 수 없을 때<행 ID>-구조(references/refactoring.md), 패키지 하나의 의존성 업데이트DEP-<패키지>-<버전>(references/dependencies.md), main 병합에서 막힌 파일MERGE-main-<날짜>다. 계획 판정은 보호 대상 변경 칸의 근거가 되므로 다른 결정처럼 기록하고 커밋한다. 행이 없는 결정도 보고 전에 로그 항목과 상태 파일의 "판정 대기"를 쓰고, 통과하면 결정 문서와 함께 커밋한다. 판정·확인을 기다리는 항목이 여러 브랜치에 걸쳐 둘 이상인데 사용자가 ID 없이 "통과"라고 하면, 어느 항목인지 묻고 나서 기록한다. - 확인 통과: 로그 항목 제목, INDEX 상태 칸, 상태 파일의 "확인 대기"를
통과(또는통과 (수정 N건))로, 계획의 확인 지점결과를 갱신하고 커밋한 뒤 다음 묶음으로 간다. - 기능 마감: 기능의 마지막 확인 지점을 통과하면
references/requirements.md의 "동작 명세에 합치기"를 한다. - 수정: 고치고 → 자동 검사 → 같은 결정·확인 지점을 다시 보고한다. 결과에 수정 건수를 남긴다.
- main 병합: 그 범위의 인수 기준 + build·preview 검증 후 PR을 열고, 병합은 사용자가 고른다.
- main 반영: 작업 브랜치에 main의 새 내용이 필요하면
git fetch후git merge origin/main으로 받는다. 원격 main에 이미 들어간 보호 대상 변경은 다시 판정받지 않는다. 충돌을 풀며 고친 파일과 main이 바꾸지 않은 파일은 그대로 검사한다. rebase, cherry-pick, revert는 게이트 훅을 거치지 않으므로 쓰지 않는다. 로컬 main은git pull로만 갱신한다(fast-forward만 됨).- 양쪽이 모두 고친 보호 대상 파일(예: main은 devDependencies를, 이 브랜치는 dependencies를 바꾼
package.json)은 병합 결과가 어느 쪽과도 같지 않아 막힌다. 병합을 멈춘 상태 그대로(충돌 없는 병합이면 git이 "Not committing merge"로 멈춘다) 결정 보고 (판정 IDMERGE-main-<날짜>)를 한다. 파일마다 main 쪽 변경, 이 브랜치 쪽 변경, 합친 결과를 쓴다. 통과하면approve --for MERGE-main-<날짜>후git commit으로 병합을 끝낸다. lock 파일은 손으로 합치지 않고 main 쪽을 받은 뒤 이 브랜치의 설치를 다시 해서 만든다(references/dependencies.md의 "lock 파일이 양쪽에서 바뀐 병합"). directPush경로를 main에서 고칠 때는 먼저git pull한다. 그사이 원격 main이 앞서 push가 거절되면git pull --rebase로 원격 위에 다시 얹고 push한다. rebase를 쓰는 유일한 예외다. push 때 훅이 올리는 커밋 전체가directPush경로만 바꾸는지 다시 검사한다.
- 양쪽이 모두 고친 보호 대상 파일(예: main은 devDependencies를, 이 브랜치는 dependencies를 바꾼
- 금지:
--no-verify, 훅 비활성화, 승인 파일 조작, 원격 추적 브랜치(origin/main등)를 손으로 바꾸기, 사용자 대신 '통과' 작성, 판정 전 approve, main 직접 push(directPush경로만 바꾸는 push는 예외), 무응답·자동 테스트 성공·이전 판정을 새 결정이나 확인의 통과로 해석하기 (계획의 보호 대상 변경 칸 범위 안의 커밋만 예외). - push가 실패하면 로컬 커밋을 보존하고 원인을 기록한다. 성공 확인 전에 완료라고 쓰지 않는다.
6. 예산
판단은 단위 경계(커밋 직후)에서만 한다. 커밋 출력의 [예산] 줄이 판단 재료다.
작은 단위만 진행: 남은 행 중 작은 것만 하고, 큰 행은 다음 세션으로 넘긴다.정지: 상태 파일의 "지금"·"다음 할 일"·"확인 대기"를 인계용으로 갱신하고 커밋한 뒤 멈춘다. 새 세션을 권한다.- 끊는 것도 묻지 않고 알린다. 수치와 이유만 쓴다. 줄이 없으면 계속한다.
- 수치 공급(어댑터)과 임계치 설정은
references/approval-gate.md에 있다.
7. 판단 규칙
- 시각 결정은 코드를 고치기 전에 시안을 같은 조건에서 캡처해 고르게 한다. Skill 도구에
capture-compare가 있으면 호출하고 시안 개수는 그 스킬을 따른다. 없으면 "현재"를 포함한 3~4개를 직접 캡처한다. 비교 시트는 세션 임시 폴더에 만들고, 고른 뒤 그 시트 하나와 고른 이유를docs/decision/에 남긴다. 임시 폴더의 경로는 다음 세션에 사라지므로 기록에 쓰지 않는다. 캡처 도구를 새로 설치해야 하면 의존성 추가(판정 질문 ③)로 본다. 고른 안을 반영하는 작업도 사이클을 거친다. 사용자가 값을 정해 준 변경("버튼을 #2563eb로")은 고를 것이 없으므로 시안을 만들지 않는다. - **버리는 실험(spike)**은 사용자 동의를 받고
references/requirements.md의 spike 규칙대로 한다. spike 코드는 병합하지 않는다. - 작업 보류: 급한 일이 끼어들거나 커밋하지 않은 변경이 다음 판정을 막으면(작은 수정을 정식 절차로 올릴 때 등),
그 변경을 지우지 않고 미뤄 둔다. 아래 명령은 PowerShell에서도 그대로 돌도록
stash@{0}대신refs/stash를 쓴다.- 상태 파일은 빼고 이름을 붙여 치운다:
git stash push -u -m "gated-tdd 보류: <ID> <이유>" -- . ":(exclude)docs/status". 상태 파일까지 치우면 3번에서 고친 상태 파일과 부딪혀 나중에 꺼낼 수 없다. - 원격이 있으면
git stash show --include-untracked --name-only refs/stash로 담긴 파일을 본다. 비밀값이나 빌드 산출물처럼 원격에 올리면 안 되는 파일이 있으면 올리지 않고 보고에 쓴다. 없으면git push origin refs/stash:refs/heads/park/<브랜치>-<ID>로 올린다(브랜치 이름의/는-). stash는 이 PC에만 있어서다. - 상태 파일의 "미뤄 둔 작업"에 ID, 이유, 원래 브랜치, 날짜, stash 커밋(
git rev-parse refs/stash)을 적고 상태 파일만 커밋한다. - 다시 할 때는 원래 브랜치에서
git stash apply <stash 커밋>으로 꺼낸다. 꺼내면서 지우는stash pop과 전부 지우는stash clear는 쓰지 않는다. 치우거나 꺼낸 변경에 매니페스트나 lock 파일이 있으면, 그 뒤 lock 파일대로 다시 설치한다(npm ci,poetry install --sync등). 안 하면 설치된 패키지가 브랜치와 달라 테스트 결과가 어긋난다. - 꺼낸 작업이 커밋된 뒤에만 그 stash 하나와
park/브랜치를 지우고, 상태 파일의 그 줄을 지운다. stash는git stash list에서 번호를 찾아git stash drop 'stash@{n}'으로 지운다(PowerShell 때문에 따옴표를 붙인다). 세션 시작의status.mjs가 이 이름의 stash와park/브랜치를 지울 때까지 매번 보여 준다. 저장소 CI가 모든 브랜치 push에서 돌면park/브랜치도 빌드된다. 문제가 되면 워크플로에서park/**를 빼는 것을 결정으로 올린다(워크플로는 보호 대상이다).
- 상태 파일은 빼고 이름을 붙여 치운다:
- 추측하지 말고 잰다. 성능·원인은 측정으로 확인하고, 측정 결과로 문제를 다시 정의한다.
- 선택지가 있는 결정은
docs/decision/에 선택지·선택·근거·틀렸던 가정을 남긴다. - 운영 보호는 구조로. 테스트는 운영 데이터를 고정값으로 쓰지 않는다. 운영 쓰기는 명시적 opt-in일 때만.
- 실패는 숨기지 않는다. 비밀값 생성 같은 중요한 단계는 실패하면 즉시 멈춘다.
- 규칙이 바뀌면 테스트를 새 의도에 맞게 고치고 그 이유를 기록한다.
- 사용자에게 의미 있는 단위로 센다 (커밋 수가 아니라 바뀐 항목 수).
- 브랜치: 도입은
chore/gated-tdd, 예전 배치 옮기기와 스크립트 갱신은chore/gated-tdd-update, 기능은 요구부터feat/<기능 ID>, 작은 수정은fix/<짧은 이름>, 버그 수정은bugfix/<영역>-<증상>, 리팩터링은refactor/<이름>, 의존성 업데이트는deps/<이름>에서 한다. 버그 조사 중 받은 재현 장치와 피해 막기의 저장소 변경은chore/capture-<버그 이름>·chore/contain-<버그 이름>에서 따로 PR로 올린다.park/<브랜치>-<ID>는 보류한 작업의 보관용이라 병합하지 않는다. 제품 명세는 함께 보고하는 기능의 브랜치에 쓴다. 선행 기능(도입 포함)이 아직 main에 병합되지 않았으면 그 브랜치에서 분기하고 보고의 전제에 쓴다. 작업 브랜치 push ≠ 배포. 공개할 방법이 없는 반쪽 기능은 병합하지 않는다.
8. 마감
2절에서 합의한 산출물만 작성한다. 운영 기능 전체 개발이면 docs/guide/<기능>-운영가이드.md
(작업 흐름, 동작 원리, 시행착오와 선택, 한계, 설정 위치)와 최종 보고서(실제로 동작하는 것과 근거,
제약과 미해결 항목, 후속 과제 표)를 쓴다. 운영 배포까지 합의했다면 운영 사이트에서 흐름을 확인한 뒤 완료로 표시한다.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

