| name | merge-check |
| description | PR을 머지해도 되는지 판단하는 머지 전 최종 리뷰. PR이 무엇을 했는지 먼저 요약하고, 기존에 잘 동작하던 기능이 깨지지 않았는지(회귀)를 가장 꼼꼼히 검증한 뒤, 동작 정확성·코드 스타일·CI까지 점검해 머지 가능/불가를 판정하고, `yarn dev`로 직접 열어봐야 할 화면 목록까지 알려줍니다. "머지해도 되나", "머지 전에 봐줘", "이 PR 리뷰해줘", "PR 괜찮은지 확인", "approve해도 되나", "머지 전에 뭘 확인해야 하나" 같은 요청이나, 사용자가 PR 링크만 던져줄 때 반드시 이 스킬을 사용하세요. 현재 브랜치에 연결된 PR이 있으면 링크 없이도 동작합니다. |
머지 전 최종 리뷰 (merge-check)
이 스킬의 목적은 "머지 버튼을 눌러도 안전한가"에 답하는 것입니다.
가장 중요한 판단 기준은 하나입니다: 기존에 잘 동작하던 기능이 그대로 동작하는가.
새 기능이 조금 부족한 건 다음 PR에서 고칠 수 있지만, 잘 쓰던 기능이 깨지면 사용자가 바로 피해를 봅니다.
그래서 이 스킬은 "새로 추가된 코드가 예쁜가"보다 **"이 변경이 무엇을 건드렸고, 그것을 쓰던 곳들이 아직 멀쩡한가"**에 시간을 더 씁니다.
절대 하지 않는 것
- 머지하지 않습니다.
gh pr merge는 어떤 경우에도 실행하지 않습니다. 이 스킬은 판단만 하고, 머지는 사용자가 합니다.
- 코드를 고치지 않습니다. 문제를 찾으면 보고합니다. 고치는 건 별개 작업(
/apply-review)입니다.
- GitHub에 아무것도 쓰지 않습니다. 결과는 대화창에만 한국어로 보고합니다. PR 코멘트나 Approve는 사용자가 명시적으로 요청할 때만, 확인을 받고 남깁니다.
- 확인하지 않은 것을 확인한 척하지 않습니다. 못 본 건 "확인 못 함"으로 적습니다. 근거 없는 ✅ 는 이 스킬을 쓰는 의미를 지웁니다.
0단계: 어떤 PR인지 확정 + 작업 중인 내용 보호
git branch --show-current
git status --porcelain
git rev-parse HEAD
gh pr view --json number,title,url,headRefName,headRefOid,baseRefName,state,mergeable,author
대상 PR 정하기
gh pr view가 PR을 찾으면 → 그 PR이 대상입니다. 링크를 따로 받지 않습니다.
- 못 찾거나 현재 브랜치가
master이면 → 멈추고 PR 링크를 요청합니다. 추측하지 않습니다.
예: "현재 브랜치에 연결된 PR을 찾지 못했어요. 리뷰할 PR 링크를 알려주세요."
- 사용자가 링크를 줬으면 항상 그 링크가 우선입니다. 링크에서
{owner}/{repo}와 PR 번호를 파싱합니다.
내가 읽는 코드가 정말 그 PR의 코드인가 (놓치기 쉬움)
git rev-parse HEAD와 PR의 headRefOid가 다르면, 로컬에서 보고 있는 코드가 PR에 올라간 코드가
아닙니다. 리베이스했지만 아직 푸시하지 않은 경우가 흔합니다. 이때 그냥 리뷰하면 "PR을 검증했다"고
말할 수 없습니다. 두 커밋의 코드가 실제로 같은지 확인하세요:
git diff --stat {headRefOid} HEAD
- 차이가 없거나 무관한 파일뿐이면 → 그대로 진행하고, 보고에 "로컬이 리베이스로 앞서 있으나 코드는
동일"이라고 한 줄 적습니다.
- 차이가 있으면 → 어느 쪽을 리뷰할지 사용자에게 확인합니다. 로컬만 있는 수정은 PR에 없으므로,
그것까지 통과 판정에 넣으면 실제 머지될 코드와 어긋납니다.
사용자의 작업 보호
검증을 위해 브랜치를 옮겨야 할 수도 있습니다. 다만 항상 위험한 건 아니니 구분하세요:
- 이미 그 PR의 브랜치에 있으면 체크아웃이 필요 없습니다. 그냥 진행합니다.
- untracked 파일(
??)만 있으면 체크아웃·머지가 그 파일을 건드리지 않으므로 그대로 진행합니다.
(보고에 한 줄 언급만)
- 수정·스테이징된 변경(
M, A 등)이 있으면 체크아웃하지 말고 사용자에게 먼저 묻습니다:
"커밋되지 않은 변경이 있어요. ① 코드 읽기만으로 리뷰 ② stash 후 진행 — 어느 쪽으로 할까요?"
브랜치를 옮겼다면 리뷰가 끝나고 반드시 원래 브랜치로 돌려놓고, 그 사실을 보고에 적습니다.
1단계: 이 PR이 무엇을 했는지 먼저 요약한다
판정보다 요약이 먼저입니다. 무엇을 하려던 PR인지 모르면 "제대로 했는지"도 판단할 수 없습니다.
gh pr view {number} --repo {owner}/{repo} --json title,body,commits,files,additions,deletions
git fetch upstream master
git diff --stat upstream/master...HEAD
읽을 것:
- PR 제목·본문·연결된 이슈 — 이 PR이 풀려던 문제가 무엇인가
- 커밋 메시지들 — 어떤 순서로 무엇을 했는가
- 변경 파일 목록과 규모 — 어디를 건드렸는가
여기서 나오는 요약은 사용자에게 보여주는 첫 항목이며, 의도(PR 본문)와 실제(diff)가 어긋나는지를 보는 기준이기도 합니다.
"본문에는 A만 고쳤다고 썼는데 diff에는 B도 바뀌어 있다" — 이건 그 자체로 리뷰 대상입니다.
의도하지 않은 파일이 섞여 들어온 것일 수 있고, 그게 회귀의 흔한 원인입니다.
2단계: 실제로 빌드·테스트를 돌린다
기본 동작은 실제 실행입니다. 코드를 읽어서 "괜찮아 보인다"와 빌드가 통과하는 것은 다른 증거입니다.
(사용자가 "빠르게 봐줘"라고 했다면 이 단계를 건너뛰고 CI 결과 조회로 대체하되, 보고에 "직접 실행하지 않음"을 명시합니다.)
검증은 머지된 뒤의 코드에 대해 해야 의미가 있습니다. PR 브랜치 단독으로 통과해도,
그 사이 master에 들어간 다른 변경과 부딪히면 머지 직후에 깨집니다. 그래서 합쳐 놓고 돌립니다.
gh pr checkout {number} --repo {owner}/{repo}
git fetch upstream master
git merge --no-commit --no-ff upstream/master
- 충돌이 나면 →
git merge --abort 후, 충돌 파일을 보고 항목으로 올립니다(조건부 또는 머지 불가 사유).
이후 리뷰는 PR 브랜치 상태로 코드 읽기 중심으로 이어갑니다.
- 깨끗하게 합쳐지면 → 그 상태(= 머지 후 master의 모습)에서 검증을 돌립니다.
yarn build
yarn test
yarn lint
검증이 끝나면 git merge --abort로 합친 상태를 되돌립니다. (머지 결과를 남기지 않습니다.)
- 빌드 실패 → 무조건 머지 불가. 더 볼 것 없습니다.
- 테스트 실패 → 실패한 테스트가 이 PR 때문인지 확인. upstream/master에서도 같은 테스트가 실패하면 기존 문제입니다.
그 구분을 하지 않고 "테스트 실패"라고만 보고하면 사용자가 헛수고합니다.
- CI 결과도 함께 봅니다.
gh pr checks는 실패 여부만 알려주고 이유를 말해주지 않으니,
실패한 것이 있으면 반드시 내용까지 읽습니다. (품질 게이트 실패는 저장소 자체의 머지 기준입니다.)
gh pr checks {number} --repo {owner}/{repo}
gh api repos/{owner}/{repo}/commits/{headRefOid}/check-runs \
--jq '.check_runs[] | select(.conclusion=="failure") | "\(.name) | \(.output.title) | \(.output.summary)"'
3단계: 기존 기능 회귀 점검 — 이 스킬의 핵심
여기에 가장 많은 시간을 씁니다. 방법이 중요합니다. diff를 위에서 아래로 훑어 읽는 것은
추가된 코드를 보게 만들 뿐이고, 회귀는 거의 항상 추가가 아니라 변경과 삭제에서 나옵니다.
3a. PR을 만든 뒤 master가 얻은 변경과 부딪히는지 본다
이건 이 PR의 diff만 봐서는 절대 보이지 않습니다. PR 브랜치 안에서는 완벽한 코드가, 그사이 master에
들어온 다른 변경과 만나 깨질 수 있습니다. 머지 리뷰가 일반 코드 리뷰와 다른 지점이 바로 여기입니다.
git log --oneline $(git merge-base HEAD upstream/master)..upstream/master
커밋 목록을 읽고, 이 PR이 건드린 영역과 겹치는 것이 있으면 그 커밋의 diff를 직접 확인합니다.
특히 백엔드 변경은 프론트와 계약으로 연결돼 있어 겹치기 쉽습니다:
- API 응답·상태 코드가 바뀌었나 — 프론트가 특정 상태 코드(404 등)나 필드를 보고 분기한다면,
그 규칙이 아직 유효한지 확인합니다. (실제로 "없는 이름은 404" 프론트 + "400을 반환" 백엔드가
같은 시점에 올라온 적이 있습니다.)
- 필수 파라미터가 늘었나 — 프론트가 그 값 없이 보내는 경로가 있으면 머지 직후 400이 됩니다.
- 조용히 넘어가던 것이 예외가 되었나 — 기본값으로 대체되던 동작이 오류로 바뀌면, 그에 의존한
화면이 깨집니다.
겹치는 것이 없으면 "master의 새 커밋 N개, 이 PR과 겹치는 영역 없음"이라고 적고 넘어갑니다.
3b. "위험한 변경"만 골라낸다
diff에서 다음을 뽑아 목록으로 만듭니다. 추가만 된 코드는 회귀 위험이 낮으니 뒤로 미룹니다.
git diff upstream/master...HEAD
| 위험 신호 | 왜 위험한가 |
|---|
| 지워진 줄 / 삭제된 파일 · export | 쓰던 곳이 남아 있으면 그대로 깨집니다 |
| 함수 시그니처 · props · 반환 타입 변경 | 호출자가 옛 계약을 기대합니다 |
| 기본값 변경, optional ↔ required 변경 | 인자를 안 넘기던 호출자의 동작이 조용히 바뀝니다 |
조건문(if, 삼항, &&) 수정 | 기존 경로가 새 조건에 걸려 빠질 수 있습니다 |
| 이름 변경 (rename) | 참조를 하나라도 놓치면 깨집니다 |
| 공용 파일 수정 (hooks/api, atoms, constants, utils) | 소비자가 많아 파급이 큽니다 |
3c. 목록의 항목마다 "쓰던 곳 전부"를 찾아 확인한다
이게 핵심 작업입니다. 변경된 심볼 하나하나에 대해:
git grep -n "심볼이름" -- '*.ts' '*.tsx'
그리고 사용처를 샘플링하지 말고 전부 확인합니다. 3곳뿐이면 3곳 다, 20곳이면 20곳 다.
너무 많아 전부 못 봤으면 몇 곳 중 몇 곳을 봤는지 숫자로 보고합니다 ("18곳 중 12곳 확인").
"대충 괜찮아 보인다"는 이 스킬에서 가장 위험한 문장입니다.
각 사용처에서 확인할 것: 이번 변경 후에도 이 호출이 예전과 같은 결과를 내는가.
타입 체크만 통과하는 것으로는 부족합니다 — 타입은 맞는데 동작만 달라지는 변경이 제일 잡기 어렵습니다
(기본값 변경, 조건 뒤집힘, 정렬 순서 변경, 캐시 키 변경 등).
.claude/rules/code-review-policy.md의 영향 분석 절차를 그대로 따릅니다.
3d. Pinpoint에서 실제로 회귀가 났던 자리들
이 프로젝트에서 조용히 깨지기 쉬운 지점입니다. 해당하는 변경이 있으면 반드시 확인합니다.
- 설정 플래그 분기 —
experimental.enableServiceMap 같은 플래그. 플래그가 꺼진 기존 사용자의 경로가
그대로인가를 별도로 확인합니다. 켠 쪽만 확인하고 넘어가는 실수가 흔합니다. 그 기능에 대한 규칙
문서가 .claude/rules/에 있으면 함께 읽습니다.
- Jotai 아톰 — 아톰은 화면 remount로 지워지지 않습니다. 아톰을 추가·수정했으면 읽는 모든 컴포넌트와
초기화 시점을 확인합니다. 안 지워진 옛 값으로 조회가 나가 400을 받는 사고가 실제로 있었습니다.
- React Query 쿼리 키 — 키가 바뀌면 캐시 무효화가 깨지거나, 다른 데이터가 같은 키에 섞입니다.
- 라우트 경로 / URL 파라미터 — 경로 형태가 바뀌면 기존 링크·북마크가 죽습니다. 로더의 검증·리다이렉트가
옛 형태도 받아주는지 확인합니다.
- i18n 키 — 제거·이름 변경된 키를 다른 화면이 아직 쓰고 있지 않은지
git grep으로 확인합니다.
- 컴포넌트 props — 렌더하는 모든 부모가 유효한 props를 넘기는지 확인합니다.
- API 엔드포인트 · 응답 타입 — Java 쪽이 함께 바뀌었으면, 프론트가 기대하는 필드·형태와 맞는지 대조합니다.
(백엔드 코드는 이 계약 부분만 봅니다. 그 외 Java 내부 로직은 이 스킬의 범위가 아니라고 밝히세요.)
3e. 판단이 안 서면 "모르겠다"가 정답이다
코드만으로 확신이 안 서면 추측으로 ✅ 하지 말고 그 항목을 "확인 필요"로 남기고,
사용자가 무엇을 어떻게 확인하면 되는지 알려줍니다 (예: "dev 서버에서 A 화면 → B 클릭 순서로 확인").
머지 여부를 잘못 통과시키는 비용이, 한 번 더 확인하는 비용보다 훨씬 큽니다.
4단계: PR이 의도한 동작을 정확히 하는가
1단계 요약에서 정리한 "이 PR이 풀려던 문제"를 다시 꺼내 대조합니다.
- 이슈에 적힌 증상이 이 변경으로 실제로 해소되는가 (코드를 따라가며 확인)
- 해피 패스뿐 아니라 빈 데이터 · 로딩 · 오류 · 경계값에서도 의도대로 동작하는가
- 문제를 근본에서 고쳤는가, 증상만 가렸는가
- 놓친 케이스가 있는가 (예: 한 화면만 고치고 같은 문제를 가진 다른 화면은 그대로)
깊은 동작 QA가 필요하면 /qa-pr 의 체크리스트(엣지 케이스, 상태 무결성, 컴포넌트 상호작용)를 활용합니다.
5단계: 그 밖에 머지 전에 봐야 하는 것들
6단계: 직접 눈으로 확인할 화면 목록을 만든다 (필수)
코드 추적·빌드·테스트로는 실제로 화면에 무엇이 그려지는지를 알 수 없습니다. 그래서 이 스킬은
"확인 못 했다"로 끝내지 않고, 사용자가 yarn dev로 무엇을 열어 무엇을 봐야 하는지를 항상
목록으로 내놓습니다. 목록이 없으면 사용자는 어디서부터 봐야 할지 몰라 결국 아무것도 확인하지 않습니다.
yarn dev
화면 목록을 뽑는 방법
변경된 파일에서 화면까지 거슬러 올라갑니다. 컴포넌트·훅은 그 자체로 화면이 아니므로, 사용처를
따라 pages/와 라우트까지 올라가야 어떤 주소를 열어야 할지 나옵니다.
git grep -n "변경된컴포넌트\|변경된훅" -- '*.tsx' '*.ts'
주소는 packages/ui/src/constants/path.ts의 APP_PATH에서 확인합니다.
목록에 반드시 들어가야 하는 것
- 기존 화면 (회귀 확인) — 이번에 바뀐 공용 코드를 쓰는 모든 기존 화면. 새 기능 화면보다
먼저 적습니다. 사용자가 제일 걱정하는 건 "잘 쓰던 게 깨졌나"입니다.
공용 코드(
hooks/api, atoms, utils, 공유 컴포넌트)를 건드렸다면 소비 화면이 여러 개일 테니
샘플링하지 말고 다 적습니다.
- 새 기능 화면 (의도 확인) — 이 PR이 만든 동작. PR 본문의 테스트 계획에 있으면 그것을 재사용합니다.
- 설정 플래그가 있으면 양쪽 다 — 켠 상태와 끈 상태. 끈 쪽이 기존 사용자의 화면이므로 더 중요합니다.
- 코드로 확신이 안 섰던 항목 (3e에서 남긴 것) — 그게 바로 눈으로 봐야 하는 것입니다.
각 항목은 **"무엇을 보면 정상인지"**까지 적습니다. "servermap 확인" 같은 문장은 도움이 안 됩니다.
"노드를 클릭하면 오른쪽 패널에 그 노드 이름과 차트가 뜨는지" 처럼 판정 가능한 문장으로 씁니다.
브라우저 개발자도구 네트워크 탭에서 볼 것이 있으면(400 응답, 중복 요청 등) 그것도 적습니다.
7단계: 보고 (대화창, 한국어)
항상 이 구조로 보고합니다. 요약이 판정보다 먼저 오는 순서를 지킵니다 —
사용자는 "무엇을 한 PR인지" 이해한 뒤에 판정을 봐야 그 판정을 신뢰할 수 있습니다.
## 1. 이 PR이 한 일
- **목적**: (이슈/PR 본문 기준, 한두 문장)
- **바꾼 것**: (파일 N개 / +A −B 줄, 핵심 변경 3~5개를 쉬운 말로)
- **의도와 diff의 차이**: (없으면 "없음")
## 2. 검증 결과
| 항목 | 결과 |
|---|---|
| upstream/master 병합 | 충돌 없음 / 충돌 (파일) |
| yarn build | 통과 / 실패 |
| yarn test | 통과 / 실패 (N건, 이 PR 때문인지 여부) |
| yarn lint | 통과 / 실패 |
| CI | 상태 |
## 3. 기존 기능 회귀 점검 (가장 중요)
**master의 새 변경과의 충돌**: 새 커밋 N개 → 겹치는 것마다 판단 + 근거 (없으면 "겹침 없음")
**위험 변경마다**: (항목) — 사용처 N곳 중 M곳 확인 → 판단 + 근거 (`파일:라인`)
**확인하지 못한 것**: (항목) — 왜 확인 못 했는지 (→ 6번 목록으로 넘긴다)
## 4. 동작 정확성
- 의도한 문제가 해소되는가: 판단 + 근거
- 엣지 케이스: 확인 결과
## 5. 그 외 (스타일 · 구조 · 기타)
심각도 순으로: Critical / Warning / Suggestion
## 6. 직접 확인할 화면 (`yarn dev`)
기존 화면 — 회귀 확인:
| 화면 | 주소 | 무엇을 보면 정상인지 |
|---|---|---|
| (화면 이름) | `/경로/...` | (판정 가능한 문장) |
새 기능 — 의도 확인:
| 화면 | 주소 | 무엇을 보면 정상인지 |
|---|---|---|
## 7. 판정
**✅ 머지 가능** / **⚠️ 조건부** / **❌ 머지 불가**
- 이유: (한두 문장)
- 머지 전에 해야 할 일: (있으면 목록)
판정 기준
- ❌ 머지 불가 — 빌드·테스트 실패, 기존 기능이 깨진 것을 확인했음, 머지 충돌 미해결
- ⚠️ 조건부 — 회귀 위험이 있는데 코드만으로는 확정할 수 없음, CI 검사(품질 게이트 등)가 빨간불,
또는 고쳐야 할 문제가 남았지만 치명적이지 않음.
무엇을 확인·수정하면 ✅ 가 되는지 반드시 적습니다.
- ✅ 머지 가능 — 검증·CI 통과 + 위험 변경의 사용처를 확인했고 문제 없음
6번의 화면 목록은 판정과 무관하게 항상 내놓습니다. ✅ 라도 "코드로는 문제를 못 찾았다"는
뜻이지 "화면을 봤다"는 뜻은 아니고, 그 차이를 사용자가 알아야 스스로 판단할 수 있습니다.
애매하면 ✅ 를 주지 마세요. ⚠️ 는 사용자가 5분 더 확인하게 만들지만, 잘못된 ✅ 는 깨진 코드를 배포합니다.
다만 근거 없이 ⚠️ 를 남발하는 것도 도움이 되지 않습니다 — ⚠️ 에는 항상 "무엇을 확인해야 하는지"가 붙어야 합니다.
마지막 정리
- 브랜치를 옮겼다면 원래 브랜치로 복귀했는지 확인하고 보고에 한 줄 적습니다.
git merge --abort, stash 복원 등 임시 상태가 남지 않았는지 확인합니다.
- 사용자가 PR 코멘트나 Approve를 원하면 그때 확인을 받고 남깁니다. 본문은 영어입니다
(
.claude/rules/git-workflow.md).