Skip to content

[Refactor] RoutineTTSWarmupCoordinator에서 값 타입과 바인딩 검증을 떼어낸다 - #234

Merged
MinHeokChoi merged 2 commits into
mainfrom
refactor/tts-warmup-split
Sep 23, 2026
Merged

MinHeokChoi merged 2 commits into
mainfrom
refactor/tts-warmup-split

Conversation

@MinHeokChoi

Copy link
Copy Markdown
Contributor

✨ PR 유형

어떤 변경 사항이 있나요??

  • 코드 리팩토링
  • 테스트 추가, 테스트 리팩토링
  • 파일 혹은 폴더명 수정

스택 PR 2/5 · base: refactor/active-routine-weekday-policy

🛠️ 작업내용

[Refactor] RoutineTTSWarmupCoordinator에서 값 타입과 바인딩 검증을 떼어낸다

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

규모 — 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

MinHeokChoi and others added 2 commits September 12, 2026 21:42
"활성 루틴끼리 요일이 겹치면 안 된다"가 두 곳에 각자 구현돼 있었다.
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>
@coderabbitai

coderabbitai Bot commented Sep 12, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: a683ead8-57b3-4e59-8823-ef93afc40bef


Comment @coderabbitai help to get the list of available commands.

@MinHeokChoi
MinHeokChoi changed the base branch from refactor/active-routine-weekday-policy to main September 23, 2026 23:57
@MinHeokChoi
MinHeokChoi merged commit 9506d95 into main Sep 23, 2026
5 checks passed
@MinHeokChoi
MinHeokChoi deleted the refactor/tts-warmup-split branch September 23, 2026 23:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant