Skip to content

루틴 생성 동기화 재조정 대기 중 TTS 준비 조기 포기 문제 수정 - #206

Closed
MinHeokChoi wants to merge 11 commits into
mainfrom
fix/routine-tts-reconciliation-pending-binding
Closed

루틴 생성 동기화 재조정 대기 중 TTS 준비 조기 포기 문제 수정#206
MinHeokChoi wants to merge 11 commits into
mainfrom
fix/routine-tts-reconciliation-pending-binding

Conversation

@MinHeokChoi

Copy link
Copy Markdown
Contributor

✨ PR 유형

  • 버그 수정

🛠️ 작업내용

새 루틴 생성 후 "루틴 시작하기"를 눌렀을 때 서버 음성이 완전 무음으로 재생되지 않는 문제를 조사했습니다.

원인은 RoutineTTSWarmupCoordinator의 두 판단 함수 간 불일치였습니다.

  • hasServerSyncIntent(이 루틴이 "서버 전용 음성"인지 판단): createRoutineGroup/addRoutine 뮤테이션 레코드가 어떤 상태로든 존재하기만 하면 서버 의도가 있다고 정확히 판단합니다.
  • hasPendingGroupBinding(루틴 시작 시 바인딩을 더 기다릴지 판단): 내부에서 쓰는 isBindingDeliveryPending.waitingForServerContract/.queued/.attempting만 "대기 중"으로 보고, .needsReconciliation은 대기 중이 아니라고 취급했습니다.

그런데 RoutineSyncSender.sendNext를 보면 .needsReconciliation은 죽은 상태가 아니라 서버 반영 여부가 모호해 자동으로 재확인(reconciliation replay)되는 정상 진행 상태입니다. .blocked만 사용자 개입이 필요한 진짜 종결 상태입니다.

루틴 그룹 생성 요청이 타임아웃/네트워크 문제로 ambiguous 처리되어 .needsReconciliation에 들어가면:

  1. expectsServerGeneratedIntro는 여전히 "서버 음성 필요함"으로 정확히 판단해 prepareAndWait(최대 30초 폴링)로 보내지만
  2. 그 안의 prepareForegroundNowhasPendingGroupBinding false를 보고 즉시 missingGroupBinding을 찍고 .unavailable로 포기해버려, 폴링도 재시도 스케줄도 없이 완전 무음으로 끝났습니다.

isBindingDeliveryPending.needsReconciliation을 pending으로 포함시켜, 재조정 중에도 다른 대기 상태와 동일하게 최대 30초 폴링 창을 갖고 그래도 안 되면 정상적인 retryScheduled 경로로 빠지도록 수정했습니다.

📋 추후 진행 상황

실기기에서 재현 후 Console.app 로그로 missingGroupBinding 대신 waitingForBinding/foregroundPrepared 등이 찍히는지 확인 예정입니다.

📌 리뷰 포인트

  • hasPendingGroupBinding/hasPendingRoutineBinding이 공유하는 isBindingDeliveryPending을 수정한 것이라 group 바인딩과 routine 바인딩 양쪽에 모두 적용됩니다.
  • .blocked만 진짜 종결 상태로 남겼습니다 — 이 상태는 여전히 즉시 missingGroupBinding으로 처리되어야 합니다(수동 개입 필요).
  • 이 클래스 자체에 대한 단위 테스트 인프라가 없어 별도 테스트는 추가하지 않았습니다(기존에도 없었음).

✅ Checklist

  • 커밋 메시지 컨벤션에 맞게 작성했습니다
  • 유지-보수를 위해 주석처리를 잘 작성하였는가?

createRoutineGroup/addRoutine 뮤테이션이 needsReconciliation 상태(응답 모호로
서버 반영 여부를 재확인 중인 상태, RoutineSyncSender가 자동 재시도함)일 때
hasPendingGroupBinding이 이를 대기 중이 아니라고 판단해 missingGroupBinding으로
즉시 포기하던 문제를 수정. blocked만 진짜 종결 상태로 남기고 needsReconciliation은
다른 대기 상태와 동일하게 최대 30초 폴링 창을 갖도록 함.
@coderabbitai

