Repository navigation
[Refactor] RoutineTTSWarmupCoordinator에서 값 타입과 바인딩 검증을 떼어낸다 - #234
Merged
Merged
Conversation
"활성 루틴끼리 요일이 겹치면 안 된다"가 두 곳에 각자 구현돼 있었다. UseCase는 저장 전에 충돌 루틴을 찾아 교체를 묻고(RoutineSettingUseCase), 리포지토리는 저장 트랜잭션 안에서 마지막 방어선으로 다시 검사했다 (SwiftDataRoutineRepository). 지금은 두 구현의 동작이 같다. 확인해 봤다 — saveRoutine이 saveRoutines로 위임하므로 가드가 두 경로를 다 덮고, isEnabled도 isActive를 따라간다. 문제는 살아 있는 버그가 아니라 드리프트다. 한쪽만 고치면 UI는 통과시키는데 저장이 throw하는 상태가 되고, 사용자에게는 저장 버튼이 말없이 안 먹는 것으로 보인다. 원인을 찾기도 어렵다. ActiveRoutineWeekdayPolicy에 판단 기준 하나를 두고 둘 다 위임한다. 두 호출자가 묻는 질문이 다르므로(UseCase는 "누구와 겹치나" — 교체 대상을 보여줘야 하니 ID가 필요하고, 리포지토리는 "겹치는 게 있나") 함수는 둘이되 기준은 하나다. 저장 트랜잭션 자체는 리포지토리에 남는다. 옮긴 것은 정책뿐이라 저장소를 띄우지 않고 규칙을 검증할 수 있게 됐고, 그래서 "두 질문이 같은 답을 낸다"를 테스트로 고정할 수 있었다. Co-Authored-By: Claude <noreply@anthropic.com>
1,975줄 한 파일이었다. 동작은 그대로 두고 이음매 두 곳만 갈랐다. 1. 맨 위 175줄은 코디네이터가 아니라 어휘였다. 폴링 정책 둘과 대기 게이트, 진단 이벤트, 프로토콜 둘. 셋 중 셋(PrefetchPollingPolicy, VoiceSelectionVersionStoring, Diagnostics)은 ServerVoiceCommonAudioProvider와 RemoteFirstRoutineGuidancePlayer도 쓰는 공용 어휘라 코디네이터 파일에 있을 이유가 없었다. 세 파일로 나눴다. RoutineTTSForegroundWaitGate는 private이라 파일을 나누면 안 보인다. 모듈 내부로 올렸다 — 쓰는 쪽은 여전히 코디네이터 하나뿐이다. 2. 바인딩 검증 8개 함수는 코디네이터의 가변 상태를 하나도 건드리지 않고 동기화 저장소만 읽는다. RoutineTTSBindingValidator로 옮겼다. validateCurrentBinding이 중첩 private 타입(PreparedPlan/LocalPlanKey)을 받던 것은 remote ID 두 개로 풀어서 넘긴다. 값어치는 줄 수가 아니라 시험 가능성이다. 이 규칙을 확인하려면 전에는 원격 서비스·오디오 캐시·다운로더·음성 선택 저장소까지 세워 코디네이터를 만들어야 했다. 지금은 동기화 저장소 하나면 된다. 그래서 "남의 루틴 음성이 재생되면 안 된다"를 여섯 가지 상황으로 직접 고정할 수 있었다 — remote ID가 바뀐 경우, 계정이 바뀐 경우, 바인딩이 없는 경우까지. 코디네이터 1,975 → 1,648줄. 스모크 1,055개 통과. Co-Authored-By: Claude <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Comment |
MinHeokChoi
changed the base branch from
refactor/active-routine-weekday-policy
to
main
September 23, 2026 23:57
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
✨ PR 유형
어떤 변경 사항이 있나요??
스택 PR 2/5 · base:
refactor/active-routine-weekday-policy🛠️ 작업내용
[Refactor] RoutineTTSWarmupCoordinator에서 값 타입과 바인딩 검증을 떼어낸다
1,975줄 한 파일이었다. 동작은 그대로 두고 이음매 두 곳만 갈랐다.
맨 위 175줄은 코디네이터가 아니라 어휘였다. 폴링 정책 둘과 대기 게이트,
진단 이벤트, 프로토콜 둘. 셋 중 셋(PrefetchPollingPolicy,
VoiceSelectionVersionStoring, Diagnostics)은 ServerVoiceCommonAudioProvider와
RemoteFirstRoutineGuidancePlayer도 쓰는 공용 어휘라 코디네이터 파일에 있을
이유가 없었다. 세 파일로 나눴다.
RoutineTTSForegroundWaitGate는 private이라 파일을 나누면 안 보인다. 모듈
내부로 올렸다 — 쓰는 쪽은 여전히 코디네이터 하나뿐이다.
바인딩 검증 8개 함수는 코디네이터의 가변 상태를 하나도 건드리지 않고
동기화 저장소만 읽는다. RoutineTTSBindingValidator로 옮겼다.
validateCurrentBinding이 중첩 private 타입(PreparedPlan/LocalPlanKey)을
받던 것은 remote ID 두 개로 풀어서 넘긴다.
값어치는 줄 수가 아니라 시험 가능성이다. 이 규칙을 확인하려면 전에는 원격
서비스·오디오 캐시·다운로더·음성 선택 저장소까지 세워 코디네이터를 만들어야
했다. 지금은 동기화 저장소 하나면 된다. 그래서 "남의 루틴 음성이 재생되면
안 된다"를 여섯 가지 상황으로 직접 고정할 수 있었다 — remote ID가 바뀐 경우,
계정이 바뀐 경우, 바인딩이 없는 경우까지.
코디네이터 1,975 → 1,648줄. 스모크 1,055개 통과.
Co-Authored-By: Claude noreply@anthropic.com
규모 — 6 files changed, 589 insertions(+), 345 deletions(-)
📋 추후 진행 상황
prepareNow(227줄)와prepareForegroundNow(250줄)가 같은 파이프라인을 두 번 구현하고 있습니다. 5번 PR이 그중 겹치는 꼬리를 먼저 처리했고, 앞쪽은 실패 의미가 정당하게 달라 더 살펴봐야 합니다.📌 리뷰 포인트
RoutineTTSForegroundWaitGate의 접근 수준을private→ 모듈 내부로 올렸습니다. 파일을 나누면private은 코디네이터에서 안 보이기 때문입니다. 쓰는 쪽은 여전히 코디네이터 하나뿐입니다.옮긴 타입 중 셋(
RoutineTTSPrefetchPollingPolicy,RoutineTTSVoiceSelectionVersionStoring,RoutineTTSDiagnostics)은ServerVoiceCommonAudioProvider와RemoteFirstRoutineGuidancePlayer도 쓰는 공용 어휘였습니다. 코디네이터 파일에 있던 게 이상한 상태였습니다.✅ Checklist
검증: 시뮬레이터 smoke 1,067개 통과(실패 0, 실기기 전용 3건 skip). 정적 게이트 3종 통과.
앞 PR이 머지되면 이 PR의 base는 자동으로
main이 된다. 순서대로 머지한다.🤖 Generated with Claude Code