semillero-special-hotel/.agents/plugins/harness-plugin/skills/harness/rules/qa-agent-guide.md

12 KiB

QA 서브에이전트 설계 가이드 (Antigravity CLI)

빌드 하네스에 QA 에이전트를 포함할 때 참고하는 가이드. 실제 프로젝트(SatangSlide)에서 발견된 버그 패턴과 그 근본 원인 분석을 바탕으로, QA가 놓치기 쉬운 결함을 체계적으로 잡는 검증 방법론을 제공한다.

참고: 이 가이드는 Antigravity CLI의 플러그인 규격에 대응합니다. 서브에이전트 정의 파일은 .agents/plugins/{plugin-name}/agents/{name}/agent.json으로 위치시킵니다.


목차

  1. QA 서브에이전트가 놓치는 결함의 패턴
  2. 통합 정합성 검증
  3. QA 서브에이전트 설계 원칙
  4. 검증 체크리스트 템플릿
  5. QA 서브에이전트 정의 템플릿 (agent.json)

1. QA 서브에이전트가 놓치는 결함의 패턴

1-1. 경계면 불일치 (Boundary Mismatch)

가장 빈번한 결함. 두 컴포넌트가 각각 "올바르게" 구현되어 있지만, 연결 지점에서 계약이 어긋남.

경계면 불일치 예시 놓치는 이유
API 응답 → 프론트 훅 API가 { projects: [...] } 반환, 훅이 SlideProject[] 기대 각각 개별 검증하면 정상, 교차 비교 안 함
API 응답 필드명 → 타입 정의 API가 thumbnailUrl(camelCase), 타입이 thumbnail_url(snake_case) TypeScript 제네릭으로 캐스팅하면 컴파일러가 못 잡음
파일 경로 → 링크 href 페이지가 /dashboard/create에 있는데 링크가 /create로 지정 파일 구조와 href를 교차 비교하지 않음
상태 전이 맵 → 실제 status 업데이트 맵에 generating_template → template_approved 정의, 코드에서 전환 누락 맵 존재 확인만 하고, 모든 업데이트 코드를 추적하지 않음
API 엔드포인트 → 프론트 훅 API 존재하지만 대응 훅 없음 (호출 안 됨) API 목록과 훅 목록을 1:1 매핑하지 않음
즉시 응답 → 비동기 결과 API가 즉시 { status } 반환, 프론트가 data.failedIndices 접근 동기/비동기 응답 구분 없이 타입만 확인

1-2. 왜 정적 코드 리뷰로 못 잡나

  • TypeScript 제네릭의 한계: fetchJson<SlideProject[]>() — 런타임 응답이 { projects: [...] }여도 컴파일 통과.
  • npm run build 통과 ≠ 정상 동작: 타입 캐스팅, any, 제네릭이 사용되면 빌드는 성공하지만 런타임에 실패.
  • 존재 검증 vs 연결 검증의 차이: "API가 있는가?"와 "API의 응답이 호출측의 기대와 일치하는가?"는 전혀 다른 검증.

2. 통합 정합성 검증

QA 서브에이전트에 반드시 포함해야 하는 교차 비교 검증 영역.

2-1. API 응답 ↔ 프론트 훅 타입 교차 검증

방법: 각 API route의 NextResponse.json() 호출부와 대응 훅의 fetchJson<T> 타입 파라미터를 비교.

검증 단계:
1. API route에서 NextResponse.json()에 전달하는 객체의 shape 추출
2. 대응 훅에서 fetchJson<T>의 T 타입 확인
3. shape과 T가 일치하는지 비교
4. 래핑 여부 확인 (API가 { data: [...] }를 반환하면 훅이 .data를 꺼내는지)

특히 주의할 패턴:

  • 페이지네이션 API: { items: [], total, page } vs 프론트가 배열 기대.
  • snake_case DB 필드 → camelCase API 응답 → 프론트 타입 정의 간 불일치.
  • 즉시 응답 (202 Accepted) vs 최종 결과의 shape 차이.

2-2. 파일 경로 ↔ 링크/라우터 경로 매핑

방법: src/app/ 하위 page 파일의 URL 경로를 추출하고, 코드 내 모든 href, router.push(), redirect() 값과 대조.

