---
description: Fundamentals 4원칙 + 근본 원인 + 접근성 + 상태관리 + React 패턴 관점을 병렬로 리뷰하고, 이슈 단위로 합쳐 원칙 충돌까지 판단
argument-hint: "[branch|staged|unstaged|<경로>] [--save]"
allowed-tools: Task, Agent, Skill, Read, Glob, Grep, Write, Bash(git status:*), Bash(git diff:*), Bash(git ls-files:*), Bash(git merge-base:*), Bash(git rev-parse:*), Bash(git symbolic-ref:*), Bash(git branch:*)
---

# Fundamentals 리뷰

Toss Frontend Fundamentals 기준의 여러 관점을 병렬로 실행하고, 결과를 **이슈 단위**로 합쳐서 원칙끼리 부딪히는 제안까지 판단하는 리뷰 커맨드입니다. 리포트는 이슈마다 **문제 → 현재 코드 → 수정 코드 → 해결 → 확인** 순서로 짧게 씁니다.

**인자:** $ARGUMENTS

## 사용 예시

```bash
/fundamentals-review                 # 브랜치 변경 전부 (기본)
/fundamentals-review staged          # git add 한 것만
/fundamentals-review unstaged        # git add 안 한 로컬 변경과 새 파일만
/fundamentals-review src/features    # 경로의 파일 전체 (과제 코드처럼 처음 보는 코드)
/fundamentals-review staged --save   # 결과를 fundamentals-review.md로 저장
```

## 사용 관점

| 관점 | 에이전트 | 실행 조건 |
|------|----------|----------|
| 가독성 | `fundamentals-readability` | 항상 |
| 예측 가능성 | `fundamentals-predictability` | 항상 |
| 응집도 | `fundamentals-cohesion` | 항상 |
| 결합도 | `fundamentals-coupling` | 항상 |
| 근본 원인 | `root-cause-reviewer` | 항상 |
| 접근성 | `a11y-reviewer` | 범위에 `.tsx`·`.jsx` 파일이 있을 때 |
| 상태관리 | `react-state-reviewer` | React 프로젝트일 때 |
| React 패턴 | `react-principles-reviewer` | 범위에 `.tsx`·`.jsx` 파일이 있을 때 |

판단 기준이 되는 스킬: `fe-readability`, `fe-predictability`, `fe-cohesion`, `fe-coupling`(4원칙), `fe-tradeoffs`(원칙 충돌과 예외), `fe-root-cause`, `fe-a11y`, `fe-state`(상태 배치), `fe-react`(React 컴포넌트 패턴). 각 에이전트가 자기 스킬을 미리 불러옵니다.

## 태그

| 태그 | 뜻 | 토스 면접 루브릭 |
|------|----|----------------|
| `코드` | 코드 모습: 가독성·예측 가능성·응집도·결합도, 추상화, 이름, 상태 배치, 컴포넌트 패턴 | ① |
| `부채` | 기술 부채: 데드코드, 같은 일을 두 가지 방식으로 하는 코드, 의존성 중복·미사용, 낡은 API | ② |
| `버그` | 근본 원인: 버그, 증상을 덮는 코드, 조용한 실패 | ③ |
| `UX` | 사용자 경험: 접근성, 사용자에게 보이는 로딩·에러·빈 상태, 입력 흐름 | ④ |
| `n/N` | 실행한 관점 N개 중 이 문제를 지적한 관점 수 | |
| `잠재` | 지금은 일어나지 않지만 조건이 생기면 문제가 됨 | |
| `확인 필요` | 요구사항이나 범위 밖 코드에 따라 문제인지가 달라짐 | |

## 작업 순서

### 1. 인자 해석

- `--save`가 있으면 저장 모드로 표시하고 나머지 토큰을 봅니다.
- 첫 토큰이 `branch` 또는 없음 → **branch** 모드
- `staged` → **staged** 모드
- `unstaged` → **unstaged** 모드
- 그 밖의 값 → **경로** 모드 (그 경로의 파일 전체)

### 2. 리뷰 대상 수집

git 명령은 하나씩 실행하고 결과를 다음 명령에 넣습니다(`$(...)` 치환을 쓰지 않습니다).

