fix(creator): 구매완료 배지를 제거한다

This commit is contained in:
Yu Sung
2026-08-10 16:39:23 +09:00
parent 00c40161c9
commit a845b54f0f
4 changed files with 184 additions and 16 deletions

View File

@@ -67,10 +67,6 @@ struct CreatorChannelCommunityPostDetailContentView: View {
} }
Spacer(minLength: 0) Spacer(minLength: 0)
if detail.price > 0 && detail.existOrdered && isOwnPost == false {
purchaseCompleteTag
}
} }
} }
@@ -144,16 +140,6 @@ struct CreatorChannelCommunityPostDetailContentView: View {
} }
} }
private var purchaseCompleteTag: some View {
Text("구매완료")
.appFont(size: 12, weight: .medium)
.foregroundColor(Color.black)
.padding(.horizontal, SodaSpacing.s8)
.padding(.vertical, SodaSpacing.s4)
.background(Color.soda400)
.clipShape(Capsule())
}
private var reactionBar: some View { private var reactionBar: some View {
HStack(spacing: 15) { HStack(spacing: 15) {
if detail.isCommentAvailable { if detail.isCommentAvailable {

View File

@@ -368,6 +368,41 @@
- 하트 tap 시 기존 좋아요 API가 호출되고 icon/count가 갱신된다. - 하트 tap 시 기존 좋아요 API가 호출되고 icon/count가 갱신된다.
- 실행 후 이 문서의 `검증 기록` 섹션에 실행 일자, 명령, 결과를 누적한다. - 실행 후 이 문서의 `검증 기록` 섹션에 실행 일자, 명령, 결과를 누적한다.
### Phase 8: 구매완료 배지 제거
**Phase 결과:** 구매한 유료 커뮤니티 게시글 상세에서 `구매완료` 배지가 표시되지 않고 기존 잠금·구매·상세 콘텐츠 흐름은 유지된다.
**선행조건:** PRD `DEC-001` 확정.
#### Task 8.1 구매완료 배지 렌더링 제거
**Goal 실행 `P8-T1`:** 상세 콘텐츠의 구매완료 배지만 최소 범위로 제거한다.
- **완료 증거:** `purchase_badge_absent` contract check 통과, 인접 잠금/reaction contract 유지, `SodaLive-dev` Debug 빌드 성공.
- **범위 밖:** `existOrdered` 모델, 잠금 overlay, 구매 다이얼로그/API, 목록·그리드 UI 변경.
- **TDD 방식:** 테스트 번들 타깃이 없는 현재 저장소 제약에 따라 source contract check를 focused test로 사용한다.
**Files:**
- Modify: `SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift`
- Modify: `docs/20260707_커뮤니티_게시글_상세/prd.md`
- Modify: `docs/20260707_커뮤니티_게시글_상세/plan-task.md`
- [x] **RED:** `purchase_badge_absent` contract check를 정의한다.
- [x] **RED 확인:** `if rg -n 'purchaseCompleteTag|Text\("구매완료"\)' SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift; then exit 1; fi`를 실행해 3개 매치와 exit code 1을 확인한다.
- [x] **GREEN:** header의 구매완료 조건부 렌더링과 `purchaseCompleteTag` computed property를 제거한다.
- [x] **GREEN 확인:** 같은 `purchase_badge_absent` contract check가 매치 없이 exit code 0으로 성공하는지 확인한다.
- [x] **REFACTOR:** 추가 정리 없이 diff가 배지 렌더링 제거로만 제한되는지 확인한다.
#### Task 8.2 회귀 및 빌드 검증
**Goal 실행 `P8-GATE`:** 구매완료 배지 제거와 인접 유료 게시글 흐름 보존을 판정한다.
- [x] `rg -n 'isPaidLocked|Button\(action: onTapPurchase\)|paidLockedOverlay|reactionBar' SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift`에서 잠금·구매·reaction 경로가 유지되는지 확인한다.
- [x] `git diff --check -- docs/20260707_커뮤니티_게시글_상세 SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift`가 성공하는지 확인한다.
- [x] `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build``BUILD SUCCEEDED`로 끝나는지 확인한다.
- [x] 가능한 simulator/API-backed 환경에서 구매한 유료 글의 배지 미표시, 미구매 글의 잠금·가격 표시, 무료 글의 상세 콘텐츠를 확인하고 결과 또는 불가 사유를 검증 기록에 남긴다.
## 검증 기록 ## 검증 기록
- 2026-07-07: `docs/20260707_커뮤니티_게시글_상세/prd.md`, `docs/agent-guides/build-test-verification.md`, 기존 `docs/20260707_글_상세_답글_쓰기/plan-task.md`, `docs/20260705_크리에이터_채널_커뮤니티_탭/plan-task.md`를 확인해 구현 범위와 문서 형식을 정했다. - 2026-07-07: `docs/20260707_커뮤니티_게시글_상세/prd.md`, `docs/agent-guides/build-test-verification.md`, 기존 `docs/20260707_글_상세_답글_쓰기/plan-task.md`, `docs/20260705_크리에이터_채널_커뮤니티_탭/plan-task.md`를 확인해 구현 범위와 문서 형식을 정했다.
@@ -380,3 +415,8 @@
- 2026-07-07: `rg "canReport|onTapReport|showReportError|CreatorChannelActionPopupWithReport|private struct CreatorChannelActionPopup|신고" SodaLive/Sources/V2/CreatorChannel/Community/Detail` 실행 결과 fake report 제거 후 출력이 없음을 확인했다. - 2026-07-07: `rg "canReport|onTapReport|showReportError|CreatorChannelActionPopupWithReport|private struct CreatorChannelActionPopup|신고" SodaLive/Sources/V2/CreatorChannel/Community/Detail` 실행 결과 fake report 제거 후 출력이 없음을 확인했다.
- 2026-07-07: 커뮤니티 댓글 신고 흐름은 기존 `ReportRequest`/`ReportType`에 커뮤니티 댓글 신고 식별자가 없어 연결하지 못했다. 구현은 기존 `CreatorCommunityCommentItemView`의 수정/삭제 popup 동작과 동일하게 맞췄고, fake report action은 노출하지 않는다. - 2026-07-07: 커뮤니티 댓글 신고 흐름은 기존 `ReportRequest`/`ReportType`에 커뮤니티 댓글 신고 식별자가 없어 연결하지 못했다. 구현은 기존 `CreatorCommunityCommentItemView`의 수정/삭제 popup 동작과 동일하게 맞췄고, fake report action은 노출하지 않는다.
- 2026-07-07: 정적 검증과 Debug 빌드 검증은 완료했다. Task 7.3의 device/simulator/API-backed 환경 수동 runtime QA는 아직 수행하지 않았다. - 2026-07-07: 정적 검증과 Debug 빌드 검증은 완료했다. Task 7.3의 device/simulator/API-backed 환경 수동 runtime QA는 아직 수행하지 않았다.
- 2026-08-10: PRD `DEC-001`에 구매완료 배지 제거와 잠금·구매 흐름 유지 범위를 확정했다. 구현 전 `purchase_badge_absent` contract check는 `purchaseCompleteTag``Text("구매완료")` 3개 매치로 exit code 1이 되어 의도한 RED 실패를 확인했다.
- 2026-08-10: header의 구매완료 조건부 렌더링과 `purchaseCompleteTag`만 제거했다. 같은 `purchase_badge_absent` contract check는 0개 매치로 통과했고, `isPaidLocked`, `Button(action: onTapPurchase)`, `paidLockedOverlay`, `reactionBar` 8개 매치가 유지됨을 확인했다.
- 2026-08-10: `git diff --check -- docs/20260707_커뮤니티_게시글_상세 SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift`는 출력 없이 성공했다. `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build``BUILD SUCCEEDED`로 통과했다.
- 2026-08-10: iPhone 16 Pro Simulator에 `SodaLive-dev`를 설치·실행해 앱 홈 화면 진입 screenshot을 확보했다. 상세 화면 직접 수동 QA는 앱 공개 deeplink가 상세가 아닌 커뮤니티 목록으로 이동하고, macOS GUI 자동화는 Apple Events 권한 `-1743`으로 차단되며, 사용자가 LLDB 기반 주입 검증을 건너뛰라고 지시해 수행하지 않았다. 따라서 실제 API-backed 구매/미구매/무료 상세 화면의 pixel QA는 미검증으로 남기고, source contract·Debug build·앱 launch smoke로 대체했다.
- 2026-08-10: 리뷰 리포트 `docs/20260707_커뮤니티_게시글_상세/reviews/phase8-remove-purchase-complete-badge.md`를 작성했다. 초기 리뷰에서 회귀 검색 매치 수 기록 불일치가 확인되어 8개로 정정했고, 같은 Oracle 리뷰 세션의 재검증에서 PASS, blocker 없음 판정을 받았다.

View File

@@ -149,7 +149,8 @@ data class CreatorChannelCommunityRepliesResponse(
- `createdAtUtc`는 기존 `DateParser.relativeTimeText(fromUTC:fallback:now:)` 계열 helper로 상대 시간으로 표시한다. - `createdAtUtc`는 기존 `DateParser.relativeTimeText(fromUTC:fallback:now:)` 계열 helper로 상대 시간으로 표시한다.
- `price > 0 && existOrdered == false && isOwnPost == false`이면 유료 미구매 잠금 상태로 표시한다. - `price > 0 && existOrdered == false && isOwnPost == false`이면 유료 미구매 잠금 상태로 표시한다.
- 유료 미구매 잠금 상태는 Figma처럼 `gray800` 계열 이미지 영역, 잠금 아이콘, 캐시 가격 capsule을 표시한다. - 유료 미구매 잠금 상태는 Figma처럼 `gray800` 계열 이미지 영역, 잠금 아이콘, 캐시 가격 capsule을 표시한다.
- 구매 완료 상태는 Figma `290:9266`처럼 `구매완료` capsule tag를 표시한다. - ~~구매 완료 상태는 Figma `290:9266`처럼 `구매완료` capsule tag를 표시한다.~~ 2026-08-10 요구사항 변경으로 폐기한다.
- 구매한 유료 게시글은 콘텐츠 접근 상태만 유지하고 `구매완료` 배지를 표시하지 않는다.
- 이미지가 있고 접근 가능한 게시글이면 이미지 또는 GIF를 표시한다. - 이미지가 있고 접근 가능한 게시글이면 이미지 또는 GIF를 표시한다.
- `audioUrl`이 있으면 기존 커뮤니티 오디오 재생 흐름을 재사용해 이미지 중앙에 재생 버튼을 표시한다. - `audioUrl`이 있으면 기존 커뮤니티 오디오 재생 흐름을 재사용해 이미지 중앙에 재생 버튼을 표시한다.
- `isPinned == true`이면 기존 커뮤니티 탭의 pinned 표시 규칙을 따른다. - `isPinned == true`이면 기존 커뮤니티 탭의 pinned 표시 규칙을 따른다.
@@ -248,6 +249,7 @@ data class CreatorChannelCommunityRepliesResponse(
- 커뮤니티 게시글 item tap 시 상세 화면으로 진입한다. - 커뮤니티 게시글 item tap 시 상세 화면으로 진입한다.
- 상세 진입 시 `GET /api/v2/creator-channels/community-posts/{postId}`가 호출된다. - 상세 진입 시 `GET /api/v2/creator-channels/community-posts/{postId}`가 호출된다.
- 상세 API 응답으로 게시글 본문, 이미지/오디오/잠금 상태, 좋아요 수, 댓글 수, 초기 댓글 목록이 표시된다. - 상세 API 응답으로 게시글 본문, 이미지/오디오/잠금 상태, 좋아요 수, 댓글 수, 초기 댓글 목록이 표시된다.
- 구매한 유료 게시글 상세의 우측 상단에 `구매완료` 배지가 표시되지 않는다.
- 댓글 추가 로딩 시 `GET /api/v2/creator-channels/community-posts/{postId}/comments?page={page}&size=20`가 호출된다. - 댓글 추가 로딩 시 `GET /api/v2/creator-channels/community-posts/{postId}/comments?page={page}&size=20`가 호출된다.
- 댓글의 답글 상세 추가 로딩 시 `GET /api/v2/creator-channels/community-comments/{commentId}/replies?page={page}&size=20`가 호출된다. - 댓글의 답글 상세 추가 로딩 시 `GET /api/v2/creator-channels/community-comments/{commentId}/replies?page={page}&size=20`가 호출된다.
- `isCommentAvailable == false`이면 reaction bar의 댓글 icon/count, 댓글 section, 하단 댓글 입력 바가 표시되지 않는다. - `isCommentAvailable == false`이면 reaction bar의 댓글 icon/count, 댓글 section, 하단 댓글 입력 바가 표시되지 않는다.
@@ -282,7 +284,13 @@ data class CreatorChannelCommunityRepliesResponse(
## 12. Open Questions ## 12. Open Questions
- 해당 없음 - 해당 없음
## 13. Verification Notes ## 13. Decision Log
| 날짜 | ID | 상태 | 결정 | 근거 | 영향 요구사항·Goal |
|---|---|---|---|---|---|
| 2026-08-10 | `DEC-001` | 확정 | 구매한 유료 커뮤니티 게시글 상세에서 `구매완료` 배지를 제거한다. 잠금·구매·구매 후 상세 재조회 흐름은 유지한다. | 사용자 변경 요청과 배지의 단일 렌더링 위치 확인 | Screen layout, Success Criteria, `P8-T1` |
## 14. Verification Notes
- 2026-07-07: Figma `get_design_context``get_screenshot`으로 `290:9243`, `290:9266`을 확인했다. - 2026-07-07: Figma `get_design_context``get_screenshot`으로 `290:9243`, `290:9266`을 확인했다.
- 2026-07-07: `docs/agent-guides/documentation-policy.md``docs/prd/sample-prd.md`를 확인해 신규 PRD 경로와 필수 섹션을 맞췄다. - 2026-07-07: `docs/agent-guides/documentation-policy.md``docs/prd/sample-prd.md`를 확인해 신규 PRD 경로와 필수 섹션을 맞췄다.
- 2026-07-07: 기존 문서 `docs/20260705_크리에이터_채널_커뮤니티_탭/prd.md`, `docs/20260704_크리에이터_채널_팬Talk_탭/prd.md`, `docs/20260707_글_상세_답글_쓰기/prd.md`를 확인했다. - 2026-07-07: 기존 문서 `docs/20260705_크리에이터_채널_커뮤니티_탭/prd.md`, `docs/20260704_크리에이터_채널_팬Talk_탭/prd.md`, `docs/20260707_글_상세_답글_쓰기/prd.md`를 확인했다.
@@ -290,3 +298,5 @@ data class CreatorChannelCommunityRepliesResponse(
- 2026-07-07: 기존 mutation 재사용 후보로 `CreatorCommunityRepository.communityPostLike`, `createCommunityPostComment`, `modifyComment`, `getCommunityPostDetail`, `getCommunityPostCommentList`, `getCommentReplyList`를 확인했다. 신규 V2 조회 API는 path/page 기준이 달라 V2 API에 별도 추가가 필요하다. - 2026-07-07: 기존 mutation 재사용 후보로 `CreatorCommunityRepository.communityPostLike`, `createCommunityPostComment`, `modifyComment`, `getCommunityPostDetail`, `getCommunityPostCommentList`, `getCommentReplyList`를 확인했다. 신규 V2 조회 API는 path/page 기준이 달라 V2 API에 별도 추가가 필요하다.
- 2026-07-07: 사용자 확인 사항을 반영해 댓글/답글 응답에 `writerId`를 추가하고, 댓글 쓰기 UI의 기존 비밀댓글 toggle 유지, 전송 버튼 icon의 `ic_arrow_up_gray`/`ic_arrow_up_white` 매핑, 댓글 불가능 게시글의 댓글 icon/count 숨김 정책을 확정했다. - 2026-07-07: 사용자 확인 사항을 반영해 댓글/답글 응답에 `writerId`를 추가하고, 댓글 쓰기 UI의 기존 비밀댓글 toggle 유지, 전송 버튼 icon의 `ic_arrow_up_gray`/`ic_arrow_up_white` 매핑, 댓글 불가능 게시글의 댓글 icon/count 숨김 정책을 확정했다.
- 2026-07-07: 기존 커뮤니티 댓글과 동일하게 수정은 작성자에게만, 삭제는 작성자 또는 게시글 크리에이터에게 제공하는 권한 규칙을 반영했다. 커뮤니티 댓글 신고는 기존 `ReportRequest`/`ReportType`에 커뮤니티 댓글 신고 식별자가 없고 기존 `CreatorCommunityCommentItemView`도 신고를 노출하지 않아 [blocked]로 정정했다. - 2026-07-07: 기존 커뮤니티 댓글과 동일하게 수정은 작성자에게만, 삭제는 작성자 또는 게시글 크리에이터에게 제공하는 권한 규칙을 반영했다. 커뮤니티 댓글 신고는 기존 `ReportRequest`/`ReportType`에 커뮤니티 댓글 신고 식별자가 없고 기존 `CreatorCommunityCommentItemView`도 신고를 노출하지 않아 [blocked]로 정정했다.
- 2026-08-10: `CreatorChannelCommunityPostDetailContentView.swift`에서 `purchaseCompleteTag`가 구매완료 배지의 유일한 렌더링 위치임을 확인했다. `isPaidLocked`, `paidLockedOverlay`, 구매 다이얼로그와 구매 API 흐름은 별도이므로 변경 범위에서 제외했다.
- 2026-08-10: `purchase_badge_absent` contract check를 구현 전에 실행했고 `purchaseCompleteTag``Text("구매완료")` 3개 매치로 의도한 RED 실패를 확인했다.

View File

@@ -0,0 +1,132 @@
# 코드 리뷰 보고서: Phase 8 구매완료 배지 제거
## 1. 리뷰 정보
| 항목 | 내용 |
|---|---|
| 리뷰 대상 | Phase 8 / `P8-T1`, `P8-GATE` |
| 기준 commit 또는 working tree | uncommitted working tree |
| 리뷰 일자 | 2026-08-10 |
| 리뷰어 | Oracle reviewer |
| 기준 문서 | `docs/20260707_커뮤니티_게시글_상세/prd.md`, `docs/20260707_커뮤니티_게시글_상세/plan-task.md` |
| 리뷰 상태 | 수정 검증 완료 |
## 2. 리뷰 목적과 범위
### 목적
- 구매한 유료 커뮤니티 게시글 상세에서 `구매완료` 배지만 제거됐는지 확인한다.
- 잠금, 구매, 콘텐츠 접근, 좋아요/댓글 reaction 흐름이 변경되지 않았는지 확인한다.
- PRD와 `plan-task.md`가 변경 요구사항과 검증 결과를 정확히 기록하는지 확인한다.
### 포함 범위
- 코드: `SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift`
- 문서: `docs/20260707_커뮤니티_게시글_상세/prd.md`, `docs/20260707_커뮤니티_게시글_상세/plan-task.md`
- 검증: source contract, `git diff --check`, `SodaLive-dev` Debug build, Simulator launch smoke 기록
### 제외 범위
- 목록·그리드 UI 변경
- 구매 API·모델·상세 조회 흐름 변경
- LLDB 기반 mock 화면 주입 검증
## 3. 판정 기준
| 심각도 | 기준 |
|---|---|
| Blocker | 요청 동작 미충족, 인접 구매/잠금 흐름 회귀, 완료 증거를 무효화하는 문서 오류 |
| High | PRD/계획과 구현 불일치 또는 주요 회귀 위험 |
| Medium | 제한 환경에서 확인되지 않은 runtime 시나리오 |
| Low | 문서 정합성 또는 유지보수성 문제 |
## 4. 검토한 근거
### 문서와 코드
- 요구사항: `prd.md` `DEC-001`, Success Criteria의 구매완료 배지 미표시 항목
- 계획: `plan-task.md` Phase 8 `P8-T1`, `P8-GATE`
- 코드: `CreatorChannelCommunityPostDetailContentView.swift`의 header, `mediaContent`, `paidLockedOverlay`, `reactionBar`, `isPaidLocked`
### 실행한 검증
| 명령 또는 수동 검증 | 결과 | 핵심 증거 |
|---|---|---|
| `rg 'purchaseCompleteTag|Text\("구매완료"\)' ...` | 성공 | GREEN 0 matches |
| `rg -o 'isPaidLocked|Button\(action: onTapPurchase\)|paidLockedOverlay|reactionBar' ...` | 성공 | 8 matches |
| `git diff --check -- docs/20260707_커뮤니티_게시글_상세 SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailContentView.swift` | 성공 | 출력 없음 |
| `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` | 성공 | `** BUILD SUCCEEDED **` |
| Simulator launch smoke | 부분 성공 | 앱 홈 진입 screenshot 확보, 상세 pixel QA는 환경 제약으로 미검증 |
## 5. 발견 사항 요약
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|---|---|---|---|---|---|
| `REV-P8-001` | Low | 수정 완료 | 회귀 검색 매치 수 기록 불일치 | `P8-GATE` | 전환 불필요 |
## 6. 발견 사항 상세
### REV-P8-001 — 회귀 검색 매치 수 기록 불일치
- **심각도:** Low
- **상태:** 수정 완료
- **관련 요구사항:** `DEC-001`
- **관련 계약:** 해당 없음
- **소유 Task:** `P8-GATE`
**관찰 내용**
초기 리뷰에서 `plan-task.md`는 잠금·구매·reaction 회귀 검색 결과를 7개 매치로 기록했지만, 실제 `rg -o` 기준 결과는 8개 매치였다.
**근거**
- 문서: `docs/20260707_커뮤니티_게시글_상세/plan-task.md`
- 검증: `rg -o 'isPaidLocked|Button\(action: onTapPurchase\)|paidLockedOverlay|reactionBar' ... | wc -l` 결과 `8`
**재현 또는 검증 절차**
1. 회귀 검색 명령을 `-o` 옵션으로 실행한다.
2. `wc -l`로 매치 수를 센다.
3. 실제 결과 `8`과 문서 기록이 일치하는지 확인한다.
**영향**
구현 동작에는 영향이 없지만, 완료 증거의 숫자 기록이 부정확했다.
**권장 조치**
`plan-task.md`의 회귀 검색 매치 수를 8개로 정정한다.
**판정 기록**
- 2026-08-10 — 실제 매치 수 8개로 확인하고 `plan-task.md` 기록을 정정했다.
- 2026-08-10 — Oracle 재리뷰에서 PASS, blocker 없음 판정을 받았다.
## 7. 확정 항목의 plan·goal 전환
전환 항목 없음. 문서 숫자 정정으로 완료됐고 신규 코드 회귀 수정 Task는 필요하지 않다.
## 8. 리뷰 종료 판정
| 판정 항목 | 결과 | 근거 |
|---|---|---|
| 리뷰 범위 전체 확인 | 충족 | Oracle reviewer가 대상 3개 파일 diff와 검증 증거 확인 |
| 후보 항목 판정 완료 | 충족 | `REV-P8-001` 수정 완료 |
| 확정 항목 plan 반영 | 해당 없음 | 신규 회귀 Task 불필요 |
| 보류 항목의 담당·재개 조건 기록 | 충족 | 상세 pixel QA 미검증 사유를 `plan-task.md`에 기록 |
| 검증 명령과 결과 기록 | 충족 | source contract, diff check, build, simulator smoke 기록 |
**최종 결론:** 수정 검증 완료
**남은 항목:** 실제 API-backed 구매/미구매/무료 상세 화면 pixel QA는 별도 조작 수단 또는 테스트 계정/데이터가 있을 때 수행한다.
## 9. 수정 후 검증 기록
### 1차 수정 검증 — 2026-08-10
- 무엇을: `REV-P8-001` 문서 매치 수 기록을 8개로 정정했다.
- 왜: 실제 회귀 검색 결과와 검증 기록을 일치시키기 위해서다.
- 어떻게:
- `rg -o 'isPaidLocked|Button\(action: onTapPurchase\)|paidLockedOverlay|reactionBar' ... | wc -l` — 성공, `8`
- Oracle 재리뷰 — PASS, blocker 없음
- 남은 항목: 실제 상세 화면 pixel QA는 환경 제약으로 미검증