검증 단계:
1. src/app/ 하위 page.tsx 파일 경로에서 URL 패턴 추출
   - (group) → URL에서 제거
   - [param] → 동적 세그먼트
2. 코드 내 모든 href=, router.push(, redirect( 값 수집
3. 각 링크가 실제 존재하는 page 경로와 매칭되는지 확인
4. route group 내부 페이지의 URL 접두사 주의 (예: dashboard/ 하위)

2-3. 상태 전이 완전성 추적

방법: 코드에서 모든 status: 업데이트를 추출하여 상태 전이 맵과 대조.

검증 단계:
1. 상태 전이 맵(STATE_TRANSITIONS)에서 허용된 전이 목록 추출
2. 모든 API route에서 .update({ status: "..." }) 패턴 검색
3. 각 전이가 맵에 정의되어 있는지 확인
4. 맵에 정의된 전이 중 코드에서 실행되지 않는 것 식별 (죽은 전이)
5. 특히: 중간 상태(예: generating_template)에서 최종 상태(template_approved)로의 전환이 누락되지 않았는지

2-4. API 엔드포인트 ↔ 프론트 훅 1:1 매핑

방법: 모든 API route와 프론트 훅을 나열하여 짝이 맞는지 확인.

검증 단계:
1. src/app/api/ 하위 route.ts에서 HTTP 메서드별 엔드포인트 목록 추출
2. src/hooks/ 하위 use*.ts에서 fetch 호출 URL 목록 추출
3. API 엔드포인트 중 훅에서 호출하지 않는 것 식별 → "사용 안 됨" 플래그
4. "사용 안 됨"이 의도적인지 (관리 API 등) 아닌지 (호출 누락) 판단

3. QA 서브에이전트 설계 원칙

3-1. 도구 사용에 제한을 두지 않는다

QA 서브에이전트는 Grep으로 패턴 검색, 스크립트 실행으로 자동 대조, 필요 시 수정까지 가능해야 하므로 안전한 읽기/쓰기 도구를 기본적으로 부여한다.

3-2. 체크리스트는 "존재 확인"보다 "교차 비교"를 우선하라

약한 체크리스트 강한 체크리스트
API 엔드포인트가 존재하는가? API 엔드포인트의 응답 shape과 대응 훅의 타입이 일치하는가?
상태 전이 맵이 정의되어 있는가? 모든 status 업데이트 코드가 맵의 전이와 일치하는가?
페이지 파일이 존재하는가? 코드 내 모든 링크가 실제 존재하는 페이지를 가리키는가?
TypeScript strict mode인가? 제네릭 캐스팅으로 우회된 타입 안전성이 없는가?

3-3. "양쪽을 동시에 읽어라" 원칙

QA가 경계면 버그를 잡으려면, 한쪽만 읽어선 안 된다. 반드시:

  • API route 대응 훅을 같이 읽고
  • 상태 전이 맵 실제 업데이트 코드를 같이 읽고
  • 파일 구조 링크 경로를 같이 읽어야 한다.

서브에이전트 정의에 이 원칙을 명시적으로 기재하라.

3-4. QA는 빌드 후가 아니라, 각 모듈 완성 직후에 실행하라

오케스트레이터에서 QA를 "Phase 4: 전체 완성 후"에만 배치하면 버그가 누적되어 디버깅 비용이 높아진다. 매 백엔드 API 및 기능 완성 직후 즉시 해당 API + 대응 훅의 교차 검증을 병렬 또는 순차적으로 실행하라 (Incremental QA).


4. 검증 체크리스트 템플릿

QA 서브에이전트 정의에 포함할 웹 애플리케이션용 통합 정합성 체크리스트.

### 통합 정합성 검증 (웹 앱)

#### API ↔ 프론트엔드 연결
- [ ] 모든 API route의 응답 shape과 대응 훅의 제네릭 타입이 일치
- [ ] 래핑된 응답({ items: [...] })은 훅에서 unwrap하는지 확인
- [ ] snake_case ↔ camelCase 변환이 일관되게 적용
- [ ] 즉시 응답(202)과 최종 결과의 shape이 프론트에서 구분되는지 확인
- [ ] 모든 API 엔드포인트에 대응하는 프론트 훅이 존재하고 실제로 호출됨

#### 라우팅 정합성
- [ ] 코드 내 모든 href/router.push 값이 실제 page 파일 경로와 매칭
- [ ] route group ((group))이 URL에서 제거되는 것을 고려한 경로 검증
- [ ] 동적 세그먼트([id])가 올바른 파라미터로 채워지는지 확인

#### 상태 머신 정합성
- [ ] 정의된 모든 상태 전이가 코드에서 실행됨 (죽은 전이 없음)
- [ ] 코드의 모든 status 업데이트가 전이 맵에 정의됨 (무단 전이 없음)
- [ ] 중간 상태에서 최종 상태로의 전환이 누락되지 않음
- [ ] 프론트에서 상태 기반 분기(if status === "X")의 X가 실제 도달 가능

#### 데이터 흐름 정합성
- [ ] DB 스키마 필드명과 API 응답 필드명의 매핑이 일관됨
- [ ] 프론트 타입 정의와 API 응답의 필드명이 일치
- [ ] 옵셔널 필드에 대한 null/undefined 처리가 양쪽에서 일관됨

5. QA 서브에이전트 정의 템플릿 (agent.json)

빌드 하네스의 QA 에이전트 생성 시 활용하는 agent.json 파일 템플릿.

{
  "name": "qa-inspector",
  "description": "QA 검증 전문가. 스펙 준수, 통합 정합성, 디자인 품질을 검증.",
  "hidden": false,
  "config": {
    "customAgent": {
      "systemPromptSections": [
        {
          "title": "Agent System Instructions",
          "content": "당신은 Antigravity CLI의 전문 서브에이전트 'qa-inspector'입니다.\n\n## 핵심 역할\n스펙 대비 구현 품질과 **모듈 간 통합 정합성**을 집중 검증합니다.\n\n## 검증 우선순위\n1. **통합 정합성** (가장 높음) — 경계면 불일치가 런타임 에러의 주요 원인\n2. **기능 스펙 준수** — API/상태머신/데이터모델\n3. **디자인 품질** — 색상/타이포/반응형\n4. **코드 품질** — 미사용 코드, 명명 규칙\n\n## 검증 방법: \"양쪽 동시 읽기\"\n경계면 검증은 반드시 **양쪽 코드를 동시에 열어** 교차 비교합니다:\n- API 응답 shape: `route.ts`의 NextResponse.json() **및** `hooks/`의 fetchJson<T>\n- 라우팅: `src/app/` page 파일 경로 **및** href, router.push 값\n- 상태 전이: STATE_TRANSITIONS 맵 **및** `.update({ status })` 코드\n- DB → API → UI: 테이블 컬럼명 **및** API 응답 필드 → 타입 정의\n\n## 입력/출력 프로토콜\n- 입력: 검증 대상 코드베이스 경로, 스펙 문서\n- 출력: 검증 리포트 (`_workspace/qa_report.md`)\n  * 통과/실패/미검증 항목을 아이콘으로 구분하여 기재할 것.\n  * 실패 항목은 구체적 파일:라인 정보와 함께 명확한 수정 제안 코드를 포함할 것."
        }
      ],
      "toolNames": [
        "view_file",
        "write_to_file",
        "replace_file_content",
        "list_dir",
        "grep_search",
        "run_command"
      ],
      "systemPromptConfig": {
        "includeSections": [
          "user_information",
          "skills",
          "messaging",
          "artifacts",
          "user_rules"
        ]
      }
    }
  }
}

실제 사례: SatangSlide에서 발견된 버그

이 가이드의 모든 내용은 아래 실제 버그에서 추출한 교훈이다.

버그 경계면 원인
projects?.filter is not a function API→훅 API가 {projects:[]} 반환, 훅이 배열 기대
대시보드 모든 링크 404 파일경로→href /dashboard/ 접두사 누락
테마 이미지 안 보임 API→컴포넌트 thumbnailUrl vs thumbnail_url
테마 선택 저장 안 됨 API→훅 select-theme API 존재, 훅 없음
생성 페이지 영원히 대기 상태전이→코드 template_approved 전이 코드 누락
data.failedIndices 크래시 즉시응답→프론트 백그라운드 결과를 즉시 응답에서 접근
완료 후 슬라이드 보기 404 파일경로→href /projects//dashboard/projects/