← 전체 글로

AI 사용기

AI 활용기: 반려 스크린샷을 고쳐 올렸는데 16장이 됐다

App Store Connect 스크린샷 교체가 덮어쓰기가 아니라 추가라는 걸 반려 이후에야 알게 된 사례와, 같은 함정을 겪은 fastlane 사용자들의 실제 이슈를 같이 정리했다.

이 글의 목적

스토어 자동화 스크립트로 스크린샷을 갱신하는 사람에게, '새로 올렸다'와 '옛 것을 지웠다'가 왜 다른 확인인지 구체적 사례로 보여준다.

핵심 내용

반려 사유가 된 스크린샷을 고쳐 10장을 새로 올렸더니 심사 대상이 16장이 됐다 — App Store Connect의 스크린샷 업로드는 기본이 추가이지 교체가 아니다. fastlane deliver도 같은 구조라 overwrite_screenshots 옵션을 기본값 false로 두면 똑같이 쌓이고, 옵션을 켜도 삭제 단계 자체가 실패하는 사례가 실제 이슈로 보고돼 있다.

읽고 나서

스크린샷을 다시 올리기 전에 항상 기존 컷을 먼저 비우거나 삭제를 확인하고, 그 확인이 도구가 자동으로 해줄 거라 가정하지 않는다.

목차

먼저 답하면

스토어 스크린샷을 새로 올린 개수와, 심사에 올라가는 개수는 다를 수 있다. App Store Connect는 스크린샷 업로드를 교체가 아니라 추가로 처리하기 때문에, 옛 컷을 먼저 지우지 않으면 새 컷은 옛 컷 위에 그냥 쌓인다.

반려된 컷을 고쳤는데 6장이 늘었다

앱 하나가 스크린샷 문제로 반려됐다. 반려 사유가 된 컷들을 새로 찍어 10장을 다시 올렸는데, App Store Connect에서 확인해보니 심사 대상이 16장이었다. 새로 올린 10장은 맞게 들어갔지만, 반려 원인이었던 옛 컷들이 그대로 남아 새 컷과 함께 심사에 갔던 것이다.

원인은 단순했다. ASC의 스크린샷 업로드는 “이 슬롯을 이 이미지로 바꿔라”가 아니라 “이 이미지를 추가해라”에 가깝게 동작한다. 문장을 고치고 화면을 다시 캡처해도, 지우는 단계를 따로 거치지 않으면 옛 화면은 여전히 심사 목록에 있다. 이 자동화 파이프라인에서는 이후 asc_shots.pyclear 명령을 넣어, 항상 비우고 나서 다시 올리는 순서로 고쳤다.

같은 종류의 함정이 로컬에도 있었다. 스크린샷을 언어별 폴더(screenshots/<locale>/)에 저장하도록 구조를 바꾼 뒤에도, 그 이전 방식으로 만든 앱은 컷이 폴더 없이 평면으로 남아 있었다. 두 구조가 한 프로젝트에 공존하면 검수 스크립트는 옛 평면 경로를 먼저 읽는다 — 문장을 몇 번 고쳐도 실제로 심사에 가는 이미지는 그대로인 상태가 된다. 이 경우도 파일이 잘못 갱신됐다기보다, “새로 만든 파일”과 “실제로 참조되는 파일”이 다른 경로에 있다는 걸 놓친 문제였다.

fastlane 사용자들도 같은 자리에서 걸렸다

이 문제는 Apple 자동화 커뮤니티에서 이미 알려진 함정이다. fastlane의 deliver/upload_to_app_store 액션 공식 문서를 보면 overwrite_screenshots 옵션이 명시적으로 존재한다. 설명은 “새 스크린샷을 올리기 전에 기존에 올라간 모든 스크린샷을 지운다”이고, 기본값은 false다. 즉 아무 옵션도 안 주면 fastlane도 기본은 추가이지 교체가 아니라는 뜻이다.

옵션을 켜도 문제가 완전히 사라지는 건 아니다. fastlane GitHub 이슈 #19935에서는 Xcode 에셋에 새 스크린샷을 추가하고 overwrite_screenshots: trueupload_to_app_store를 돌렸더니 업로드 마지막 단계에서 실패했고, App Store Connect에는 옛 스크린샷과 새 스크린샷이 “6장 전부” 같이 남았다는 실사용 보고가 있다. 같은 저장소의 토론 #19605에서는 overwrite_screenshots: trueforce: true를 함께 켰는데도 기존 스크린샷 삭제 단계 자체가 반복 실패하며 “삭제되지 않은 스크린샷 수: 12”라는 로그를 남긴 사례가 보고돼 있다. 옵션을 켜서 “지워지길 기대”하는 것과 “실제로 지워졌는지 확인”하는 것은 다른 확인이라는 뜻이다.

도구를 믿는 것과 결과를 확인하는 것은 다른 확인이다

세 사례의 공통점은 “업로드에 성공했다”는 신호와 “옛 것이 지워졌다”는 사실이 서로 독립이라는 점이다. API든 fastlane이든 업로드 요청 자체는 정상 응답을 돌려줄 수 있고, 그 응답만 보면 작업이 끝난 것처럼 보인다. 실제로 무엇이 심사 목록에 남아 있는지는 별도로 세어봐야 드러난다.

이후로는 스크린샷을 다시 올리는 작업을 “새 컷 업로드”가 아니라 “비우기 → 업로드 → 개수 확인”의 세 단계로 고정했다. 옵션 하나를 켜는 것보다, 작업이 끝난 뒤 실제로 몇 장이 남아 있는지 세어보는 습관이 더 확실했다.