**기본 브랜치 찾기** (branch 모드만): `git symbolic-ref --short refs/remotes/origin/HEAD`의 결과(예: `origin/main`)를 씁니다. 실패하면 `git rev-parse --verify main`, 그다음 `master` 순서로 확인합니다.

| 모드 | 변경 파일 목록 | 변경 줄 범위와 지운 줄 |
|------|--------------|-------------|
| branch | `git merge-base <기본 브랜치> HEAD`로 기준 커밋을 구한 뒤 `git diff --name-only <기준 커밋>` + `git ls-files --others --exclude-standard` | `git diff -U0 <기준 커밋>` |
| staged | `git diff --cached --name-only` | `git diff --cached -U0` |
| unstaged | `git diff --name-only` + `git ls-files --others --exclude-standard` | `git diff -U0` |
| 경로 | `Glob`으로 경로 아래 코드 파일 | 파일 전체 |

- branch 모드는 기준 커밋과 **현재 작업 트리**를 비교하므로 커밋, staged, 로컬 변경이 모두 들어갑니다. 새 파일은 `ls-files`로 더합니다.
- 기본 브랜치 위에서 실행하면 아직 커밋하지 않은 변경과 push하지 않은 커밋만 잡힙니다.
- 코드 파일(`.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`, `.cjs`)만 남기고 `node_modules`, `dist`, `build`, `*.d.ts`, lock 파일은 뺍니다.
- 변경 줄 범위는 hunk 헤더 `@@ -a,b +c,d @@`의 `c`부터 `c+d-1`까지입니다. `,d`가 없으면(`+c`) 한 줄입니다. 새 파일은 "전체"로 표시합니다.
- **지운 줄**: 에이전트는 현재 파일만 읽을 수 있어서, 지운 코드는 따로 넘겨야 판단할 수 있습니다. hunk의 `-` 줄을 원래 내용 그대로 "지운 줄"에 적습니다. 가드, 에러 처리, cleanup, 검증을 지운 변경을 잡기 위해서입니다. 한 파일에서 지운 줄이 40줄을 넘으면 앞 40줄만 적고 "외 N줄 삭제"로 줄입니다. 파일을 통째로 지웠으면 "파일 삭제"로만 적습니다.
- 대상이 없으면 "리뷰할 변경이 없습니다"와 함께 다른 모드를 안내하고 끝냅니다.

수집 결과를 아래 **리뷰 범위 블록**으로 만듭니다.

```
리뷰 범위: branch 모드 (기준 origin/main, abc1234)
- src/lib/api-client.ts: 9-12
  지운 줄 (원래 9-11):
    if (!response.ok) {
      throw new HttpError(response.status, message)
    }
- src/hooks/post.ts: 새 파일(전체)
```

### 3. 관점 선택

- 항상: fundamentals 4개 + `root-cause-reviewer`
- 범위에 `.tsx`·`.jsx`가 있으면: `a11y-reviewer`, `react-principles-reviewer`
- `package.json`에 `react` 또는 `next` 의존성이 있으면: `react-state-reviewer`

### 4. 병렬 실행

선택한 에이전트를 **한 메시지에서 동시에** 실행합니다. 에이전트마다 정해진 출력 형식이 있지만, 합치기 쉽도록 이 커맨드에서는 아래 짧은 형식으로 받습니다. 각 에이전트 프롬프트:

````
[리뷰 범위 블록]

위 범위의 코드를 [관점] 관점으로 리뷰하세요.
- 변경된 줄과, 그 변경이 직접 영향을 주는 코드만 이슈로 올리세요. 지운 줄이 있으면 무엇이 사라졌는지도 판단하세요. (경로 모드에서는 범위의 파일 전체가 대상입니다.)
- 이해에 필요하면 범위 밖 파일을 읽어도 됩니다.
- 평소 출력 형식 대신 아래 형식으로만 답하세요. 잘한 점, Metrics, 심각도 분류는 쓰지 마세요. 심각도는 합치는 쪽이 정합니다.

