게임QA(주)좀비메이트김윤수
스테이지 QA 에이전트화, 오집계 3건을 잡았다
마이스티커팝 스테이지 20개의 난이도 QA를 Claude와 한 번 하고, 그 방법을 QA 에이전트 4종으로 만들어 다시 돌렸다. 2차에서 1차의 배치 수 오집계 3건이 드러나 최대 허들 스테이지가 바뀌었다.
시간 근거 · 스티커 퍼즐 게임 스테이지 난이도·플레이타임 QA (1차 20개, 2차 1–17)
- AI 전 예상
- 40시간 — 기획자 1명 5일. 3회 플레이 8.4 + 스티커·체인 집계 10 + 정리·문서화 8 + 보완 4 + 재검증 플레이 2.8 + 스티커 568개 직관성 판정 7 = 약 40
- 실 작업
- 10.5시간 — 1차 QA 2.5 + 2차 QA 8. 시간을 따로 재지 않아 커밋 시각으로 역산한 값. 에이전트 제작·보완 시간은 제외
- 절감
- 29.5시간 (−74%)
문제
CPI 테스트 지표가 낮게 나온 퍼즐 게임에서, 스테이지 20개 중 어디가 왜 어려운지 어떻게 찾을까?
마이스티커팝은 방 그림에 가구 스티커를 제자리에 붙여 방을 완성하는 게임이다. 1차 CPI 테스트에서 D1 리텐션은 12.79%, 첫날 평균 플레이타임은 769초였다. 테스트 리뷰는 레벨 난이도, 그림자 힌트, 스테이지 순서를 원인으로 지목했다. 그런데 스테이지 단위 이탈 데이터는 없었다. 날짜별 집계만 있었다.
예전 방식이라면 기획자가 스테이지 20개를 직접 여러 번 플레이하며 체감으로 판단했을 것이다. 한 바퀴에 약 2.8시간, 세 번이면 8.4시간이다. 에디터에서 스테이지마다 스티커와 체인 수를 세는 데 10시간, 난이도·플레이타임을 정리해 문서로 만드는 데 8시간, 확인하고 보완하는 데 4시간이 든다. 고친 뒤 한 번 더 플레이해 재검증하고, 2차처럼 스티커 568개의 자리를 하나씩 판정하는 일까지 더하면 한 사람이 5일이다. 그렇게 해도 “이 스테이지는 실제로 몇 개를 붙이는가” 같은 데이터 수준의 착오는 플레이만으로는 보이지 않는다. 이 글의 핵심이 바로 그 착오다.
해결 과정
QA는 두 번 했다. 1차는 Claude Code와 대화하며 했고, 그 방법을 에이전트로 만든 뒤 2차를 돌렸다. 2차는 1차를 똑같이 반복하지 않았다. 1차에서 가장 약했던 부분을 주제로 잡았다.
1차 QA: Claude Code와 대화로 (7월 7일)
게임 저장소를 Claude Code로 열고 작업지시서부터 같이 썼다. 질문은 여섯 개였다. 스테이지별 난이도와
배치 순서, 예상 플레이타임, 초반 적응, 초반 5스테이지 허들, 난이도 급등 구간, 특수 기믹 스테이지다.
데이터는 유니티 프리팹의 배치 목록(_objectArrayList), 스테이지 JSON, 힌트 로직 코드에서 뽑았다.
난이도 모델은 이렇게 잡았다.
난이도 점수 = 수동 배치 수(M) × 공간 예측성(P) × 제시 묶음 계수(B)
P: 실내 1.0 / 반야외 1.3 / 추상 1.4 / 야외 1.5 / 완전오픈 1.7 (배경 아트를 보고 정한 가설값)
플레이타임은 배치 수와 계수로 추정하고, 실측 첫날 플레이타임 769초에 맞춰 역산했다. 결론은 이랬다. 평균 유저는 Stage 2(Bakery) 중간에서 첫날을 끝낸다. 가장 쉬운 Stage 4(WashRoom)에는 도달하지 못한다. 개선 액션 12건을 뽑았고 1순위는 “실내·저난이도 스테이지를 앞으로” 순서 재배열이었다. 1–17스테이지 안에서 최대 허들은 Stage 13 BeachRestaurant(68.0)였다.
한계도 문서에 적었다. P는 방이 실내냐 야외냐만 보고 붙인 숫자였다.
QA 에이전트 4종으로 만들기 (7월 8일)
1차에서 한 일을 네 역할로 나눠 Claude Code 서브에이전트로 정의했다.
- qa-master: 작업지시서를 쓰고 사람 승인을 받은 뒤 아래 셋을 지휘한다.
- balance-qa-analyst: 데이터를 추출하고 분석 문서를 쓴다.
- qa-verifier: 원본 데이터에서 숫자를 다시 계산해 문서와 대조한다. 결과 첫 줄에 PASS 또는 REWORK를 적는다.
- qa-report-builder: 통과한 분석을 팀 공유용 HTML 한 장으로 묶는다.
REWORK가 나오면 분석으로 되돌리고, 두 번 넘게 반복되면 사람에게 올린다. 핵심은 검증 담당을 분석 담당과 분리한 것이다. qa-verifier 정의의 첫 단계는 이렇다(원문).
Pass 1 — Recompute the numbers from source
- Start with upstream inputs that feed multiple outputs or scores (counts, coefficients,
classifications) — an error there propagates into everything downstream, so re-derive
those independently first.
- Re-verify every "for all N stages, X is fixed/true" claim by actually checking all N,
not a sample — iterate the full set programmatically rather than spot-checking.
- Where the report's model uses a hypothesis coefficient (not measured), don't flag the
coefficient itself as wrong — verify the *arithmetic* and the *inputs* feeding it are correct.
2차 QA: 주제를 바꿔 에이전트로 (7월 9–10일)
2차의 주제는 1차의 약점인 P였다. 질문을 “이 방은 실내인가”에서 **“스티커 하나하나의 자리를 보고 알 수 있는가”**로 바꿨다. 스티커마다 직관성 지수를 매기고, 스테이지 평균으로 P를 다시 계산하는 방식이다. 작업지시서에 적은 모델은 이렇다.
LI(스티커) = S × G
S: 의미 분류 (사람이 스프라이트를 보고 태그)
관습형 1.0 — 놓일 자리가 뻔함 (침대·냉장고)
친화형 0.6 — 영역은 있으나 한 점은 아님 (의자·화분)
산포형 0.3 — 관습적 자리 없음 (버섯·덤불·돌)
G: 기하 보정 (프리팹 좌표·스프라이트 크기로 자동 계산, 1.0 중심 ±20% 안팎)
SLI(스테이지) = 수동 배치 스티커 LI의 평균
바로 전수로 가지 않고 Stage 1(Camping)과 Stage 13(BeachRestaurant) 두 곳으로 파일럿을 돌렸다.
처음 세운 선형식(P = a − b × SLI)은 부호가 반대로 나와 불합격했다. 에이전트는 작업지시서 규칙대로
전수 확장을 멈추고 세 가지 대안을 들고 돌아왔다. 그중 방 타입 P를 기준으로 두고 직관성으로 보정하는 안을 골랐다.
P_refined = P_방타입 + 2.0 × (SLI_기준 − SLI)
이 식으로 1–17스테이지를 전수 계산했다. 계산은 서로 다른 구현 두 벌로 돌려 전 행 불일치 0을 확인했고, qa-verifier가 PASS를 줬다. Stage 18–20은 이번 범위에서 뺐다.
1차의 오집계를 찾은 방법
직관성 지수는 스티커 단위로 계산한다. 그래서 스테이지마다 배치 목록을 프리팹에서 하나씩 다시 뽑아야 했다. 분석 에이전트에는 “뽑은 개수를 이전 문서의 총량과 교차 검증한다”는 규칙이 있었고, 여기서 세 곳이 어긋났다.
- Stage 14 (Utohouse): 1차는 체인 스티커(앞 스티커를 붙이면 자동으로 나타나는 스티커) 참조 5건을 서로 다른 5개로 보고, 수동 배치를 23으로 셌다. 실제로는 5건 모두 같은 1개를 가리켰다. 수동 배치는 28이다.
- Stage 15 (Sunflower): 1차는 체인 12개가 46개 안에 들어 있다고 보고 수동 배치를 34로 셌다. 실제로 12개는 배치 목록 밖의 보너스 연출이었다. 수동 배치는 46이다.
- Stage 16 (Cafe): 같은 유형으로 42가 아니라 43이다.
에이전트는 이 차이를 “발견사항”으로 따로 보고했고, 반영은 사람 승인을 받은 뒤에 했다.
결론을 다시 검증하기 (7월 13일)
2차 결과로 스테이지 순서를 다시 정하기 전에 한 번 더 검증을 맡겼다. 입력한 말은 이것이다.
07-09 QA리포트를 기준으로 스테이지 순서 변경을 다시 한번 체크해봐
메인 세션이 이 말을 qa-verifier에게 넘길 때 붙인 지시 중 핵심은 이렇다.
재검증 대상: 스테이지 순서 변경 권고안 (A1)이 2026-07-09 정제 리포트 기준으로도 여전히 타당한지 다시 한번 체크해줘.
...
2. A1 권고 순서가 07-09의 정제 수치로 다시 시뮬레이션했을 때도 "실내 우선 + 저난이도 우선 온보딩" 목표를
실제로 달성하는지 확인 — 재배열 후 난이도 곡선이 완만하게 상승하는지, 6→7 스파이크가 완화되는지.
...
새 분석을 만들거나 리포트를 재작성하지 말고 기존 문서와 소스 데이터 기준으로 검증만 해줘.
qa-verifier는 프리팹 17개에서 배치 수를 다시 세고 난이도·플레이타임을 재계산했다. 도구를 52번 호출했고 15.6분이 걸렸다. 수치 불일치는 0이었다. 대신 1차 개선안이 약속한 효과가 부풀려져 있었다는 점을 찾아냈다. 같은 날 순서 개선안 문서도 검증을 맡겼는데, 이번에는 REWORK가 나왔다. 문서 간 모순 2건과 사실 오류 1건, 구현하면 “이어하기”와 지도 화면이 서로 다른 스테이지를 가리키게 되는 코드 위험 1건 등 8건이었다.
힘들었던 것
- 1차 모델의 핵심 계수가 가설이었다. P를 방 타입으로만 붙였기 때문에 “실내인데 자잘한 장식이 가득한 방”과 “야외인데 큰 구조물뿐인 방”을 구분하지 못했다. 2차가 이 문제에서 출발했다.
- 2차 파일럿이 처음 세운 공식으로는 실패했다. 에이전트가 그대로 밀고 나가 17스테이지를 계산했다면 틀린 숫자가 전부에 퍼졌을 것이다. “파일럿 통과 시에만 전수 확장”을 작업지시서에 적어 둔 것이 여기서 작동했다.
- 에이전트가 처음에는 제대로 돌지 않았다. 정의 파일 설명에 콜론과 공백(
:)이 들어가자 YAML 파싱이 깨져 에이전트 두 개가 조용히 등록되지 않았다. 서브에이전트는 사람에게 직접 질문할 수 없어서, 확인이 필요한 지점을 메인 세션으로 돌려보내게 바꿨다. 스테이지 여러 개를 한 번에 맡기면 중간에 끊겨서, 몇 개씩 나눠 맡기고 매번 파일에 저장하게 했다. 모두 2차를 돌리며 겪고 그날 정의에 반영했다. - 검증 에이전트도 틀렸다. 7월 13일 qa-verifier는 “Circus의 JSON 총량 31과 프리팹 배치 목록 27개가 달라 데이터 버그”라고 보고했다. 그런데 1차 추출표와 2차 발견사항 모두 31을 “수동 27 + 체인 4”로 기록하고 있었다. 체인을 빼고 비교해서 생긴 오탐으로 본다. 진짜 문제는 개수가 아니라 Circus는 총량에 체인을 넣고 Stage 14·15·16은 빼는, 섞인 집계 규약이다. 검증 결과도 원본 데이터로 한 번 더 봐야 한다.
- 숫자는 여전히 추정이다. 스테이지별 이탈 데이터가 없어서 플레이타임과 보정 계수 2.0은 모두 가정이다. 에이전트가 계산을 정확하게 해 줘도 입력이 가정이면 결론도 가정이다. 문서마다 이 점을 명시했다.
결과
- 1–17스테이지의 최대 허들이 바뀌었다. 1차는 BeachRestaurant(68.0)였고, 2차는 Sunflower(70.38)였다. Sunflower는 1차 허들 목록에서 51.0점으로 4번째에 있었다. 증가분의 93%가 배치 수 정정에서 나왔다. 1차의 “체인 12개가 난이도를 완화한다”는 해석도 반대로 뒤집혔다.
- 순서 재배열 권고는 유지하되, 기대치는 낮췄다. 가장 쉬운 곳은 여전히 WashRoom(17.62)이고 현재 1번 Camping(30.10)은 쉽지 않다. 다만 재검증 결과 첫날 끝까지 깨는 스테이지는 1개에서 3개가 아니라 2개로 늘어난다.
- 부산물도 나왔다. 게임에 배치되지 않는 고아 자산 10개, 스프라이트 복제·명명 문제 2건, 개선안 문서의 코드 위험 1건이다.
- 사람의 일이 바뀌었다. 프리팹을 세고 17개 스테이지를 재계산하는 일은 에이전트가 한다. 사람은 모델 방향을 고르고, 발견사항을 승인하고, 오탐을 가려낸다.
- 다음 단계. 이 QA 결과를 받아 스테이지를 고치는 레벨 디자인 에이전트를 같은 방식으로 만들었다. 추정치를 실측으로 바꾸려고 스테이지별 시작·클리어·이탈 이벤트를 수집하는 작업도 시작했다.

