Skip to content
Back to skills

Refactor Plan

ASecurity

완료된 프로젝트(문서·플랜·하네스·LOOP.md 가 있고 루프가 도는 중이 아닌 상태)의 코드 품질을 올리는 리팩토링을 계획한다. 범위 셋(기저 언어·프레임워크 교체 / 라이브러리 최신화 / 코드 정리 — 중복 제거·안 쓰는 코드·너무 큰 파일·계층 어김) 중 무엇인지 먼저 묻고, 코드를 읽어 고칠 목록(문서와 어긋난 곳 포함)을 만들고, 스택·라이브러리가 바뀌면 docs/TRD.md 후미에, 구조가 바뀌면 docs/ARCHITECTURE/ 후미에 "## 리팩토링 N: <이름>" 절을 붙이고, plan-generator 를 부분 갱신 모드로 불러 plan_setup/ 에 phase-NN-refactor-<이름> 을 끝번호로 더한 뒤 harness-update·loop-update 를 부른다. 통과 조건은 새 수용 기준이 아니라 "기존 게이트 전부 통과(행위 보존)" + 구조 조건이다. 사용자가 "리팩토링하자", "코드 정리 좀 하자", "중복 없애줘", "파일이 너무 커서 나누...

  • 3 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 23, 2026
ai-agentstypescriptgoexpressgitapibackend

Works with

  • claude code
  • api

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned September 23, 2026

