---
name: gosu-review
description: "Go 코드 리팩토링 검토 스킬. 변경된 .go 파일 전체를 읽고 16개 트리거(함수 시그니처, 에러 처리, 에러 타입/값 선언, defer, 슬라이스 메모리, nil/empty, range 순회, 구조체 정의, 동등성 비교, 맵 운용, 인터페이스 선언, 제네릭, 패키지 구조, 수치 연산 등)에 매핑된 43개 룰을 적용해 한국어 마크다운 리뷰 리포트를 생성한다. 린터(golangci-lint)가 커버하는 영역(shadowing, init 제약, 문서화, errors.Is/As, errcheck 등)은 중복 검사하지 않는다. 사용자가 'Go 코드 리뷰', 'Go 리팩토링 검토', 'Go PR 리뷰', '.go 파일 검토'를 요청하거나, 변경된 .go 파일을 제시하며 개선점을 물을 때 사용한다. Go 외 언어, 단순 문법 질문, 빌드/테스트 실행 요청에는 사용하지 않는다."
---

# gosu-review

Go 코드의 변경된 파일을 트리거 기반으로 검토해 한국어 마크다운 리포트를 생성하는 스킬.

## 이 스킬이 하는 일

사용자가 변경된 Go 코드를 주면, **변경된 파일 전체**를 읽고 16개 트리거에 매핑된 43개 리팩토링 룰을 적용해 위반 사항을 찾고 마크다운 리포트로 정리한다. 변경된 라인의 새 위반과 기존 라인의 기존 위반을 분리해서 보고한다.

**린터 영역은 중복 검사하지 않는다.** golangci-lint로 커버되는 룰(Rule 1, 3, 14~17, 22, 38, 49, 52)은 스킬에서 제외. 린터가 못 잡는 **설계 판단 / 맥락 의존 / 보고 대상이 애매한** 룰만 다룬다.

**룰 본문은 이 파일에 없다.** 각 트리거의 룰은 `references/trigger-NN-*.md`에 분리되어 있다. 워크플로우 3단계에서 발동된 트리거의 레퍼런스 파일만 읽어 룰을 적용한다.

## 입력

다음 중 하나의 형태로 받는다:

1. **사용자가 직접 제시한 `.go` 파일들** + (선택) "이번 변경분은 L42-58, L120-135" 같은 변경 라인 정보
2. **git 작업 디렉토리** — `git status`/`git diff`로 변경 파일 식별
3. **PR/diff 텍스트** — 변경 파일과 라인을 추출

확인 사항:
- `_test.go` 파일은 **검토 대상에서 제외** (프로덕션 코드만)
- 삭제된 파일은 제외 (현재 내용 없음)
- 변경 라인 정보가 없으면 사용자에게 물어보거나, 파일 전체를 "변경분"으로 간주

## 워크플로우

### 1단계: 검토 대상 식별
- 변경된 `.go` 파일 목록 확보 (`_test.go` 제외)
- 각 파일의 **현재 전체 내용** 읽기
- 가능하면 변경된 라인 범위 메모

### 2단계: 트리거 스캔 (메인)
파일을 한 번 훑어 어느 트리거가 어디서 발동하는지 인덱스를 만든다. 이 단계에서는 **레퍼런스 파일은 아직 읽지 않는다.** 아래 "트리거 인덱스 표"의 "패턴" 컬럼만 보고 매칭한다.

산출물 예시:
```
handler.go:
  - L12  : T9  (type Order struct)
  - L42  : T1  (func ProcessOrder)  [변경됨]
  - L51  : T2  (if err != nil)      [변경됨]
  - L120 : T6  (var users []User)
```

### 3단계: 처리 모드 결정

| 조건 | 모드 |
|---|---|
| 발동 트리거 ≤ 3 **또는** 총 발동 위치 ≤ 10 | 메인이 직접 순회 |
| 발동 트리거 ≥ 4 **이고** 총 발동 위치 ≥ 11 | 트리거별 서브에이전트 분배 |
| 트리거 14 (패키지/디렉토리 구조) | **항상 메인이 직접 처리** (전역 시야 필요) |

**메인이 직접 처리할 때**: 발동된 트리거 각각의 레퍼런스 파일(아래 표 참고)을 `view` 도구로 읽고 룰 적용.

**서브에이전트에게 줄 것**:
- 해당 트리거의 **레퍼런스 파일 경로** (서브에이전트가 직접 읽도록 지시)
- 발동 위치 목록과 각 위치의 코드 스니펫 (±20줄 컨텍스트)
- 파일 전체 내용 (Rule 25, 41, 29처럼 사용 지점이 멀리 있을 수 있음)
- 변경 라인 메타정보

### 4단계: 룰 적용

각 트리거의 레퍼런스 파일에 있는 검사 절차에 따라 위반 사항을 수집한다. 발견 사항 1건당 다음 필드를 채운다:

- `파일:라인` (예: `handler.go:51`)
- `룰 번호` 및 룰 이름
- `변경 여부` (변경 라인이면 🔴, 기존 라인이면 🟡)
- `근거` — **1문장**. 왜 위반인지 핵심만.
- `제안` — **1줄 요약** (시그니처 변경 / 패턴 이름 / 한 줄 diff 힌트). 코드 스니펫은 원칙적으로 제외. 위반이 비자명하거나 패턴 이름으로 설명 불가할 때만 **최대 5줄**(변경 후 형태만, before/after 분리 금지).

### 5단계: 리포트 통합

