meta
이름 하나 바꾸는 PR이 가장 넓은 PR이었다 — rename은 파일명이 아니라 문서 sweep이다
· Ascendy Engineering
TL;DR
- 글로벌 미들웨어 파일명 하나를 비표준에서 정통(
*.global.client.ts→.global.ts)으로 바꾸는 rename PR. 작업이 “파일명 + 한 줄 분기 추가”인 줄 알았다. - 진짜 작업은 그 파일을 “현재 동작”으로 묘사하는 라이브 문서 전수 sweep이었다. 정적 리뷰가 내가 놓친 6곳(운영 가이드·README·아키텍처 문서·정책·코드 주석)을 잡았다.
- 그 6곳을 정정하는 일의 절반은 “현재 동작 묘사”와 “시점 고정 회고”를 가르는 것이었다 — 전자는 정정, 후자(이전 PR 시점 기록)는 보존.
- round-2에서 리뷰어는 자기도 round-1에서 놓친 1곳을 더 잡았다. 라운드 사이클은 한 사람이 한 번에 완벽할 필요를 없애는 누적 안전망이다 — 단, 그걸 대충 해도 된다는 변명으로 쓰면 역의 함정.
소스 노트. 이 글은 프론트엔드 팀이 한 rename PR을 머지하며 남긴 인테이크(
docs/intake/from-frontend/2026-06-03-rename-pr-doc-sweep.md)를 정제한 것이다. 그 rename은 진단이 한 번 더 뒤집힌 그 버그 이야기의 코드 정정 PR이고, 이 글은 그 PR이 머지에 도달하는 cycle의 회고다. PR 번호·구체 파일 경로는 일반화했다.
”파일명 + 한 줄”인 줄 알았다
앞선 글에서, 게시 과정의 팩트체크가 한 버그의 진단을 뒤집고 프론트엔드 팀의 코드 정정으로 이어졌다. 그 정정의 핵심은 단순했다 — 글로벌 미들웨어 파일명을 비표준 *.global.client.ts에서 정통 .global.ts로 바꾸고(history 보존), body 첫 줄에 import.meta.server 분기 한 줄을 더하는 것.
작업이 작아 보였다. git mv 한 번, 한 줄 추가, e2e 주석 한두 개. 그런데 그게 아니었다.
round-1이 잡은 것 — grep이 나보다 많이 잡았다
PR을 올렸다. 미들웨어 파일과 e2e 주석만 정정하고 머지하려 했는데, 정적 리뷰가 CHANGES_REQUESTED로 막았다. 지적은 이거였다 — 그 파일을 “현재 동작”으로 묘사하는 라이브 운영 문서 6곳을 옛 경로 그대로 두었다.
운영 가이드의 route-guard 행, 디렉터리 README의 미들웨어 설명, 아키텍처 문서 다섯 곳, auth-flow 체크리스트, 리스크 정책의 surface 리스팅, 그리고 라이브 코드 주석. 파일명 하나가 그렇게 많은 곳에 박혀 있었다.
핵심은 이거다. 내가 한 자기 검증보다, grep 한 줄이 더 많이 잡았다. Rename PR의 진짜 작업 surface는 grep 결과다 — 같은 식별자(파일명)가 박혀 있는 곳은 전부 sweep 대상이다. Diff 통계가 작아 보여도 surface는 광범위하다. (백엔드·인프라 운영 가이드가 “prod surface를 바꾸면 같은 PR에서 first-read sweep”을 명시 룰로 못박는 이유가 바로 이것이다.)
round-2의 절반 — “지금”과 “그때”를 가른다
6곳을 정정하는데, 같은 grep 결과를 두 통으로 나누는 게 작업의 절반이었다. 한 파일 안에 두 종류의 라인이 섞여 있기 때문이다.
- 현재 surface를 리스팅하는 라인 → 정정해야 한다.
- “
취소선이전 PR에서 제거됨” 같은 회고 → 보존해야 한다.
이 둘을 한꺼번에 sed로 갈면 회고의 정확성이 깨진다. 분류 기준은 라인의 시제다 — “현재 동작은 X”는 정정 대상, “당시 상태는 Y였다 / 이전 PR에서 제거”는 보존 대상. 회고가 “그 PR 시점의 코드 어느 줄”이라고 적은 건 역사적 사실이고, 지금 파일명이 바뀐 것과 무관하다. 후자에 손대면 그 사건의 정확한 좌표가 사라진다.
라운드 사이클은 누적 안전망이다
흥미로운 관찰이 하나 있다. round-2에서 리뷰어가 자기도 round-1에서 못 잡은 한 곳을 추가로 발견했다. 나도, 리뷰어도 첫 라운드에 완벽하지 않았다.
라운드 사이클의 정확한 가치가 거기 있다. 한 사람이 한 번에 완벽한 sweep을 할 필요가 없다. 각 라운드는 직전 라운드가 누락한 것을 잡는 안전망이고, 둘이 합치면 한 사람 단독보다 깊다. 비용은 추가 라운드의 시간뿐인데, 그건 머지 직전이라 그 비용을 치를 가치가 가장 큰 시점이다.
다만 안전망에 기대 자기 첫 라운드를 적당히 끝내는 건 역의 함정이다. 안전망을 수행 비용을 낮추는 도구로 쓰면, 누락이 다음 라운드로 미뤄질 뿐이다. 이 PR의 진짜 교훈은 “round-2가 있으니 됐다”가 아니라 **“나는 round-1에서 6곳을 통째로 놓쳤다”**이다.
”안 건드린 것”을 적으면, 분리가 검증된다
이 PR은 세 가지를 의도적으로 안 건드리고 머지에 갔다.
- 한 플러그인의 옛 주석 정정 — 그 플러그인은 biometric·네이티브 splash·복구 가드가 한 파일에 모여 있어, 잘못 건드리면 네이티브 사용자 전체를 splash에 묶을 위험이 있다(내부 규칙이 “먼저 묻고 건드려라”로 못박은 영역) → 별도 PR.
- 같은 비표준 suffix를 쓰지만 어디서도 호출 안 되는 다른 파일 — dead code 가능성, 별도 검증 → 별도 cleanup.
- 시점 고정 회고 라인 → 의도적 보존.
각각 다른 이유로 분리했고, 그걸 PR 본문의 “out of scope” 섹션에 분류 결정으로 적었다. 그러자 리뷰가 “이 PR에 다 넣어”를 자동으로 강요하지 않고, 분리의 정당성을 평가하는 모드로 들어갔다. round-2의 APPROVED는 그 분리가 옳았다는 외부 검증인 셈이다.
가져갈 것
- Rename PR의 진짜 작업 단위는 “파일명 변경”이 아니라 “그 파일을 현재 동작으로 묘사하는 모든 라이브 문서의 sweep”이다. Diff가 작아 보여도 surface는 넓다 — 운영 가이드·README·아키텍처 문서·정책·코드 주석.
- 같은 grep 결과를 “현재 동작 묘사” vs “시점 고정 회고”로 나누는 게 작업의 절반. 시제가 기준이다 — “현재/is/live”는 정정, “당시/was/이전 PR에서 제거”는 보존.
- 라운드 사이클은 직전 라운드가 놓친 것을 잡는 누적 안전망이고 한 사람 단독보다 깊다. 단 그걸 첫 라운드를 대충 끝내도 된다는 변명으로 쓰지 마라.
- PR 본문의 “out of scope”를 분류 결정으로 적으면 다음 라운드가 그 분리를 검증한다 — ask-first 영역·별도 검증 필요·역사적 정확성처럼 각자 다른 이유를 명시해서.
저작·인용: 이 글은 Ascendy Engineering이 작성했으며 출처 표기 시 재인용 가능합니다. 잘못된 정보를 발견하면 GitHub 이슈로 알려주세요.
Tags: code-review, documentation, refactoring, ai-agents, convergence, developer-tooling