npx -y skills add GangJaeYu/harness_loop_full_korean --skill refactor-plan --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Refactor Plan?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Refactor Plan
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/gangjaeyu-refactor-plan/badge)](https://www.skillsdirectory.com/skills/gangjaeyu-refactor-plan)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: refactor-plan
description: 완료된 프로젝트(문서·플랜·하네스·LOOP.md 가 있고 루프가 도는 중이 아닌 상태)의 코드 품질을 올리는 리팩토링을 계획한다. 범위 셋(기저 언어·프레임워크 교체 / 라이브러리 최신화 / 코드 정리 — 중복 제거·안 쓰는 코드·너무 큰 파일·계층 어김) 중 무엇인지 먼저 묻고, 코드를 읽어 고칠 목록(문서와 어긋난 곳 포함)을 만들고, 스택·라이브러리가 바뀌면 docs/TRD.md 후미에, 구조가 바뀌면 docs/ARCHITECTURE/ 후미에 "## 리팩토링 N: <이름>" 절을 붙이고, plan-generator 를 부분 갱신 모드로 불러 plan_setup/ 에 phase-NN-refactor-<이름> 을 끝번호로 더한 뒤 harness-update·loop-update 를 부른다. 통과 조건은 새 수용 기준이 아니라 "기존 게이트 전부 통과(행위 보존)" + 구조 조건이다. 사용자가 "리팩토링하자", "코드 정리 좀 하자", "중복 없애줘", "파일이 너무 커서 나누고 싶어", "라이브러리 버전 올리자", "의존성 최신화해줘", "Express 를 Fastify 로 바꾸자", "TypeScript 로 옮기자", "계층 분리하자", "구조 좀 잡아줘"라고 하거나, 동작은 그대로 두고 코드의 모양·의존성·스택만 바꾸려 할 때 반드시 이 스킬을 사용한다. 코드를 바로 고치기 시작하지 말고 이 스킬로 먼저 목록과 phase 를 만든다. 요구가 바뀌는 것("로그인 제대로 만들자", "권한 넣자")은 feature-add, 안 되는 것을 고치는 것은 bug-fix, docs/PRD.md 가 없으면 code-to-docs 가 먼저다.
---

# 리팩토링 계획 (Layer 6 · 코드 품질)

## 이 스킬의 목적

프로젝트가 완료된 뒤 코드 품질을 올리는 일은 세 가지로 온다 — 기저 언어·프레임워크를 바꾸거나, 라이브러리를 최신으로 올리거나, 코드 자체를 정리하거나.
셋 다 **동작은 그대로 두고 모양을 바꾸는 일**이라 새 요구사항이 없다. 그래서 통과 조건도 새 수용 기준이 아니라 **"기존 게이트 전부 통과(행위 보존)"** 와
**구조 조건**(파일이 어디에 있는가, 무엇이 무엇을 import 하지 않는가)이다.

이 스킬은 코드를 고치지 않는다. **범위를 정하고, 고칠 목록을 만들고, 문서 후미에 절을 붙이고, phase 하나를 더한다.** 고치는 것은 개발 루프다.

```
범위를 묻는다  (교체 / 최신화 / 정리 — 손대는 문서가 다르다)
   → 코드를 읽어 고칠 목록 (문서와 어긋난 곳도 목록에)                       ← 이 스킬이 직접
   → docs/TRD.md 후미 "## 리팩토링 N"        (스택·라이브러리가 바뀔 때만)   ← trd-generator 후미 절 모드
   → docs/ARCHITECTURE/ 후미 "## 리팩토링 N"  (구조가 바뀔 때만)             ← architecture-generator 9단계
   → plan_setup/phase-NN-refactor-<이름>      (고칠 목록 = 태스크)           ← plan-generator 10단계
   → harness-update · loop-update                                          ← 게이트 명령·DAG
   → 개발 루프 실행                                                         ← 사용자
```

**왜 목록과 문서를 먼저 만드는가.** 이 플러그인의 모든 스킬은 문서를 읽고 움직인다. 코드를 먼저 고치면 문서가 낡고, 그다음 작업(기능 추가·플랜 갱신·다음 리팩토링)이
낡은 문서를 근거로 삼는다. 그래서 **리팩토링이 끝나면 문서와 코드가 맞아야 하고**, 문서와 어긋난 곳은 고칠 목록에 들어간다.
그리고 리팩토링은 "무엇이 깨졌는지" 를 게이트가 말해 줄 때만 안전하다 — 그래서 게이트가 활성인 프로젝트에만 들어간다(0단계).

### 여기서 하는 일과 하지 않는 일

| 하지 않는 것 | 어디서 하는가 |
|---|---|
| 코드를 고치는 것 — 목록에 적은 것도 | 개발 루프(`LOOP.md`)가 phase-NN 의 태스크로 고친다 |
| 요구를 바꾸는 것 — "로그인 제대로", "권한 넣자", "응답 형식 바꾸자" | `feature-add`. PRD 수용 기준이 바뀌면 리팩토링이 아니다 |
| 안 되는 것을 고치는 것 — "필터가 빈 배열 나와" | `bug-fix`. 게이트 결과가 바뀌면 리팩토링이 아니다 |
| TD·설계 단위·태스크의 형식과 절차를 정하는 것 | `trd-generator`·`architecture-generator`·`plan-generator`. 이 스킬은 **부를 때 넘길 지시**만 정한다 |
| 게이트 명령을 바꾸고 DAG 를 다시 그리는 것 | `harness-update`·`loop-update`. 끝에 부른다 |
| 문서 없는 코드에 리팩토링 목록을 만드는 것 | `code-to-docs` 가 먼저다 — 현행 고정 테스트 없이는 행위 보존을 판정할 수 없다 |

### 리팩토링과 기능·버그의 경계

경계가 흐리면 리팩토링 phase 에 요구 변경이 섞여 들어가고, 그러면 "기존 게이트 통과" 가 통과 조건으로 성립하지 않는다(바뀐 동작은 기존 테스트가 잡는다). 판정은 두 질문이다.

| 질문 | 예 | 아니오 |
|---|---|---|
| PRD 의 수용 기준 한 줄이라도 바뀌는가 | `feature-add` (요구가 바뀐다) | ↓ |
| 지금 활성인 게이트의 결과가 바뀌는가 (통과하던 테스트가 실패하게 되는가) | `bug-fix` (현행 고정 테스트가 잘못된 동작을 붙잡고 있다) 또는 `feature-add` | **리팩토링** |

"리팩토링하는 김에" 는 경계를 넘는 가장 흔한 말이다. 같은 파일을 만지더라도 요구가 바뀌는 부분은 떼어 `feature-add` 로 보낸다 — 두 phase 가 같은 파일을 건드려도 순서만 정하면 된다(뒤 phase 는 앞 phase 의 결과 위에서 잘린다).

---

## 0단계. 진입 조건

세 가지를 확인하고 하나라도 걸리면 멈춰 보고한다. 조용히 진행하지 않는다.

| 확인 | 걸렸을 때 |
|---|---|
| `docs/PRD.md`·`plan_setup/STATE.md`·`harness_setup/`·`loop_setup/LOOP.md` 가 있는가 | 없으면 `code-to-docs` 로 보낸다(문서 없는 코드). 일부만 없으면 무엇이 없는지 보고하고 사용자가 정한다 |
| `STATE.md` 의 `Phase Overview` 에 `in_progress` 인 phase 가 없는가 | 있으면 멈춘다 — "루프가 도는 중이다. phase 완료 뒤에 다시 부르라". 문서·STATE.md·LOG.md 의 필자는 루프의 코디네이터 하나여야 한다(Layer 5). `pending` phase 는 막지 않는다(feature-add 가 phase 를 더한 직후가 그렇다) |
| 게이트가 활성인가 — `harness_setup/HARNESS.md` 1절의 게이트 넷이 `활성`(또는 `부분 활성`) | 전부 `미활성` 이면 멈춘다 — "기존 게이트 통과" 가 뜻이 없다. `code-to-docs` 로 진입한 프로젝트는 **phase-01 baseline 이 `completed`** 여야 한다. 아니면 "루프를 한 번 돌려 phase-01 을 완료시키라" |

`부분 활성` 은 막지 않되, 어느 영역이 덮이지 않는지 2단계에서 목록의 "행위 보존 근거" 열에 드러난다.

**git 상태**를 본다. 미커밋 변경이 있으면 알린다 — 리팩토링 전 기준점 커밋이 있어야 "리팩토링 전과 같다" 를 비교할 수 있다. 사용자가 정하기 전에는 커밋하지 않는다.

---

## 1단계. 범위를 묻는다

범위가 손대는 문서를 정하므로 **코드를 읽기 전에** 정한다. 요청에 범위가 이미 명시되어 있으면 확인만 하고, 아니면 셋 중 무엇인지 묻는다(복수 가능).

| 범위 | 무엇을 바꾸나 | 손대는 문서 | 행위 보존의 기준 |
|---|---|---|---|
| **기저 언어·프레임워크 교체** | 런타임·언어·웹 프레임워크·ORM 같은 굵은 TD | TRD 후미 절(결정 대체) + ARCHITECTURE 후미 절(대개 구조도 바뀐다) | **블랙박스 e2e 만** — 옛 스택의 unit 은 새 스택에서 돌지 않는다(4단계) |
| **라이브러리 최신화** | 버전 올림, 대체 패키지, 폐기된 API 교체 | TRD 후미 절(고정 버전·결정 대체). ARCHITECTURE 는 3절 의존 방향 표가 그 라이브러리를 이름으로 적고 있을 때만 그 행을 대체하는 후미 절("구조 변화 없음" 명시) | 게이트 넷 전부 |
| **코드 정리** | 중복 제거, 안 쓰는 코드, 너무 큰 파일, 계층 어김, 이름·위치 정리 | 문서를 안 건드리거나 ARCHITECTURE 후미 절만(설계 단위가 갈라지거나 의존 방향이 생길 때) | 게이트 넷 전부 |

물을 때 함께 확인하는 것 — **요청에 요구 변경이 섞여 있는가.** "라이브러리 올리면서 로그인도 제대로" 처럼 오면 뒤쪽은 `feature-add` 로 떼어 낸다고 답하고 리팩토링 범위만 진행한다.
사용자가 "그래도 같이" 라고 하면 그 결정을 기록하되, 이 스킬은 리팩토링 phase 만 만들고 기능 부분은 `feature-add` 를 이어서 부르라고 안내한다 — 한 phase 에 섞으면 통과 조건이 둘이 된다.

범위 안에서 **크기**도 묻는다 — 전체인가, 특정 영역(예: 서버만)인가. 리팩토링 phase 가 phase-01 만큼 커지면 루프가 그만큼 돌아야 하고, 그동안 기능 추가는 막힌다(0단계 진입 조건).
사용자와 대화할 수 없는 환경이면 요청에서 읽히는 범위로 진행하고 물었을 질문과 가정을 기록으로 남긴다.

---

## 2단계. 코드를 읽어 고칠 목록을 만든다

문서(TRD·ARCHITECTURE)를 먼저 읽고 코드를 읽는다 — 문서가 "있어야 할 자리" 이고 코드가 "실제" 라, 둘을 대조해야 어긋난 곳이 보인다.
as-is 문서(`> 코드에서 역으로 작성`)면 문서가 곧 지금 코드이므로 어긋남은 대개 문서를 만든 뒤 바뀐 코드이거나 as-is 가 잘못 읽은 곳이다.

### 범위마다 보는 자리

| 범위 | 어디를 보나 | 무엇이 목록이 되나 |
|---|---|---|
| 교체 | TRD 의 그 TD 와 **되돌리기 비용** 항목, 그 TD 에 걸린 설계 단위 전부, 옛 스택에 묶인 테스트·설정·스크립트 | 새 스택 뼈대 → FR 묶음마다 이식 → unit 재구축 → 옛 코드 제거. 되돌리기 비용에 적힌 파일이 곧 대상이다 |
| 최신화 | `package.json`·잠금 파일·TRD 에 적힌 고정 버전, 각 라이브러리의 변경 로그(호환 깨짐 목록), 깊은 경로 import·폐기 API 호출부 | 라이브러리(또는 같이 올려야 하는 묶음)마다 하나. 호환 깨짐이 있으면 그 호출부가 같은 항목 |
| 정리 | 같은 이름·같은 본문의 함수, import 되지 않는 파일·export, 파일 크기·핸들러 수, ARCHITECTURE 3절 의존 방향을 어기는 import, 문서에 적힌 자리와 다른 파일, 문서에 없는 모듈 | 문제 하나 = 항목 하나. "파일 하나의 수정" 에 가깝게 자른다 |

### 항목 하나의 형식

목록의 한 항목이 그대로 태스크 하나가 된다. 그래서 여기서 관찰 가능하게 써 두면 plan-generator 가 옮겨 적기만 하면 된다.

```markdown
| # | 종류 | 위치 | 지금 | 목표 | 구조 조건(관찰 가능) | 영향 문서 | 행위 보존 근거 |
|---|---|---|---|---|---|---|---|
| 1 | 중복 | `routes/projects.js` 7~11행, `routes/tasks.js` 7~11행, `server.js` 29~30행 | `getUserId` 사본 둘 + 인라인 하나 | `lib/auth.js` 한 곳 | `getUserId` 정의가 `lib/auth.js` 에만 있다(grep 1건). 두 라우터와 `server.js` 가 그것을 import 한다 | ARCHITECTURE backend.md §3.5 (대체), overview 3절 의존 방향 | unit: `test/api/*.test.js` 의 401 케이스 전부, e2e: 로그인 흐름 |
| 2 | 문서 불일치 (문서 쪽) | `docs/TRD.md` TD-002 확정도 ↔ `package.json` | 문서는 `package.json` 10~11행이라 적었는데 phase-01 이 scripts 를 더해 16~17행이 됨 | 후미 절의 대체가 현재 값 | — (태스크 아님) | TRD `## 리팩토링 N` | — |
```

열마다 지킬 것이 있다.

- **종류** — `중복` / `미사용` / `큰 파일` / `계층 어김` / `문서 불일치` / `라이브러리` / `스택`. 뒤에서 태스크 순서와 손대는 문서를 이 열로 가른다
- **구조 조건** — 분리된 세션의 검증자가 파일 시스템과 grep 만으로 판정할 수 있게 쓴다. "깔끔하다", "응집도가 높다" 는 판정할 수 없다. "파일 X 가 경로 Y 에 있다", "모듈 A 에 `require('../db')` 가 없다", "파일 Z 가 200줄 이하다"
- **영향 문서** — 이 항목이 끝나면 어느 문서의 어느 절이 낡는가. TD 번호 또는 `파일명 §절번호`. 비어 있으면 문서를 안 건드리는 정리다
- **행위 보존 근거** — 이 코드의 지금 동작을 붙잡고 있는 **게이트와 테스트 파일**. **비어 있으면 그 항목은 아직 안전하지 않다** — 현행 고정 테스트를 먼저 쓰는 태스크를 phase 앞에 두거나(3단계에서 plan-generator 에 넘긴다), 사용자에게 "덮이지 않은 채 고칠지" 를 묻는다. 조용히 비워 두고 넘어가면 루프가 무엇을 깼는지 모른 채 통과시킨다

**문서와 어긋난 곳**은 둘로 가른다 — 코드가 문서를 어긴 것이면 코드를 문서에 맞추는 항목(구조 조건 = 문서의 그 절), 문서가 틀린 것(as-is 가 잘못 읽었거나 그 뒤 의도적으로 바뀐 코드)이면
문서를 고치는 항목이고 그것은 태스크가 아니라 3단계 후미 절의 "대체" 다. 어느 쪽인지 코드만으로 모르면 사용자에게 묻는다 — 문서에 맞춰 코드를 되돌리는 것은 동작이 바뀔 수 있다.

**목록에 넣지 않는 것** — 동작이 바뀌는 것(경계 표). 눈에 띄면 "문서에 일부러 넣지 않은 것" 으로 보고에 옮기고 `feature-add`·`bug-fix` 를 가리킨다.

### 목록을 사용자와 확인한다

목록이 곧 phase 의 크기다. 만들고 나서 **사용자에게 보여 주고 뺄 것·더할 것을 받는다.** 범위 판단은 사용자의 것이다 — 모델이 "이것도 정리하면 좋겠다" 로 목록을 늘리면 phase 가 커지고 그동안 기능 추가가 막힌다.
같은 이유로 **문제 하나를 여러 태스크로 쪼개지 않는다** — 태스크는 "검증 가능한 단위" 이고, 사본 둘을 합치는 것을 파일마다 쪼개면 중간 상태에서 게이트가 실패한다.

---

## 3단계. 문서 후미에 `## 리팩토링 N` 절을 붙인다

**어느 문서에 붙이는가는 범위가 정한다** — TRD 는 스택·라이브러리(TD)가 바뀔 때, ARCHITECTURE 는 구조(설계 단위·의존 방향)가 바뀔 때만. 코드 정리로 문서가 안 바뀌면 절을 붙이지 않는다.
**TD 의 결정("무엇을 쓰는가")이 그대로면 TRD 는 열지 않는다** — TD 본문의 되돌리기 비용·근거 파일·줄 번호 같은 위치 서술이 리팩토링 뒤 낡는 것은 TRD 를 열 이유가 아니다.
그 서술은 ARCHITECTURE 후미 절에 "(TD-003 의 되돌리기 비용은 이 절 이후 `lib/store.js` 한 파일)" 로 적고, 이미 낡아 있던 것(문서 쪽 불일치)은 보고에만 둔다. TRD 는 다음에 결정이 실제로 바뀌는 요청(라이브러리 최신화·feature-add)이 열 때 함께 정리된다.
코드 정리 요청마다 TRD 에 절을 붙이면 TRD 가 결정 문서가 아니라 변경 일지가 되고, 뒤 스킬이 어느 TD 가 실제로 바뀌었는지 절 수로 알 수 없게 된다.
붙일 때는 이 스킬이 직접 쓰지 않고 **그 문서의 스킬을 부분 갱신 모드로 부른다** — 형식·추적표·버전·`CLAUDE.md` 절은 그 스킬의 규칙이고, 이 스킬은 아래 지시만 넘긴다.

### N 과 절 형식

- **N 은 요청 단위의 공통 번호다.** 이 요청이 TRD 와 ARCHITECTURE 에 남기는 절은 전부 같은 N 이고, 절이 안 생기는 문서는 그 번호를 건너뛴다. 문서마다 따로 세면 TRD 의 "리팩토링 2" 와 overview 의 "리팩토링 3" 이 같은 요청이 되어 교차 참조가 흔들린다.
  N 은 `docs/` 전체에서 `## 리팩토링 (\d+)` 의 최댓값 + 1 이다. `## 추가 N`(feature-add)과는 **따로 센다** — "리팩토링 1" 이 첫 리팩토링이어야 phase 문서와 LOG 에서 읽힌다
- **절은 후미에 붙이고 기존 절 본문은 고치지 않는다.** 기존 TD·설계 단위가 바뀌는 것은 절 안에 "TD-002 를 다음으로 대체" 로 적는다 — **같은 문서 안에서는 뒤 절이 앞 절을 이긴다.**
  완료된 태스크가 가리키는 절이 그대로 남아야 통과 기록이 뜻을 가진다. 예외는 부른 스킬 자체의 규칙 — 표의 행 추가·값 갱신, 버전 줄, architecture-generator 9단계의 "폐기 — 대체: §3.y" 표시
- **절 첫 줄**에 날짜 · 요청 한 줄 · 이 절이 만든 ID 목록(새 TD·새 설계 단위 절·OQ)을 둔다. 뒤 스킬이 델타만 읽는 자리다

### TRD — `trd-generator` 후미 절 모드

```
trd-generator 호출 지시 (refactor-plan 에서)

- docs/TRD.md 가 이미 있다. 1~8단계를 다시 돌리지 말고 문서 후미에 `## 리팩토링 N: <이름>` 절 하나만 붙인다 (N = <값>)
- 절 첫 줄: 날짜 · 요청 한 줄 · 이 절이 만든 ID
- 바뀌는 결정은 "TD-00x 를 다음으로 대체" 로 적고 TD 여섯 항목(영역·근거 요구사항·결정·검토한 대안·확정도·되돌리기 비용·검증 방법)을 그대로 채운다.
  **대체는 번호를 유지한다** — TD-002 는 계속 TD-002 이고 뒤 절이 이긴다(새 번호를 주면 13절 추적표와 아키텍처 근거가 전부 옮겨 적어야 한다).
  새 번호는 추가 결정(대체가 아닌 것)에만, 기존 마지막 TD 번호 다음이다. 기존 TD 본문은 고치지 않는다
- 근거 요구사항은 기존 FR·NFR 그대로다 — 새 요구사항은 없다. 검증 방법은 "기존 게이트 통과" 와 확인 가능한 사실(버전 문자열, import 경로)
- 라이브러리 최신화: 고정 버전을 옛 값 → 새 값으로 적고, 호환 깨짐(깊은 경로 import·폐기 API)이 있으면 결정 본문에 호출부와 함께
- 언어·프레임워크 교체: 8절 테스트 TD 도 대체된다 — 새 스택의 러너·lint. 옛 unit 이 새 스택에서 돌지 않는다는 것과 "행위 보존 기준은 e2e" 를 결정 본문에 적는다
- 2절 요약 표에 행을 더하고(대체 행은 옛 행 옆에 "→ 리팩토링 N" 병기), 13절 추적표의 관련 결정 열을 갱신하고, 버전을 올린다(0.1 → 0.2). 새 OQ 는 마지막 번호 다음
- CLAUDE.md·AGENTS.md 의 `## 기술` 절은 평소대로 갱신하되 `현재 단계` 줄은 refactor-plan 이 끝에 다시 쓴다
```

### ARCHITECTURE — `architecture-generator` 9단계

```
architecture-generator 호출 지시 (refactor-plan 에서)

- docs/ARCHITECTURE/ 가 이미 있다. 9단계(부분 갱신)만 한다
- overview.md 와 바뀌는 영역 문서의 후미에 `## 리팩토링 N: <이름>` 절을 붙인다 (N = <값>). 첫 줄은 날짜 · 요청 한 줄 · 새 절 번호 목록
- 새 설계 단위는 9단계 규칙대로 영역 문서 `## 3. 설계 단위` 의 끝번호에 붙이고(다섯 항목 전부), 갈라지거나 없어지는 기존 절은 본문을 고치지 않고 "폐기 — 대체: §3.y" 로만 표시한다.
  후미 절에는 무엇이 어디로 갔는지(옛 절 → 새 절)와 바뀌는 의존 방향을 적는다
- overview 3절 의존 방향 표는 후미 절에 "다음으로 대체" 로 적는다. 리팩토링이 끝난 뒤 지켜야 할 방향이 "금지되는 방향" 열에 규칙으로 생긴다 —
  as-is 문서에서 "관찰" 이던 것이 여기서 처음 규칙이 된다
- 근거는 기존 FR·NFR·TD(대체됐으면 리팩토링 N 의 TD)다. 검증 기준에는 구조 조건을 적는다 — 파일 경로, import 유무
- 7절 CF: 새 절만 검토. 8절 추적표는 폐기된 절을 새 절로 옮긴다. 버전을 올린다
- 폐기한 절을 `architecture` 로 가리키는 완료 태스크 목록을 보고에 적는다 — plan-generator 가 색인에 병기한다
- CLAUDE.md·AGENTS.md 의 `## 구조` 절은 평소대로. `현재 단계` 줄은 refactor-plan 이 끝에 다시 쓴다
```

문서를 안 건드리는 코드 정리라도 **N 은 배정한다** — phase 문서와 LOG 가 "리팩토링 N" 으로 이 요청을 가리킨다.

---

## 4단계. `plan-generator` 10단계 호출 — phase 하나, 태스크는 고칠 목록

plan-generator 는 평소처럼 자기 절차(태스크 frontmatter·phase 문서·STATE.md 행 추가·LOG.md 한 줄·자체 점검·보고)를 다 한다. 이 스킬은 아래 지시만 넘긴다.
지시가 없으면 plan-generator 는 설계 단위마다 "만드는" 태스크를 자르고 PRD 수용 기준을 통과 조건으로 쓴다 — 리팩토링에는 둘 다 맞지 않는다.

```
plan-generator 호출 지시 (refactor-plan 에서)

- plan_setup/ 이 이미 있다. 10단계(부분 갱신)만 한다. 완료된 phase·태스크는 건드리지 않는다
- phase 하나를 끝번호로 더한다: phase-NN, 파일 이름 phase-NN-refactor-<이름>.md (NN = Phase Overview 끝번호 + 1, <이름> 은 영문 — 경로·스크립트 인자에서 인코딩 문제를 피한다).
  phase 문서 머리에 "리팩토링 N: <이름>" 과 후미 절 위치(TRD/ARCHITECTURE 의 절, 없으면 "문서 변경 없음")를 적는다
- 태스크는 아래 고칠 목록의 항목 하나가 태스크 하나다. 항목을 쪼개거나 합치지 않는다. 항목 번호를 태스크 본문 Context 에 적는다
- acceptance_criteria 는 새 수용 기준(기능)이 아니라 둘이다 — 관찰 가능하게:
  ① 구조 조건: 항목의 "구조 조건" 열 그대로 ("파일 X 가 경로 Y 에 있다", "모듈 A 가 B 를 import 하지 않는다")
  ② 행위 보존: "lint·unit·e2e 결과가 리팩토링 전과 같다 — <행위 보존 근거 열의 테스트> 전부 통과, 케이스 수 감소 0"
  실패 경로 하나: "<구조 조건을 어기면> task_validation FAIL". 기능 수용 기준(PRD 의 새 FR)은 0건이어야 한다
- verification 은 넷 그대로. task_validation 은 구조 조건을 본다(파일 시스템·grep — 관찰 수단은 harness-update 가 정의서에 적는다)
- architecture 는 새 절(리팩토링 N 이 만든 §3.x)을 가리킨다. 폐기된 절은 가리키지 않는다
- files 는 항목의 "위치" 열 + 목표 위치. 옮기는 파일은 옛 경로·새 경로 둘 다
- depends_on: 종류 순서 — 스택 뼈대 → 이식 → unit 재구축 → 옛 코드 제거 → 문서 불일치 정리. 정리 항목끼리는 files 가 안 겹치면 독립
- 행위 보존 근거가 빈 항목이 있으면 그 코드의 현행 고정 테스트를 쓰는 태스크를 그 항목 앞에 두고 depends_on 으로 잇는다
- PRD 9절은 건드리지 않는다 — 리팩토링 태스크는 어느 FR 의 담당도 아니고 새 FR 도 없다. PLAN.md 6절 추적표에도 행을 더하지 않는다
- phase 의 Acceptance Criteria: 태스크 전부 completed, 게이트 넷 통과, 구조 조건 전부 성립, "PRD 9절 상태 변화 0, 테스트 케이스 수 리팩토링 전 이상",
  후미 절(리팩토링 N)이 가리키는 구조와 코드가 일치
- phase 문서 머리에 "리팩토링 전 기준값" 칸을 둔다 — 기준 커밋 해시와 unit·e2e 케이스 수. 케이스 수는 이 스킬이 세지 않고 비워 두며, 코디네이터가 첫 배정 전에 게이트를 한 번 돌려 채운다
  (문서에 적힌 수와 파일에서 센 수가 다를 수 있고, "감소 0" 은 실행 결과끼리 비교해야 뜻이 있다)
- STATE.md 의 Phase Overview 에 phase-NN pending 행을 더한다. Current Phase 는 옮기지 않는다(루프의 것). LOG.md 에 "플랜 갱신 — 리팩토링 N phase-NN 추가, 태스크 n개" 한 줄
- CLAUDE.md·AGENTS.md 의 `## 플랜` 절은 평소대로. `현재 단계` 줄은 refactor-plan 이 끝에 다시 쓴다
```

### 기저 언어·프레임워크 교체일 때 지시에 더하는 것

옛 스택으로 쓴 unit 테스트는 새 스택에서 돌지 않는다. 그래서 이 범위에서는 **행위 보존의 기준이 블랙박스 e2e 뿐**이고, unit 은 그 phase 안의 태스크가 새 스택으로 다시 세운다.

```
- 행위 보존 기준은 e2e 뿐이다. 모든 태스크의 ② 는 "e2e 결과가 리팩토링 전과 같다" 로 쓴다. unit 은 기존 게이트로 세지 않는다
- unit 재구축 태스크를 둔다(phase-NN-task-MM) — 새 스택의 러너로 기존 unit 케이스를 하나도 줄이지 않고 다시 쓴다. acceptance_criteria: "옛 unit 파일의 케이스마다 대응 케이스가 있다(수 감소 0)", "새 러너로 전부 통과"
- 이 태스크 뒤의 태스크만 ② 에 unit 을 다시 넣는다. 이 태스크 ID 를 phase 문서에 "unit 게이트 활성 시점" 으로 적는다 — harness-update 가 그 값을 쓴다
- 기존 e2e 가 블랙박스(HTTP·브라우저만, 앱 코드 import 없음)가 아니면 그것을 블랙박스로 바꾸는 태스크가 phase 의 첫 태스크다 — 그전에는 행위 보존 기준이 없다
- lint 도구가 바뀌면 같은 방식 — 새 lint 설정 태스크가 활성 시점
```

게이트 명령(unit 러너·lint)이 바뀌는 것은 **그 태스크가 끝난 뒤 라운드 사이에 harness-update ①** 로 반영한다. phase 시작 전에 한 번에 바꿔 두면 그 사이 태스크들이 안 도는 명령으로 판정된다.

plan-generator 가 끝나면 보고를 그대로 전한다. 확인할 것은 넷 — phase 가 하나 늘었는가, 태스크 수 = 목록 항목 수(+ 현행 고정·unit 재구축), 모든 태스크의 acceptance_criteria 에 구조 조건과 행위 보존이 있고 기능 기준이 없는가, PRD 9절이 그대로인가.

---

## 5단계. `harness-update` · `loop-update` 호출

둘 다 평소대로 자기 절차를 한다. 넘길 것은 리팩토링이 바꾸는 것뿐이다.

```
harness-update 호출 지시 (refactor-plan 에서)

- phase-NN-refactor-<이름> 이 추가됐다. 태스크는 리팩토링(행위 보존 + 구조 조건)이고 새 FR 은 없다 — E2E 흐름 목록·커버 영역에 더할 것은 없다
- task_validation 정의서에 구조 조건의 관찰 수단(파일 존재·grep 으로 import 확인)이 없으면 더한다(②)
- 언어·프레임워크 교체: unit(·lint) 게이트의 활성 시점을 phase-NN 의 재구축 태스크 ID 로 옮긴다 — 활성을 미루는 것이라 ③이다. 결과(그 태스크까지 unit 없이 e2e 만으로 판정)를 제시하고 확인받는다.
  게이트 명령 교체는 지금 하지 않는다 — 그 태스크가 끝난 뒤 라운드 사이에 ① 로 한다
- 라이브러리 최신화·코드 정리: 활성 시점·명령은 그대로. 구성 요소 표(TRD 9.3)가 바뀌면 local-dev 에 반영(②)
- 리팩토링으로 파일이 옮겨지면 lint 대상 경로·테스트 디렉터리가 바뀔 수 있다 — 목록의 "목표" 열을 보고 명령을 맞춘다(①)
```

```
loop-update 호출 지시 (refactor-plan 에서)

- 태스크가 늘었다. DAG 를 스크립트로 다시 만들고 자원 충돌 표·폭을 다시 잰다 — 리팩토링 태스크는 같은 파일을 여럿이 만지므로 files 겹침이 많다
- 언어·프레임워크 교체: 재구축 태스크 전까지 unit 이 미활성이다 — Standing Decisions 의 미활성 승인을 그 태스크 ID 까지로 받아 적는다
- phase-NN 이 completed 되면 루프를 멈추고 사용자에게 돌아온다
```

---

## 6단계. `CLAUDE.md` · `AGENTS.md` — `현재 단계` 줄

이 스킬은 자기 절이 없다. 제품·기술·구조·플랜·하네스·루프 절은 3~5단계에서 부른 스킬이 각자 갱신한다.
이 스킬이 하는 것은 **맨 끝에 `현재 단계` 줄을 덮어쓰는 것** 하나다 — 중간에 부른 plan-generator 가 그 줄을 "plan-generator → 다음: harness-setup" 으로 썼고 update 계열은 그 줄을 건드리지 않으므로, 끝에서 한 번 더 쓴다. 두 파일 다.

```
- 현재 단계: refactor-plan(리팩토링 N: <이름> → phase-NN) → 다음: 개발 루프 (phase-NN-refactor-<이름>)
```

두 파일이 서로 다르면 지금 호스트의 파일을 기준으로 다른 쪽을 맞추되 손으로 적은 줄은 양쪽에 남긴다. 200줄을 넘기지 않는다.

---

## 7단계. 자체 점검과 보고

셋이 끝나면 처음부터 다시 읽으면서 확인한다. 열은 `확인할 것 | 통과 조건 | 걸렸을 때` 다.

| 확인할 것 | 통과 조건 | 걸렸을 때 |
|---|---|---|
| 진입 조건 | `in_progress` phase 0건, 게이트 활성(code-to-docs 진입이면 phase-01 completed) | 0단계로 돌아가 멈춘다 |
| 범위 | 셋 중 하나 이상이 명시됐고 요구 변경이 섞이지 않음 | 섞인 것은 보고의 "일부러 넣지 않은 것" 으로 feature-add·bug-fix 에 |
| 목록 | 모든 항목에 구조 조건(관찰 가능)과 행위 보존 근거가 있음. 근거가 빈 항목은 현행 고정 태스크가 앞에 있음 | 채우거나 태스크를 더한다 |
| 문서 불일치 | 대조한 설계 단위 절 전부(누락 0). 어긋난 곳이 목록(코드 쪽) 또는 후미 절 "대체"(문서 쪽)에 있음 | 대조를 마저 한다 |
| 후미 절 | 범위가 요구하는 문서에만 `## 리팩토링 N` 이 있고 N 이 같음. 첫 줄에 날짜·요청·ID. 기존 절 본문 변경 0(9단계의 "폐기 — 대체" 표시 제외) | 되돌리고 후미 절로 옮긴다 |
| 기존 항목 변경 | "TD-00x 를 다음으로 대체" 형식. 기존 TD·절의 본문이 그대로 | 되돌린다 |
| phase | `plan_setup/phase-NN/phase-NN-refactor-<이름>.md` 가 끝번호이고 완료된 phase 는 바이트 단위로 그대로 | plan-generator 10단계 |
| 태스크 | 수 = 목록 항목 수(+ 현행 고정·unit 재구축). 모든 `acceptance_criteria` 에 구조 조건 + 행위 보존, 기능 기준 0건. `verification` 넷 | plan-generator 10단계 |
| 교체 범위 | ② 가 e2e 뿐이고 unit 재구축 태스크가 있으며 phase 문서에 활성 시점이 적힘 | plan-generator 10단계 |
| PRD | `docs/PRD.md` 가 바이트 단위로 그대로 | 되돌린다 — 요구가 바뀌었으면 feature-add |
| STATE.md | `Phase Overview` 에 phase-NN `pending` 행. 다른 절 그대로 | plan-generator 10단계 |
| 하네스·루프 | 게이트 정의서의 활성 시점이 교체 범위에서만 바뀜(③ 확인 기록). `DAG.md` 에 phase-NN 태스크가 있음 | harness-update·loop-update |
| `현재 단계` 줄 | `CLAUDE.md`·`AGENTS.md` 둘 다 6단계 값, 두 파일이 같음 | 덮어쓴다 |

**자체 점검 결과는 문서에 남기지 않는다.** 보고로 간다.

보고는 이렇게 한다.

1. 범위와 크기 — 셋 중 무엇, 전체/영역, 리팩토링 N
2. 고칠 목록 요약 — 항목 n개(종류별), 그중 문서 불일치 n개(코드 쪽 / 문서 쪽), 행위 보존 근거가 없어 현행 고정 태스크를 더한 항목
3. 문서 — 후미 절을 붙인 문서와 대체된 TD·설계 단위 목록. 안 붙인 문서와 이유("구조 변경 없음")
4. phase-NN — 태스크 n개, 순서(depends_on), 교체 범위면 unit 재구축 태스크와 활성 시점
5. 하네스·루프 — 바뀐 활성 시점(③이면 확인 요청), DAG 폭
6. **문서에 일부러 넣지 않은 것** — 요구 변경(`feature-add`)·버그(`bug-fix`)로 보낸 것. 요청 내용을 그대로 옮겨 다음 스킬에서 다시 설명하지 않게
7. 다음: "루프를 돌려 phase-NN 을 완료시키세요. 교체 범위면 재구축 태스크 완료 뒤 라운드 사이에 harness-update 로 게이트 명령을 바꿉니다"

---

## 범위를 넘는 요청이 함께 오면

리팩토링 요청은 다른 것과 같이 오는 일이 많다. **하지 않고, 어디로 가는지 답한다.** 조용히 무시하지도, 조용히 하지도 않는다.

| 요청 | 이 스킬이 하는 것 | 왜 |
|---|---|---|
| "라이브러리 올리면서 로그인도 제대로 만들자" / "권한 넣자" | 최신화만 목록에. 로그인·권한은 요구 변경이라 `feature-add`. 요청 문장을 보고에 그대로 옮긴다 | PRD 수용 기준이 바뀌면 기존 테스트가 실패하는 것이 정상이 되어 "기존 게이트 통과" 가 통과 조건으로 성립하지 않는다 |
| "정리하는 김에 이 버그도" | 목록에 넣지 않는다. `bug-fix`(phase 완료 뒤, 또는 리팩토링 전에 먼저) | 버그 수정은 회귀 검사·BUG-NN 기록·분리 검증이 따른다. 리팩토링 태스크에 섞이면 셋 다 빠진다 |
| "리팩토링 바로 해 줘, 문서는 됐어" | 목록과 phase 는 만든다. 후미 절은 범위가 요구하면 붙인다 | 문서 없이 고치면 다음 작업이 낡은 문서를 근거로 삼는다. 루프가 고치는 것은 같다 — 문서는 그 루프가 무엇을 지켜야 하는지다 |
| "테스트 없는 부분인데 그냥 고치자" | 현행 고정 테스트 태스크를 앞에 두거나, 사용자가 명시하면 "덮이지 않음" 을 태스크 본문에 적고 진행 | 행위 보존 근거가 없는 항목은 루프가 무엇을 깼는지 모른다. 결정은 사용자가 하되 기록은 남긴다 |

---

## 산출물 요약

이 스킬이 직접 쓰는 것은 없다 — 고칠 목록은 보고와 phase 문서에 남고, 문서·플랜·하네스·루프는 부른 스킬의 형식이다. 여기서는 **후미 절과 phase·태스크의 달라지는 칸**만 보여 준다.

### `docs/TRD.md` 후미 절

```markdown
## 리팩토링 1: 라이브러리 최신화

- **날짜**: YYYY-MM-DD · **요청**: "express·uuid 를 최신으로" · **이 절이 만든 ID**: TD-002·TD-004 대체, OQ-012
- **phase**: phase-02-refactor-deps

### TD-002 를 다음으로 대체
- **영역**: 스택
- **근거 요구사항**: FR-001~FR-012 (변경 없음)
- **결정**: `express` 4.17.1 → 4.21.x, `body-parser` 제거(`express.json()` 내장)
- **검토한 대안**: 5.x — 라우터 경로 문법이 바뀌어 핸들러 전부 재검토. 이번 범위 밖
- **확정도**: 확정
- **되돌리기 비용**: `package.json` 두 줄과 `server.js` 6행
- **검증 방법**: 기존 게이트 넷 통과. `npm ls express` 가 4.21 을 출력

(2절 요약 표 행 추가 · 13절 추적표 갱신 · 버전 0.2 — trd-generator 규칙)
```

### `docs/ARCHITECTURE/overview.md` · 영역 문서 후미 절

```markdown
## 리팩토링 1: 인증 검사 한 곳으로

- **날짜**: YYYY-MM-DD · **요청**: "getUserId 중복 정리" · **이 절이 만든 ID**: backend.md §3.6 (신설), §3.5 폐기 — 대체: §3.6
- **phase**: phase-02-refactor-auth-helper

### 3절 의존 방향을 다음으로 대체
| 부르는 쪽 | 부르는 대상 | 금지되는 방향 |
|---|---|---|
| `routes/*.js`·`server.js` | `lib/auth.js` | 라우터가 쿠키 문자열을 직접 파싱하지 않는다 (규칙 — 리팩토링 1 부터) |

### 옮겨진 것
| 옛 절 | 새 절 | 무엇이 |
|---|---|---|
| backend.md §3.5 | backend.md §3.6 | `getUserId` 정의 (사본 셋 → 한 곳) |
```

### `plan_setup/phase-NN/phase-NN-refactor-<이름>.md` 머리

```markdown
# Phase 02 — refactor-auth-helper (리팩토링 1: 인증 검사 한 곳으로)

- **Goal**: 동작을 바꾸지 않고 `getUserId` 사본 셋을 `lib/auth.js` 하나로 모은다. 기준 문서: overview.md·backend.md 의 `## 리팩토링 1`
- **Dependencies**: phase-01 (게이트 넷 활성)
- **Status**: pending
- **행위 보존 기준**: 게이트 넷 전부 (교체 범위면 "e2e — unit 은 phase-02-task-03 부터")
- **리팩토링 전 기준값**: 커밋 `<해시>` · unit 케이스 수 (코디네이터가 첫 배정 전에 채움) · e2e 케이스 수 (같음)

## Acceptance Criteria
1. 태스크 전부 completed
2. lint·unit·e2e 통과, 케이스 수가 기준값(unit n·e2e m) 이상
3. `getUserId` 정의가 `lib/auth.js` 에만 있다 (`grep -rn "function getUserId"` 1건)
4. `docs/PRD.md` 바이트 단위 변경 0 · 9절 상태 변화 0
```

### 태스크 frontmatter 의 `acceptance_criteria`

```yaml
acceptance_criteria:
  - "`lib/auth.js` 가 있고 `getUserId` 를 export 한다"
  - "`routes/projects.js`·`routes/tasks.js`·`server.js` 에 `getUserId` 정의와 `/uid=` 정규식이 없다 (grep 0건)"
  - "세 파일이 `require('../lib/auth')` 또는 `require('./lib/auth')` 로 가져온다"
  - "lint·unit·e2e 결과가 리팩토링 전과 같다 — test/api/*.test.js 의 401 케이스 전부 통과, 케이스 수 감소 0"
  - "실패 경로: 정의가 두 곳 이상 남아 있으면 task_validation FAIL"
verification: [lint, unit, e2e, task_validation]
```

---

## 에이전트별 참고

- Claude Code에서 실행 중이면: `references/claude-code.md`
- Codex에서 실행 중이면: `references/codex.md`

Files in this skill

  • SKILL.md36.2 KB
  • references/claude-code.md2.9 KB
  • references/codex.md2.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.