coderabbitai Bot commented Aug 26, 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: Pro Plus

Run ID: 02d63fab-cb71-4461-b1a4-a007961c4a17


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

바인딩이 없고 대기 상태도 아닌 경우가 mutation 레코드 자체가 없는 것인지,
blocked 상태인 것인지, 아니면 바인딩은 있는데 유효성 검사에서 걸린 것인지
로그만으로 구분할 수 없었음. 세 가지 원인을 별도 이벤트로 분리.
missingGroupBindingMutationBlocked까지는 확인됐지만 blocked 상태는
6가지 사유(TTL 만료/재시도 소진/idempotency 충돌/서버 명시적 거부 등)로
갈릴 수 있어 정확한 원인 파악을 위해 blockReason 값 자체를 로그에 추가.
… 로그 추가

unknownConflict까지는 확인됐지만 실제 서버 응답의 code/message를 버리고 있어
정확한 거부 사유를 알 수 없었음. transport 레이어에서 그대로 로그로 남김.
transport 레벨 code/message 로그가 재현 때 안 찍혀서, 이번 block이 방금
새로 시도된 것인지 예전에 이미 blocked된 걸 반복 조회만 하는 것인지
구분하기 위해 attempt.attemptedAt 경과시간을 추가로 남김.
localCommonAudio가 준비 안 됨(unavailableForServerVoice) 또는 뒤늦은
재생 실패(failedToStart)로 조용히 완료 처리될 때 원인을 구분할 로그가
전혀 없었음. 두 분기 각각에 diagnostics 이벤트 추가.
@MinHeokChoi
MinHeokChoi force-pushed the fix/routine-tts-reconciliation-pending-binding branch from bfb8c27 to 237284e Compare August 27, 2026 04:43
캐시에 없을 때 백그라운드 URLSession 큐만 걸어두고 그 자리에서 바로
fail-open 되던 걸, 짧게(2초) 기다리면서 일반 foreground 다운로드를
직접 시도하도록 변경. 백그라운드 세션은 첫 전송 시작까지 지연이 커서
완료/무응답 큐처럼 즉시 필요한 소리에는 적합하지 않았음.
닉네임을 아직 안 정한 신규 카카오 로그인 계정은 nickname이 null로
내려오는데, 이를 필수값으로 검증해 프로필 조회 자체를 실패시키고
있었음. 그 위에서 도는 로그인 시 TTS 목소리 자동 선택 등 프로필에
의존하는 다른 흐름까지 같이 막혔음. ttsId가 null인 경우와 동일하게
"아직 안 정해짐"으로 취급하도록 완화. 다른 화면들은 이미 닉네임이
비어있을 때 로컬 표시 이름으로 대체하도록 되어 있어 안전함.
AI 루틴 추천을 실제로 시도할 때만 우연히 뜨던 걸, 소셜 로그인 성공
시점에 바로 물어보도록 변경. 이미 동의/거부를 정한 사용자에게는
재로그인해도 다시 뜨지 않음.
constructReadyGraph의 catch가 원인과 무관하게 항상 같은 안내 메시지만
띄우고 로그를 전혀 남기지 않아, 재현 시 Console.app으로도 원인 파악이
불가능했음. 실제 에러를 OSLog로 남기도록 추가 (사용자에게 보이는
메시지는 그대로 유지).
2.4.5는 이미 승인된 버전이라 트레인이 마감되어 재제출 불가.
@MinHeokChoi

Copy link
Copy Markdown
Contributor Author

이 PR 브랜치에 서로 무관한 변경(TTS 재조정 수정 + DONE/REMIND 음원 수정 + 닉네임 프로필 수정 + Gemini 동의 화면 변경 + 버전 범프)이 섞여 있어 정리 차원에서 아래 PR들로 분리했습니다:

버전 범프(2.4.5 → 2.4.6) 커밋은 별도로 확인 후 처리 예정이라 아직 분리하지 않았습니다.

@MinHeokChoi MinHeokChoi closed this Sep 1, 2026
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