# Phase 3 ViewModel 상태와 API 호출 리뷰 ## 1. 리뷰 정보 | 항목 | 내용 | |---|---| | 리뷰 대상 | Phase 3 / Task 3.1~3.4 | | 기준 commit 또는 working tree | `f600d10e8b63b6fdc812b18a874b077dfe072ca8` + 2026-07-31 working tree | | 리뷰 일자 | 2026-07-31 | | 리뷰어 | Codex | | 기준 문서 | 대상 `prd.md`, `plan-task.md` | | 리뷰 상태 | 수정 검증 완료 | ## 2. 리뷰 목적과 범위 ### 목적 - Loading, success/login-required/error와 optional header 흐름이 구현·테스트에서 일치하는지 확인한다. - 완료 기록이 주장하는 상태 발행 순서가 실제 assertion으로 보호되는지 확인한다. ### 포함 범위 - `HomeFollowingViewModel.kt`, DI 등록, `HomeFollowingViewModelTest.kt` ### 제외 범위 - Fragment rendering과 pull refresh UI. ## 3. 판정 기준 - 확정 상태 전환 요구사항 위반은 High, 기능은 맞지만 완료 증거가 누락된 검증 문제는 Low로 판정했다. ## 4. 검토한 근거 ### 문서와 코드 - `HomeFollowingViewModel.kt:38-78` - `HomeFollowingViewModelTest.kt:56-65`, `67-128` - Task 3.1의 “loading 후 content 상태를 발행한다” 테스트 케이스와 Task 3.2 완료 기록 ### 실행 환경 ```text OS: Darwin 25.0.0 x86_64 JDK: OpenJDK 17.0.15 Gradle wrapper: 8.14.3 ``` ### 실행한 검증 | 명령 | 결과 | 핵심 증거 | |---|---|---| | `./gradlew --no-daemon :app:testDebugUnitTest --tests "...HomeFollowingViewModelTest"` | 성공 | 7개 테스트 실패 0 | | 테스트 assertion 수동 대조 | 문제 확인 | 첫 테스트는 최종 Content와 `isLoading=false`만 확인하고 `Loading` 이력은 수집하지 않음 | ## 5. 발견 사항 요약 | ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal | |---|---|---|---|---|---| | `REV-P3-001` | Low | 수정 완료 | Loading → 결과 발행 순서가 테스트 이름과 완료 기록과 달리 검증되지 않음 | Task 3.4 | `P3-R1` 완료 | ## 6. 발견 사항 상세 ### REV-P3-001 — Loading → 결과 발행 순서가 테스트로 보호되지 않음 - **심각도:** Low - **상태:** 수정 완료 - **관련 요구사항:** Task 3.1 loading 후 content 상태 발행 - **소유 Task:** 신규 Task 3.4 **관찰 내용** production은 `Loading`을 먼저 설정하지만 테스트는 `loadFollowing()` 완료 후 LiveData의 마지막 값만 읽는다. 테스트가 통과해도 `Loading` 발행이 제거되는 회귀를 잡지 못한다. **근거** - 코드: `HomeFollowingViewModel.kt:43-57` - 테스트: `HomeFollowingViewModelTest.kt:56-65` - 문서: Task 3.1, Task 3.2 검증 기록 **재현 또는 검증 절차** 1. `loadFollowing은 loading 후 content 상태를 발행한다` 테스트를 확인한다. 2. observer 이력 수집이나 `Loading` assertion이 없는지 대조한다. 3. 실제 결과는 최종 `Content`와 `isLoading=false`만 검증된다. **영향** 로딩 UI 계약이 회귀해도 Phase 3 focused test와 완료 기록은 계속 PASS할 수 있다. **권장 조치** observer가 수집한 상태 이력을 이용해 `Loading`, `Content` 순서를 한 테스트에서 검증한다. production 변경은 필요하지 않으며, 이미 존재하는 동작의 coverage 보강이므로 의도적인 RED를 만들지 않는다. **판정 기록** - 2026-07-30 — 테스트와 완료 기준을 직접 대조해 확정. - 2026-07-30 — Task 3.4에서 observer 상태 이력 assertion을 추가하고 focused/전체 회귀 PASS로 수정 완료. ## 7. 확정 항목의 plan·goal 전환 - `plan-task.md` Phase 3에 Task 3.4 / `P3-R1`을 추가했다. - objective: `[P3-R1]의 REV-P3-001을 테스트로 고정하고 Phase 3 회귀를 방지한다.` ## 8. 리뷰 종료 판정 | 판정 항목 | 결과 | 근거 | |---|---|---| | 리뷰 범위 전체 확인 | 충족 | ViewModel, DI, test 확인 | | 후보 항목 판정 완료 | 충족 | REV-P3-001 확정 | | 확정 항목 plan 반영 | 충족 | Task 3.4 추가 | | 검증 명령과 결과 기록 | 충족 | focused test 7개 PASS | **최종 결론:** 수정 검증 완료 **남은 항목:** 없음 ## 9. 수정 후 검증 기록 - 2026-07-30: `HomeFollowingViewModelTest`에 observer 상태 이력 assertion을 추가해 `Loading → Content` 발행 순서를 검증했다. production 변경 없이 focused test와 팔로잉 전체 회귀, `git diff --check` PASS. - 2026-07-31 재점검: ViewModel 7개 test와 Phase 1~13 focused 회귀 113개 test, resource merge, Kotlin compile, ktlint PASS. 추가 확정 발견 사항 없음. - 2026-07-31 최종 검증: ViewModel 상태 전이를 포함한 통합 20개 suite·306개 test와 Kotlin compile, ktlint가 PASS했다. 추가 확정 발견 사항 없음. - 2026-07-31 이번 리뷰 재검증: `Loading → Content`, optional auth, login-required, 초기 오류와 refresh fallback 상태를 다시 대조했다. 통합 16개 suite·120개 test와 Kotlin compile·ktlint가 PASS해 추가 확정 발견 사항이 없다.