같은 위치에 여러 룰이 발동하면 한 항목 아래에 합쳐서 표시. 파일별로 묶고, 파일 안에서는 `🔴 변경 라인` → `🟡 기존 라인` 순으로 정렬. 라인 번호 오름차순.

**트리거 14의 발견**은 리포트 맨 앞 "## 프로젝트 구조" 섹션에 별도 배치.

## 트리거 인덱스

| # | 트리거 | 패턴 / 발동 조건 | 적용 룰 | 레퍼런스 |
|---|---|---|---|---|
| 1  | 함수 시그니처           | `func ...` 선언 (메서드 포함)                                                             | 7, 44, 8, 45, 11, 42, 43 | `references/trigger-01-function-signature.md` |
| 2  | 에러 처리               | `if err != nil` 블록                                                                      | 51, 48                    | `references/trigger-02-error-handling.md` |
| 3  | defer                   | `defer ...`, `recover()`, `panic(...)`                                                    | 46, 35, 47, 53            | `references/trigger-03-defer.md` |
| 4  | 가드 절/중첩 깊이       | `if`/`for`/`switch` 중첩 깊이 ≥ 3                                                        | 2                         | `references/trigger-04-guard-nesting.md` |
| 5  | 슬라이스/문자열 메모리  | `make`, `append`, `copy`, `[low:high]`, `string(`, `[]byte(`, `strings.`, `bytes.`, 루프 내 `+=` 문자열 | 21, 23, 24, 25, 39, 40, 41 | `references/trigger-05-slice-string-memory.md` |
| 6  | nil/empty 선언 및 비교  | `var s []T` / `var m map[K]V`, `len(x)==0`, `x==nil`                                     | 26, 27, 28                | `references/trigger-06-nil-empty.md` |
| 7  | range 순회              | `for ... range ...`                                                                       | 31, 32, 33, 36, 37        | `references/trigger-07-range-iteration.md` |
| 8  | 중첩 루프/switch/select | 중첩된 `for`/`switch`/`select` + `break`/`continue`                                       | 34                        | `references/trigger-08-nested-loop.md` |
| 9  | 구조체 정의             | `type ... struct { ... }`                                                                 | 4, 10                     | `references/trigger-09-struct-definition.md` |
| 10 | 동등성 비교             | `==`, `!=`, `reflect.DeepEqual`                                                           | 30                        | `references/trigger-10-equality.md` |
| 11 | 맵 운용                 | `delete(m, ...)` 또는 장수명 맵 (전역/필드/캐시)                                          | 29                        | `references/trigger-11-map-usage.md` |
| 12 | 인터페이스 선언         | `type ... interface { ... }`                                                              | 5, 6                      | `references/trigger-12-interface-declaration.md` |
| 13 | 제네릭                  | `[T any]`, `[K comparable]` 등 타입 파라미터                                              | 9                         | `references/trigger-13-generics.md` |
| 14 | 패키지/디렉토리 구조    | `package <n>`, 디렉토리 이름                                                           | 12, 13                    | `references/trigger-14-package-structure.md` |
| 15 | 수치 연산               | `+`, `-`, `*`, `/`, float `==`/`!=` 비교, 정수 변환/오버플로 위험 지점                    | 18, 19, 20                | `references/trigger-15-arithmetic.md` |
| 16 | 에러 타입/값 선언       | `var Err... = errors.New/fmt.Errorf`, `type ...Error struct { ... }`                      | 50                        | `references/trigger-16-error-declaration.md` |

> **빠진 룰 번호**(1, 3, 14~17, 22, 38, 49, 52)는 의도적으로 누락된 것이며 린터/포맷터로 커버되는 영역이라 본 스킬 범위 밖이다. 원본 번호를 그대로 보존한다.

## 출력 포맷

발견 1건은 **4줄 고정**(제목 1줄 + 근거 1줄 + 제안 1줄 + 공백 1줄). 서브헤더(`####`)·before/after 코드 블록 사용 금지.

```markdown
# gosu-review 리뷰 리포트

## 요약
- 검토 파일: N개 / 새 위반: M건 / 기존 위반: K건

## 프로젝트 구조
<트리거 14 발견 시만. 3줄 이내 핵심만>

---

## <파일명>

### 🔴 변경 라인
- **L<라인>** `<함수명/심볼>` — [Rule N] <룰 이름>
  - 근거: <1문장>
  - 제안: <1줄. 필요 시 인라인 `코드` 또는 `→ 새 시그니처`>

### 🟡 기존 라인 (참고)
- **L<라인>** `<심볼>` — [Rule N] <룰 이름>
  - 근거: <1문장>
  - 제안: <1줄>

---

## <다른 파일>
...
```

## 부록: 검토 시 일반 원칙

- **확실하지 않으면 보고하지 말 것** — 거짓 양성은 리뷰 가치를 떨어뜨림
- **컨텍스트 부족 시 명시** — "이 함수의 호출처가 보이지 않아 Rule 7 적용 보류" 같은 메모는 OK
- **자동 수정 단정 금지** — 룰별 예외가 많음, 항상 "검토 권장"으로 제안
- **변경 라인 ≠ 단순 라인 번호 비교** — 함수 추가/삭제로 라인이 밀렸을 수 있음. 가능하면 git diff 컨텍스트로 판단

**포맷 예시 (1건)**:
- **L25** `Lookup` — [Rule 8] any 남용
  - 근거: 반환값이 `int`/`string`으로 한정됨.
  - 제안: `(string, bool)` 시그니처로 변경.