QA2 검증 범위 보강 2차 — 미배정 공개 경계 172개 배정 (2026-09-15)
- 기간: 2026-09-15 (세션 1개, 1차에 이어서). 오너 지시 원문 "미배정 경계 172개도 같은 방식으로 2차 보강 진행해줘". 선행 원칙 "QA1의 레거시를 절대 QA2까지 끌고와서는 안됨"(같은 날).
- 랜딩: QA2 main
096eb5a(PR #5, 커밋 8개 = Phase 1~8) · 앱qa2.lock.json갱신은 앱 PR #1626 → 큐 병합eee3aac1(release/v0.19.3; staging·Production 미반영). 마이그레이션·Edge 변경 없음. - 설계서: QA2#4 본문과 Phase 완료 댓글 8건.
- 정본: QA2 승격 게이트(09-15 보강 2차 절), QA2 저장소
docs/verification.md(QA2#4 결과 절)·docs/database.md(시나리오 요약)·catalog.mjs(의무-경계 대응 정본). - 도구: QA2
scenarios/database/의 신규 시나리오 22개,scenarios/database/catalog.mjs·catalog.mjs의 의무·outOfScope갱신. 새 도구는 없음(1차의 커버리지·판정·보고 위에서 진행). - 게이트: QA2
npm run check101/101 · 앱 main157bf12b전체 실행 71개 중 70 통과(1 실패 = 제품 결함 [Barbelic#1624], releaseEligible false) · 앱 precheck(static·unit-1 2107·unit-2 1778 통과) · 큐 Merge Check 통과. 원격 Full CI는 미실행(지시 범위 밖; 다음 승격 PR에서 처음 실행). - 버그리포트: 새로 작성 없음. 유일한 실패는 이미 접수된 앱 이슈 Barbelic#1624(차단당한 계정 삭제 불가). 수리 PR이 병합되면 그때
bug-report/를 작성한다. - 계약: QA2 카탈로그의
surfaces·outOfScope(사유 포함)·retired, 판정의coverage.
Phase 현황
| Phase | 내용 | 상태 |
|---|---|---|
| Phase 1 | 표 격리(앱 권한 표 전수 열거), 소셜 참조가 있는 계정 삭제 | ✅ 06918f6 |
| Phase 2 | 계획 수명주기·가시성 | ✅ 8fe45d9 |
| Phase 3 | 그룹 멤버십·보드·라운지·멤버 세션 | ✅ 9aae76e |
| Phase 4 | 팔로우 게이트·세션 상호작용·알림 | ✅ 3bb60e2 |
| Phase 5 | 조회 정합성(홈·달력·로그 표·볼륨·기록·리포트·세션 상세·검색) | ✅ 7541330 |
| Phase 6 | 프로필·카탈로그·기록·신체·초안·사진 문 | ✅ 80597a5 |
| Phase 7 | 통계 갱신 권한·무결성 검증기·예약 유지보수 | ✅ 8f47ba8 |
| Phase 8 | 전체 실행·QA2 게시·앱 락 반영·문서 | ✅ QA2 096eb5a · 앱 PR #1626 → eee3aac1 |
1. 배경
1차(QA2#2)에서 공개 경계 커버리지라는 분모가 생겼다. 검증 대상 DB에서 로그인 사용자가 부를 수 있는 RPC 문, 앱 계정에 권한이 있는 표, 설치된 예약 작업을 실행 시점에 열거하고, 의무가 선언한 경계(surfaces)와 대조해 의무 있음 / 범위 밖(이유) / 미배정을 보여 준다. 1차 종료 시점 앱 main 기준 공개 경계 208개 중 의무 있음 11·범위 밖 25로, 172개가 미배정으로 남아 있었다. 미배정은 통과가 아니라 아직 약속이 없는 경계다.
2. 문제 제기
미배정 172개(RPC 118·표 47·예약 작업 7)는 QA2가 아직 아무 약속도 검증하지 않는 제품 표면이다. 오너 지시는 이 172개를 "같은 방식으로" — QA1의 케이스·헬퍼·러너·장부를 옮기지 않고, 기록된 제품 실패와 접근 계약의 의미만 QA2의 단위(약속·의무·requiredInputs·대상 지문·교정)로 — 배정하는 것이다.
3. 해결 방안
- 원칙(오너 결정): QA1 레거시 무이관. 시나리오는 계약(friend-access·app-role-privileges·user-fact-immutability)과 기록된 버그의 의미에서만 기대값을 authoring하고, 조회는 조회끼리 비교하지 않고 저장한 사실의 독립 산술과 대조한다.
- 접근: 표면 종류별로 의무를 나눠 8개 Phase로 진행하고, 각 Phase는 개발 DB에서 통과·
npm run check·커밋·보고를 마친 뒤 다음으로 넘어간다. 마지막에 앱 main 전체 실행 1회로 커버리지 0 미배정과 판정을 확인한다.
4. 적용한 내용
- Phase 1~4 — 삭제·격리, 계획, 그룹, 소셜: 표 격리는 앱 권한 표를 실행 시점에 전수 열거해 본인 행만 보이는지, 전역 참조 표는 읽기 전용인지 검사한다. 계정 삭제는 팔로우·차단·초대·댓글·좋아요·그룹 관계가 있어도 되고 상대 원본은 그대로여야 한다 — 이 중 "남이 나를 차단한 경우"가 제품에서 실패했고 [Barbelic#1624]로 접수했다. 계획·그룹·소셜은 각 문의 권한(작성자·주인·멤버·팔로워)과 차단·비회원 거부를 검사한다.
- Phase 5 — 조회 정합성: 한 가상 사용자의 2024년 7월 3회 운동을 저장하고, 손으로 계산한 일별·월별·종목별 수치(일 1220/210/625, 월 8세트·44회·2055, 종목 A 최고 무게 70·5회 기록 60→62.5)와 홈·달력·로그 표·볼륨·기록·리포트·세션 상세·검색을 대조한다.
- Phase 6 — 프로필·카탈로그·기록·초안·사진: 종목 카탈로그와 커스텀 켜고 끄기, 즐겨찾기 교체, 직접 입력 기록(1RM·최대 반복·버티기·거리), 신체 측정·인바디 가져오기, 온보딩·동의·핸들·성별·설정, 클라이언트 오류 진단, 운동 초안(순서 펜스·복구 영수증), 세션 사진(폴더·객체·피드 게이트), 원본 변경 이력 조회.
- Phase 7 — 통계·유지보수: 통계 갱신 문은 본인만, 무결성 검증기는 저장 사실 재계산, 예약 유지보수 5종은 특권 전용·유저 원본 불변. 통계 투영 claim 작업은
db-wide-statistics에 편입, pg_cron 실행 로그 정리는 인프라 하우스키핑으로 범위 밖. - Phase 8 — 앱 main
157bf12b전체 실행, QA2 [PR #5] 병합, 앱 락 [PR #1626] → 큐 병합, 문서.
5. 적용 결과
| 항목 | 전 (1차 종료) | 후 (2차) |
|---|---|---|
| 공개 경계 미배정 | 172 | 0 |
| 배정(claimed) / 범위 밖 | 11 / 25 | 163 / 45 |
| 의무 수 | 38 | 55 |
| 시나리오 수 | 54 | 71 |
| 앱 main 전체 실행 | 43/43 통과 · releaseEligible true | 70/71 통과 · releaseEligible false |
- releaseEligible이 false로 내려간 이유는 QA2가 제품 결함 [Barbelic#1624]를 잡았기 때문이다. 제품을 초록으로 만들려 의무를 완화하지 않았다(원본 불변 원칙과 "제품 실패는 실패로 남긴다"). #1624이 고쳐지기 전까지 release/v0.19.3 → staging 승격은 이 판정에 막힌다.
- 사람 눈으로만 판단할 품질(화면 감각 등)은 이 자동 검증의 대상이 아니다. 통계 워커 문·검증기 일부의
session_user기반 회원 거부는 하네스 한계로 재현하지 못했다(아래 남은 것).
6. 이번 개선으로 향상된 것
- QA2가 검증하는 공개 경계가 11개에서 163개로 늘고 미배정이 0이 됐다. 이제 앱의 회원용 문·표·예약 작업 대부분에 "무엇을 약속하는가"가 QA2 단위로 적혀 있고, 판정이 그 약속 위반을 잡는다.
- 조회 화면이 저장한 사실과 어긋나는 회귀(과거 여러 버그의 유형)를 독립 산술로 잡는다.
- 커버리지가 0 미배정이므로, 앞으로 새 문·표·예약 작업이 추가되면 인벤토리에 나타나 즉시 미배정으로 보이고 약속을 요구한다.
후속 (2026-09-15, 같은 날)
- 제품 결함 [Barbelic#1624] — 앱 트랙이
release/v0.19.34c4a847e(PR #1632)로 수리, 버그 리포트bug-report/bug-148-20260915.md. QA2096eb5a전체 실행으로 확인: 71개 중 70 통과·실패 0·미검증 1(db-wide-100060초 한도 초과 — 로컬 부하, 부하 없이 54.4초 통과). 차단당한 계정 삭제 의무 통과. - 하네스 후속 — QA2 PR #6(
05332518): 배우 작업을 이미지의 비특권 로그인authenticator의 두 번째 연결에서 실행하고, 로그인이 특권이면 미검증으로 거부. 회원 거부 검사 5개 복원(워커 일괄 문 2·검증기 3, 모두 42501). 앱4c4a847e전체 실행 71/71 통과(releaseEligible true, 미배정 0/208, 시나리오 실행 2분 46초, 2026-09-15 05:58Z). 앱 락 갱신 PR #1635 → 큐 병합79026980(release/v0.19.3). 상세는 승격 게이트의 후속 절.
남은 것
- 없음(승격 ① release→staging의 GitHub Full CI에서 QA2 판정 게이트가 처음 실행된다).