### [이슈 제목]
- 위치: file:line
- 태그: 코드 / 부채 / 버그 / UX 중 해당하는 것. 확신이 낮으면 `잠재` 또는 `확인 필요`와 이유
- 현재 코드: 3~5줄
- 문제: 원인과 결과를 한 문장으로
- 영향: 이 코드를 고치면 동작이 같이 바뀌는 다른 위치 (없으면 생략)
- 수정 코드: 10줄 이내
- 해결: 고치면 무엇이 달라지는지 한 문장
- 확인: 어떻게 해보는지 → 지금 결과 → 고친 뒤 결과
- 원칙 충돌: 다른 원칙과 부딪히면 양쪽 수정안을 사실대로 (판단은 하지 않음)
- 라이브러리 동작: 문제·해결·확인이 라이브러리 동작(TanStack Query, React Hook Form, React Router 등)에 기대면 그 주장을 한 줄로 적기

## 다른 관점 참고
- 내 관점 밖이지만 본 문제를 한 줄씩: 문제 — file:line

## 범위 밖 참고
- (diff 모드에서만) 이번 변경과 무관한 기존 코드의 문제를 한 줄씩: 문제 — file:line
````

### 5. 결과 합치기 (메인이 직접)

먼저 Skill 도구로 `fe-tradeoffs`를 불러옵니다.

1. **같은 문제 묶기**: 위치가 같거나 원인이 같은 지적은 한 이슈로 합칩니다. 이슈로 올렸든 "다른 관점 참고"에 적었든, 그 문제를 언급한 관점 수를 `n`으로 셉니다. 특히 React 패턴 관점은 예측 가능성(부수효과 위치), 근본 원인(Suspense 경계, 요청 경쟁), 상태관리(props와 state)와 겹치기 쉬우니 하나로 묶습니다.
2. **걸러내기**: `fe-tradeoffs`의 "원칙을 깨도 되는 경우"에 해당하는 지적은 빼고, 수정 방법이 "하지 말아야 할 제안"이면 고치거나 뺍니다.
3. **원칙 충돌 판단**: 관점끼리 반대 방향을 제안하면(예: 응집도는 공통화, 결합도는 중복 허용) 그 이슈 안에 **각 원칙의 수정안을 코드로 나란히** 두고, `fe-tradeoffs`의 판단 기준으로 한쪽을 고른 뒤 근거를 한 줄로 남깁니다. 코드만으로 판단할 수 없으면 "확인 필요"와 무엇을 확인해야 하는지 적습니다. 이슈로 올리지 않은 충돌(예: 보류한 상수화)은 "보류한 판단"에 한 줄씩 적습니다.
4. **검증**: 아래는 메인이 직접 확인한 뒤에만 내보냅니다. 틀리면 문장을 고치거나 이슈를 뺍니다.
   - Critical 후보: 해당 `file:line`을 열어 코드와 맞는지 확인합니다. 판단이 범위 밖 코드에 달려 있으면 `확인 필요`를 붙이고 Recommended로 내립니다.
   - 라이브러리 동작에 기대는 문장: 에이전트가 "라이브러리 동작"으로 적은 주장, 그리고 문제·해결·확인 줄에서 라이브러리가 어떻게 동작한다고 말하는 부분은 `node_modules`의 실제 코드나 공식 문서로 확인합니다. 설치된 버전 기준으로 봅니다.
   - 관점끼리 사실을 반대로 말하는 경우: 코드를 열어 어느 쪽이 맞는지 확인합니다.
5. **태그 붙이기**: `코드`·`부채`·`버그`·`UX` 중 해당하는 것을 모두 붙이고, `n/N`(N은 실행한 관점 수)을 붙입니다. 확신이 낮은 이슈에는 `잠재` 또는 `확인 필요`를 붙이고, 이유를 "문제" 줄 끝 괄호에 적습니다.
6. **Critical과 Recommended 나누기**
   - **Critical**: 사용자가 겪는 문제(화면이 틀리게 보임, 잘못된 데이터가 저장됨, 기능을 쓸 수 없음, 실패를 알 수 없음). 또는 `코드` 태그이면서 관점 5개 이상이 지적한 구조 문제(실행한 관점이 8개보다 적으면 60% 이상).
   - `잠재`, `확인 필요`가 붙은 이슈는 Critical에 두지 않습니다.
   - 나머지는 모두 **Recommended**입니다. 간단한 이슈도 같은 형식으로 쓰고, 개수 제한은 두지 않습니다.
