--- name: code-review-and-quality description: 여러 축으로 코드 리뷰를 수행합니다. 어떤 변경이든 머지하기 전에 사용하세요. 자신, 다른 에이전트, 또는 사람이 작성한 코드를 리뷰할 때 사용하세요. 변경이 메인 브랜치에 들어가기 전에 여러 차원에서 코드 품질을 평가해야 할 때 사용하세요. diff나 풀 리퀘스트를 리뷰해 달라는 요청이 있을 때, diff가 본문에 그대로 붙여넣어진 경우에도 사용하세요. --- # Code Review and Quality ## 개요 품질 게이트가 있는 다차원 코드 리뷰입니다. 모든 변경은 머지 전에 리뷰합니다. 예외는 없습니다. 리뷰는 다섯 축을 다룹니다. 정확성, 가독성, 아키텍처, 보안, 성능입니다. **승인 기준:** 완벽하지 않더라도 전체 코드 건강성을 분명히 개선하면 변경을 승인하세요. 완벽한 코드는 없습니다. 목표는 지속적 개선입니다. 자신이 작성했을 방식과 정확히 같지 않다는 이유로 변경을 막지 마세요. 코드베이스를 개선하고 프로젝트 관례를 따르면 승인하세요. ## 언제 사용하나 - 풀 리퀘스트나 변경을 머지하기 전 - 기능 구현을 마친 뒤 - 다른 에이전트나 모델이 만든 코드를 평가해야 할 때 - 기존 코드를 리팩터할 때 - 버그를 고친 뒤 (수정과 회귀 테스트를 모두 리뷰) ## 다섯 축 리뷰 모든 리뷰는 다음 차원으로 코드를 평가합니다. ### 1. 정확성 코드가 주장하는 대로 동작하나요? - 스펙이나 작업 요구사항과 맞나요? - 엣지 케이스(null, 빈 값, 경계값)를 처리하나요? - 에러 경로를 처리하나요? (정상 경로만이 아닙니다) - 모든 테스트를 통과하나요? 테스트가 실제로 올바른 대상을 검증하나요? - off-by-one 오류, 경쟁 상태, 상태 불일치가 있나요? ### 2. 가독성과 단순성 다른 엔지니어(또는 에이전트)가 작성자의 설명 없이 이 코드를 이해할 수 있나요? - 이름이 설명적이고 프로젝트 관례와 일관되나요? (맥락 없는 `temp`, `data`, `result`는 안 됩니다) - 제어 흐름이 직관적인가요? (중첩 삼항 연산자와 깊은 콜백은 피하세요) - 코드가 논리적으로 구성되어 있나요? (관련 코드가 모여 있고, 모듈 경계가 분명한가요) - 단순화해야 할 "영리한" 트릭이 있나요? - **더 적은 줄로 할 수 있나요?** (100줄이면 충분한 일을 1000줄로 쓰는 것은 실패입니다) - **추상화가 그 복잡성을 감수할 만큼의 이득을 주나요?** (세 번째 사용 사례가 나오기 전에는 일반화하지 마세요) - 분명하지 않은 의도를 주석이 밝혀 줄까요? (다만 뻔한 코드에는 주석을 달지 마세요.) - 죽은 코드 아티팩트가 있나요? no-op 변수(`_unused`), 하위 호환 심, `// removed` 주석 등입니다. - **새 조건문이 관련 없는 흐름에 덧붙어 있나요?** 이것은 니트가 아니라 설계 냄새입니다. 기존 경로를 얽히게 하지 말고, 로직을 자체 헬퍼, 상태, 또는 정책으로 밀어 넣으세요. - **같은 형태를 조건문으로 반복하나요?** 빠진 모델이나 디스패처의 신호입니다. "임시" 분기는 대개 영구적인 부채가 됩니다. ### 3. 아키텍처 변경이 시스템 설계에 맞나요? - 기존 패턴을 따르나요, 아니면 새 패턴을 도입하나요? 새 패턴이라면 근거가 있나요? - 모듈 경계가 깨끗한가요? - 공유해야 할 코드 중복이 있나요? - 의존성이 올바른 방향으로 흐르나요? (순환 의존성은 없어야 합니다) - 추상화 수준이 적절한가요? (과잉 설계도 아니고, 지나치게 결합되어 있지도 않아야 합니다) - **이 리팩터가 복잡성을 줄이나요, 아니면 자리만 옮기나요?** 변경을 따라가려면 독자가 쥐고 있어야 하는 개념의 수를 세어 보세요. "더 깔끔한" 버전이 그 수를 그대로 두면 더 깔끔한 것이 아닙니다. 같은 로직을 다시 한곳으로 모으는 쪽보다, 분기나 모드나 계층 전체가 사라지는 재구성을 선호하세요. 추상화를 다듬기보다 삭제하는 쪽을 선호하세요. - **기능 전용 로직이 공유 모듈이나 범용 모듈로 새고 있나요?** 로직은 소유 계층에 두세요. 거의 같은 복제본 대신 기존 표준 헬퍼를 재사용하세요. 아키텍처 표류를 정상적인 것으로 만들지 마세요. - **타입 경계가 명시적인가요?** 불필요한 `any`/`unknown`/optional/캐스트와, 불명확한 불변 조건을 가리는 조용한 폴백을 의심하세요. 경계를 명시하면 주변 제어 흐름이 더 단순해지는 경우가 많습니다. ### 4. 보안 자세한 보안 안내는 `security-and-hardening`을 보세요. 변경이 취약점을 도입하나요? - 사용자 입력을 검증하고 정제하나요? - 시크릿을 코드, 로그, 버전 관리 밖에 두나요? - 필요한 곳에서 인증과 인가를 확인하나요? - SQL 쿼리를 파라미터화했나요? (문자열 연결은 쓰지 않습니다) - XSS를 막도록 출력을 인코딩하나요? - 의존성이 신뢰할 수 있는 출처이고, 알려진 취약점이 없나요? - 외부 출처(API, 로그, 사용자 콘텐츠, 설정 파일)의 데이터를 신뢰하지 않는 데이터로 다루나요? - 외부 데이터 흐름을 로직이나 렌더링에 쓰기 전에 시스템 경계에서 검증하나요? ### 5. 성능 자세한 프로파일링과 최적화는 `performance-optimization`을 보세요. 변경이 성능 문제를 도입하나요? - N+1 쿼리 패턴이 있나요? - 제한 없는 루프나 제한 없는 데이터 조회가 있나요? - 비동기여야 할 동기 작업이 있나요? - UI 컴포넌트의 불필요한 리렌더가 있나요? - 목록 엔드포인트에 페이지네이션이 빠졌나요? - 핫 패스에서 큰 객체를 생성하나요? ## 구조적 해결책 구조적 문제를 지적할 때는 문제만이 아니라 어떻게 옮길지를 제안하세요. "복잡합니다"라고만 말하는 리뷰는 작성자가 추측하게 둡니다. 이름이 있는 재구성을 고르세요. - **조건문 사슬을** 타입이 있는 모델이나 명시적 디스패처로 **바꾸세요.** - **중복 분기를** 하나의 더 분명한 흐름으로 **합치세요.** - **오케스트레이션과 비즈니스 로직을 분리**해서 각각이 따로 읽히게 하세요. - **기능 전용 로직을** 공유 모듈에서 그 개념을 소유하는 패키지로 **옮기세요.** - 따로 만든 거의 같은 복제본 대신 **표준 헬퍼를 재사용**하세요. - **타입 경계를 명시**해서 하류 분기가 사라지게 하세요. - API를 더 분명하게 하지 않으면서 우회만 더하는 **통과용 래퍼를 삭제**하세요. - **헬퍼를 추출하거나, 큰 파일을** 초점이 있는 모듈로 **나누세요.** 같은 복잡성을 흩어 놓는 해결책보다, 움직이는 부품을 없애는 해결책을 선호하세요. ## 변경 크기 작고 초점이 있는 변경은 리뷰하기 쉽고, 머지가 빠르며, 배포하기 안전합니다. 다음 크기를 목표로 하세요. ``` ~100 lines changed → Good. Reviewable in one sitting. ~300 lines changed → Acceptable if it's a single logical change. ~1000 lines changed → Too large. Split it. ``` **파일 크기를 보세요. diff 크기만 보지 마세요.** 작은 diff도 파일을 건강한 경계를 넘게 밀어 넣을 수 있습니다. 단일 파일에서 약 1000 *전체* 줄(위의 ~1000 *변경* 줄 기준과는 별개입니다)은 흔한 점검 신호이지, 절대 상한이 아닙니다. 변경이 이미 큰 파일을 실질적으로 키우면, 더 쌓기 전에 헬퍼, 하위 컴포넌트, 모듈을 *먼저* 추출할지 물으세요. 분해한 다음 추가하세요. **"하나의 변경"으로 치는 것:** 한 가지를 다루는 자기 완결적 수정입니다. 관련 테스트를 포함하고, 제출 후에도 시스템이 동작하는 상태를 유지합니다. 기능 전체가 아니라 기능의 한 부분입니다. **변경이 너무 클 때의 나누기 전략:** | 전략 | 방법 | 시점 | |------|------|------| | **쌓기 (Stack)** | 작은 변경을 제출하고, 그것을 기반으로 다음 변경을 시작합니다 | 순차적 의존성이 있을 때 | | **파일 그룹별 (By file group)** | 서로 다른 리뷰어가 필요한 그룹마다 변경을 나눕니다 | 횡단 관심사 | | **수평 (Horizontal)** | 공유 코드와 스텁을 먼저 만들고, 그다음 소비 측을 만듭니다 | 계층형 아키텍처 | | **수직 (Vertical)** | 기능을 더 작은 풀스택 조각으로 나눕니다 | 기능 작업 | **큰 변경이 허용되는 경우:** 파일 전체 삭제, 그리고 리뷰어가 모든 줄이 아니라 의도만 확인하면 되는 자동 리팩터링입니다. **리팩터링과 기능 작업을 분리하세요.** 기존 코드를 리팩터하면서 새 동작을 추가하는 변경은 두 개의 변경입니다. 따로 제출하세요. 작은 정리(변수 이름 바꾸기)는 리뷰어 재량으로 포함할 수 있습니다. ## 변경 설명 모든 변경에는 버전 관리 이력 안에서 그 자체로 성립하는 설명이 필요합니다. **첫 줄:** 짧고, 명령형이며, 단독으로 읽혀야 합니다. "Deleting the FizzBuzz RPC."가 아니라 "Delete the FizzBuzz RPC"입니다. 이력을 검색하는 사람이 diff를 읽지 않고도 변경을 이해할 만큼 정보가 있어야 합니다. **본문:** 무엇이 바뀌는지, 왜 바뀌는지. 코드 자체에서는 보이지 않는 맥락, 결정, 근거를 넣으세요. 관련이 있으면 버그 번호, 벤치마크 결과, 설계 문서에 링크하세요. 접근법의 부족한 점이 있으면 인정하세요. **안티패턴:** "Fix bug", "Fix build", "Add patch", "Moving code from A to B", "Phase 1", "Add convenience functions." (버그를 고침, 빌드를 고침, 패치를 추가함, A에서 B로 코드를 옮김, 1단계, 편의 함수를 추가함) ## 리뷰 절차 ### 1단계: 맥락 파악 코드를 보기 전에 의도를 파악하세요. ``` - What is this change trying to accomplish? - What spec or task does it implement? - What is the expected behavior change? ``` ### 2단계: 테스트부터 리뷰 테스트는 의도와 커버리지를 드러냅니다. ``` - Do tests exist for the change? - Do they test behavior (not implementation details)? - Are edge cases covered? - Do tests have descriptive names? - Would the tests catch a regression if the code changed? ``` 마지막 질문은 읽어서가 아니라 실험으로 답하세요. 변경이 추가한 조건 하나를 뒤집으세요. 부정을 빼거나 `&&`를 `||`로 바꿉니다. 스위트를 실행한 다음, 복사본에서 파일을 복원하세요. GREEN으로 남는 뮤테이션은 발견 사항입니다. 빠진 테스트 케이스의 이름을 적으세요. 프로젝트 전체 뮤테이션 점수는 `constraint-driven-development`를 보세요. ### 3단계: 구현 리뷰 다섯 축을 염두에 두고 코드를 따라가세요. ``` For each file changed: 1. Correctness: Does this code do what the test says it should? 2. Readability: Can I understand this without help? 3. Architecture: Does this fit the system? 4. Security: Any vulnerabilities? 5. Performance: Any bottlenecks? ``` ### 4단계: 발견 사항 분류 발견 사항을 보고하기 전에, 변경된 코드에 도달하는 호출자, 가드, 테스트와 대조하세요. 그것들이 해당 사항을 배제하면 빼세요. 베이스에 이미 있는 결함은, 이 변경이 도입하는 회귀와 구분해서 표시하세요. 발견 사항이 0건인 것도 유효한 결과입니다. 하나를 지어내지 마세요. 모든 코멘트에 심각도를 붙여서, 작성자가 필수와 선택을 구분할 수 있게 하세요. | 접두사 | 의미 | 작성자 조치 | |--------|------|-------------| | *(접두사 없음)* | 필수 변경 | 머지 전에 반드시 반영 | | **Critical:** | 머지를 막음 | 보안 취약점, 데이터 손실, 깨진 기능 | | **Nit:** | 사소하고 선택 | 작성자가 무시해도 됩니다. 포맷과 스타일 취향입니다 | | **Optional:** / **Consider:** | 제안 | 고려할 가치는 있으나 필수는 아닙니다 | | **FYI** | 정보 제공만 | 조치는 필요 없습니다. 나중 참고를 위한 맥락입니다 | 이렇게 하면 작성자가 모든 피드백을 필수로 보고 선택 제안에 시간을 낭비하지 않습니다. **중요한 것을 앞에 두세요.** 발견 사항을 영향이 큰 순서로 배열하세요. 정확성과 보안이 먼저이고, 그다음 구조적 회귀와 놓친 단순화, 그다음 나머지입니다. 진짜 이슈를 겉모습만의 니트 아래에 묻지 마세요. 확신이 높은 코멘트 몇 개가 긴 목록보다 낫습니다. 구조적 문제가 하나이고 니트가 열 개라면, 그 구조적 문제가 *곧* 리뷰입니다. ### 5단계: 검증 내용 확인 작성자의 검증 이야기를 확인하세요. ``` - What tests were run? - Did the build pass? - Was the change tested manually? - Are there screenshots for UI changes? - Is there a before/after comparison? ``` ## 다중 모델 리뷰 패턴 리뷰 관점마다 다른 모델을 사용하세요. ``` Model A writes the code │ ▼ Model B reviews for correctness and architecture │ ▼ Model A addresses the feedback │ ▼ Human makes the final call ``` 이렇게 하면 단일 모델이 놓칠 수 있는 이슈를 잡습니다. 모델마다 맹점이 다릅니다. **리뷰 에이전트용 예시 프롬프트:** ``` Review this code change for correctness, security, and adherence to our project conventions. The spec says [X]. The change should [Y]. Flag any issues as Critical, Required, Optional, or Nit. ``` ## 죽은 코드 정리 리팩터링이나 구현 변경 후에 고아 코드를 확인하세요. 1. 이제 도달할 수 없거나 쓰이지 않는 코드를 찾으세요 2. 그것을 명시적으로 나열하세요 3. **삭제하기 전에 물어보세요.** "Should I remove these now-unused elements: [list]?" (지금 쓰이지 않게 된 이 요소들을 제거할까요: [목록]) 죽은 코드를 남겨 두지 마세요. 이후의 독자와 에이전트를 혼란스럽게 합니다. 다만 확신이 없는 것을 조용히 삭제하지는 마세요. 의심스러우면 물어보세요. ``` DEAD CODE IDENTIFIED: - formatLegacyDate() in src/utils/date.ts — replaced by formatDate() - OldTaskCard component in src/components/ — replaced by TaskCard - LEGACY_API_URL constant in src/config.ts — no remaining references → Safe to remove these? ``` ## 리뷰 속도 느린 리뷰는 팀 전체를 막습니다. 리뷰를 위해 컨텍스트를 전환하는 비용은, 다른 사람에게 지우는 대기 비용보다 작습니다. - **영업일 기준 하루 안에 응답하세요.** 이것은 최대치이지 목표가 아닙니다 - **이상적인 주기:** 집중해서 코딩하는 중이 아니라면, 리뷰 요청이 도착한 직후에 응답하세요. 일반적인 변경은 하루 안에 리뷰를 여러 라운드 마쳐야 합니다 - **빠른 최종 승인보다 빠른 개별 응답을 우선하세요.** 여러 라운드가 필요해도 빠른 피드백은 좌절을 줄입니다 - **큰 변경:** 거대한 변경 묶음 하나를 리뷰하지 말고, 작성자에게 나누라고 요청하세요 ## 의견 충돌 다루기 리뷰 이견을 해결할 때 다음 위계를 적용하세요. 1. **기술적 사실과 데이터**가 의견과 취향보다 우선합니다 2. **스타일 가이드**는 스타일 문제에서 절대적인 권위입니다 3. **소프트웨어 설계**는 개인 취향이 아니라 엔지니어링 원칙으로 평가해야 합니다 4. **코드베이스 일관성**은 전체 건강성을 떨어뜨리지 않으면 허용됩니다 **"I'll clean it up later."(나중에 정리하겠습니다)를 받아들이지 마세요.** 경험상 미룬 정리는 거의 일어나지 않습니다. 진짜 긴급 상황이 아니면 제출 전에 정리를 요구하세요. 이 변경에서 주변 이슈를 다룰 수 없으면, 버그를 등록하고 자신에게 할당하도록 요구하세요. ## 리뷰에서의 정직함 코드를 리뷰할 때, 자신이 썼든 다른 에이전트나 사람이 썼든 다음을 지키세요. - **형식적으로 승인하지 마세요.** 리뷰했다는 근거 없는 "LGTM"은 누구에게도 도움이 되지 않습니다. - **진짜 이슈를 누그러뜨리지 마세요.** 프로덕션에 닿을 버그인데 "사소한 우려일 수 있습니다"라고 말하는 것은 정직하지 않습니다. - **가능하면 문제를 수치로 말하세요.** "느릴 수 있습니다"보다 "이 N+1 쿼리는 목록의 항목마다 약 50ms를 더합니다"가 낫습니다. - **문제가 분명한 접근에는 반박하세요.** 리뷰에서 아부는 실패 모드입니다. 구현에 문제가 있으면 직접 말하고 대안을 제안하세요. - **번복을 우아하게 받아들이세요.** 작성자가 전체 맥락을 갖고 있고 동의하지 않으면, 그 판단에 따르세요. 사람이 아니라 코드에 코멘트하세요. 개인에 대한 비판은 코드 자체에 초점을 맞춰 다시 쓰세요. ## 의존성 규율 코드 리뷰의 일부는 의존성 리뷰입니다. **의존성을 추가하기 전에:** 1. 기존 스택이 이 문제를 푸나요? (대개 풉니다.) 2. 의존성 크기는 얼마나 되나요? (번들 영향을 확인하세요.) 3. 활발히 유지보수되나요? (마지막 커밋과 열린 이슈를 확인하세요.) 4. 알려진 취약점이 있나요? (`npm audit`) 5. 라이선스는 무엇인가요? (프로젝트와 호환되어야 합니다.) **규칙:** 새 의존성보다 표준 라이브러리와 기존 유틸리티를 선호하세요. 모든 의존성은 부담입니다. **기존 의존성을 업그레이드하는 것**도 다른 코드 변경과 같습니다. 가장 위험한 업그레이드는 "bump deps" 같은 메시지와 함께 한꺼번에 머지되는 것입니다. 같은 규율로 리뷰하세요. 1. **버전 번호만이 아니라 변경 이력을 읽으세요.** SemVer는 메인테이너가 지키지 않았을 수도 있는 약속입니다. "patch"에도 동작 변경이 실릴 수 있습니다. 메이저 범프라면 마이그레이션 노트를 읽고 무엇이 깨지는지 찾으세요. 2. **변경당 의존성 하나.** 하나씩, 또는 서로 관련된 작은 묶음으로 업그레이드하고 머지하세요. 일괄 범프가 빌드를 깨뜨리면 어느 패키지가 원인인지 알 수 없게 됩니다. 패키지 하나짜리 변경은 원인이 분명하고 되돌리기도 깨끗합니다. 3. **테스트가 결정하게 하세요.** 업그레이드는 "설치됐다"로 검증되는 것이 아닙니다. 전 *그리고* 후의 녹색 스위트로 검증됩니다. 의존성 동작 주변 커버리지가 얇으면 그 공백이 진짜 발견 사항입니다. 테스트를 먼저 추가하세요. 4. **전이 그래프를 의식하세요.** 설치된 패키지 대부분은 아무도 직접 고르지 않은 것입니다. `package.json`만이 아니라 락파일 diff를 리뷰하세요. 직접 의존성 범프 하나가 간접 변경 수십 개를 끌어올 수 있습니다. 5. **락파일을 정직하게 유지하세요.** 커밋하고, diff를 리뷰하고, 손으로 고치지 마세요. 실제로 출시되는 내용을 고정하는 것은 락파일입니다. `npm audit` 발견 사항과 공급망 위험(타이포스쿼팅, 침해된 메인테이너)을 분류할 때는 `security-and-hardening` 스킬을 따르세요. 이 절은 업그레이드 *워크플로우*를 다루고, 그 스킬은 보안 판정을 다룹니다. ## 리뷰 체크리스트 ```markdown ## Review: [PR/Change title] ### Context - [ ] I understand what this change does and why ### Correctness - [ ] Change matches spec/task requirements - [ ] Edge cases handled - [ ] Error paths handled - [ ] Tests cover the change adequately ### Readability - [ ] Names are clear and consistent - [ ] Logic is straightforward - [ ] No unnecessary complexity ### Architecture - [ ] Follows existing patterns - [ ] No unnecessary coupling or dependencies - [ ] Appropriate abstraction level - [ ] Refactors reduce complexity rather than relocate it - [ ] No feature logic in shared modules; file stays within a healthy size ### Security - [ ] No secrets in code - [ ] Input validated at boundaries - [ ] No injection vulnerabilities - [ ] Auth checks in place - [ ] External data sources treated as untrusted ### Performance - [ ] No N+1 patterns - [ ] No unbounded operations - [ ] Pagination on list endpoints ### Verification - [ ] Tests pass - [ ] Build succeeds - [ ] Manual verification done (if applicable) ### Verdict - [ ] **Approve** — Ready to merge - [ ] **Request changes** — Issues must be addressed ``` ## 함께 보기 - 자세한 보안 리뷰 안내는 `../../references/security-checklist.md`를 보세요 - 성능 리뷰 점검 항목은 `../../references/performance-checklist.md`를 보세요 ## 흔한 합리화 | 합리화 | 현실 | |---|---| | "동작하니까 그걸로 충분하다" | 동작은 하지만 읽기 어렵거나, 안전하지 않거나, 아키텍처가 틀린 코드는 복리로 쌓이는 부채를 만듭니다. | | "내가 썼으니 맞다" | 작성자는 자기 가정에 눈이 멉니다. 모든 변경은 다른 시선이 있으면 더 좋아집니다. | | "나중에 정리하자" | 나중은 오지 않습니다. 리뷰가 품질 게이트입니다. 그것을 쓰세요. 머지 후에가 아니라 머지 전에 정리를 요구하세요. | | "AI가 만든 코드니까 아마 괜찮다" | AI가 만든 코드는 덜이 아니라 더 살펴야 합니다. 틀려도 자신 있고 그럴듯합니다. | | "테스트가 통과하니 좋다" | 테스트는 필요하지만 충분하지 않습니다. 아키텍처 문제, 보안 이슈, 가독성 우려는 잡지 못합니다. | | "리팩터하니 더 깔끔하다" | 복잡성을 옮기는 것은 줄이는 것이 아닙니다. 독자가 여전히 같은 수의 개념을 쥐고 있다면 구조는 개선되지 않은 것입니다. 분기가 사라지는 버전을 찾으세요. | | "이 파일에 조금만 더한 것이다" | 작은 diff도 파일을 건강한 크기를 넘게 밀고, 관련 없는 흐름에 분기를 덧붙입니다. diff 크기가 아니라 결과 구조를 판단하세요. | | "버전 범프일 뿐이다" | 범프는 여러분이 쓰지 않은 동작 변경입니다. 변경 이력을 읽으세요. SemVer가 깨지지 않는다고 보장하지는 않습니다. | | "시간을 아끼려고 한 풀 리퀘스트에서 전부 올리겠다" | 빌드를 깨뜨리는 일괄 범프는 어느 패키지가 원인인지 숨깁니다. 변경당 의존성 하나면 원인과 되돌리기가 깨끗하게 남습니다. | ## 레드 플래그 - 리뷰 없이 머지된 풀 리퀘스트 - 테스트 통과만 보는 리뷰 (다른 축은 무시) - 실제 리뷰 근거 없는 "LGTM" - 보안 중심 리뷰 없이 진행된 보안 민감 변경 - "제대로 리뷰하기엔 너무 크다"는 대형 풀 리퀘스트 (나누세요) - 버그 수정 풀 리퀘스트에 회귀 테스트가 없음 - 심각도 라벨이 없는 리뷰 코멘트. 필수와 선택이 불분명해집니다 - "나중에 고칠게요"를 받아들임. 그런 일은 일어나지 않습니다 - 독자가 쥐어야 하는 개념의 수를 줄이지 않고 코드만 옮기는 리팩터 - 분해하지 않고 이미 큰 파일을 키우는 변경 - 관련 없는 코드 경로에 흩어진 새 조건문 (빠진 추상화) - 기존 표준 헬퍼를 복제한 맞춤 헬퍼, 또는 공유 모듈에 놓인 기능 로직 - 변경 이력 리뷰도 패키지별 격리도 없는 일괄 "bump dependencies" 풀 리퀘스트 - 손으로 고쳤거나, 커밋되지 않았거나, diff 리뷰 없이 머지된 락파일 변경 ## 검증 리뷰가 끝난 뒤: - [ ] 모든 Critical 이슈가 해결됨 - [ ] 접두사 없는 필수(Required) 변경이 모두 해결되었거나, 근거와 함께 명시적으로 연기됨 - [ ] 테스트가 통과함 - [ ] 빌드가 성공함 - [ ] 검증 이야기가 문서화됨 (무엇이 바뀌었는지, 어떻게 검증했는지) - [ ] 의존성 업그레이드를 변경 이력과 대조해 리뷰하고, 패키지별로 격리했으며, 락파일 diff를 리뷰한 녹색 스위트로 검증함 **기본 차단 후보:** 다음에 대해서는 더 단순한 설계를 드러내고 제안하세요. 변경이 구조를 적극적으로 더 나쁘게 만들 때만 Required로 올리세요. 복잡성을 줄이는 대신 옮기는 리팩터. 분해 없이 파일을 크기 경계 너머로 미는 변경. 공유 모듈에 추가된 기능 로직. 기존 표준 헬퍼와 거의 같은 복제본. 불명확한 불변 조건을 숨기는 조용한 폴백.