7. **정렬**: 각 묶음 안에서 `n`이 큰 것부터, 같으면 `버그`·`UX`가 붙은 것을 먼저 둡니다.
8. **리뷰가 못 보는 것**: 범위에 화면을 그리는 파일(`.tsx`·`.jsx`)이 있으면, 이슈로 잡히지 않았지만 실행해야 알 수 있는 것을 이번 범위에 맞춰 체크박스로 만듭니다. 예: 마우스 커서, 375px 화면의 레이아웃, Tab 키만으로 모든 기능 사용, 느린 네트워크나 요청 실패.

### 6. 출력

아래 형식으로 화면에 출력합니다. 해당 내용이 없는 섹션은 통째로 뺍니다.

`````markdown
# Fundamentals 리뷰 결과

**범위:** [branch (origin/main 대비) | staged | unstaged | 경로] · 파일 N개 · 관점 N개 · Critical X · Recommended Y
> 태그: `코드` 코드 모습 · `부채` 기술 부채 · `버그` 근본 원인 · `UX` 사용자 경험 · `n/N` 지적한 관점 수 · `잠재` 지금은 안 일어나지만 조건이 생기면 문제 · `확인 필요` 요구사항에 따라 다름

## Critical

---

### 1. [이슈 제목]
`버그` `UX` `7/8`

> **문제** [원인과 결과를 한 문장으로]

**현재** `path/to/file.ts:9`
```ts
[현재 코드 3~5줄]
```
**수정**
```ts
[수정 코드 10줄 이내]
```
| | |
|---|---|
| **해결** | [고치면 무엇이 달라지는지] |
| **영향** | `path/a.tsx:85` · `path/b.tsx:13` (다른 곳이 같이 바뀔 때만, 없으면 이 줄을 뺌) |
| **확인** | [어떻게 해보는지] → 지금: [지금 결과] / 고친 뒤: [고친 뒤 결과] |

---

### 2. [원칙 충돌이 있는 이슈]
`코드` `7/8`

> **문제** [한 문장]

**현재** `path/to/file.tsx:30`
```tsx
[현재 코드]
```
**[원칙 A] 안** [수정안 한 줄 설명]
```tsx
[원칙 A의 수정 코드]
```
**[원칙 B] 안** [수정안 한 줄 설명]
```tsx
[원칙 B의 수정 코드]
```
**판단** [택한 쪽]. [근거 한 줄, fe-tradeoffs 판단 기준]
```tsx
[택한 수정 코드]
```
| | |
|---|---|
| **해결** | [한 문장] |
| **확인** | [어떻게 해보는지] → 지금: [...] / 고친 뒤: [...] |

---

## Recommended

---

### 3. [이슈 제목]
`버그` `3/8` `잠재`

[Critical과 같은 형식. 문제 줄 끝에 (잠재: 이유)]

---

## 보류한 판단
- [무엇]: [원칙 A 제안] vs [원칙 B 제안] → 보류. [무엇을 확인해야 하는지]

## 범위 밖 참고 (diff 모드에서만)
- `버그` 문제 — `file:line`

## 리뷰가 못 보는 것 (직접 실행해서 확인)
- [ ] [이번 범위에 맞춘 확인 항목]
`````

### 7. 저장 (`--save`일 때만)

- 저장 모드가 아니면 파일을 만들지 않습니다.
- 저장 모드면 `git rev-parse --show-toplevel`(실패하면 현재 폴더) 아래 `fundamentals-review.md`에 씁니다. 파일이 이미 있으면 기존 내용을 읽고 `---` 구분선 뒤에 이어 붙입니다.

## 중요 사항

- **리뷰만 합니다.** 코드를 고치지 않습니다.
- **병렬 실행:** 관점 에이전트는 한 메시지에서 동시에 실행합니다.
- **짧게:** 문제·해결은 한 문장, 현재 코드는 3~5줄, 수정 코드는 10줄 이내로 씁니다.
- **이슈 구분:** 이슈 사이에 `---`를 넣고, 태그는 제목 아래 줄에 씁니다. 문제는 인용 블록(`>`)으로 제목 바로 아래에, 현재·수정 코드 다음에 해결·영향·확인을 표로 둡니다. 이름표 줄을 빈 줄 없이 이어 쓰면 한 문단으로 합쳐 보이므로 표를 씁니다.
- **file:line 보존:** "현재" 이름표 옆에 위치를 적습니다.
- **한국어 출력:** 최종 리포트는 한국어로 씁니다.
- **AI attribution 금지:** "Generated by AI" 같은 문구를 붙이지 않습니다.
