빌드마다 지나는 게이트
Ariandel 빌드는 scripts/test-mobile.sh를 통과하기 전엔 TestFlight로 못 가. 이 스크립트는 세 가지를 순서대로 돌려. 키트 드리프트 검사(cwkSiblingKit에서 벤더링한 파일이 아직 키트랑 똑같은지), 엔진 스위트(Mac 자체 GPU 위의 swift test), 그리고 전용 시뮬레이터 "Ariandel QA iPad" 하나 위에서 도는 앱의 호스티드 XCTest와 XCUITest. 빌드 24 기준으로 소스에서 세면 엔진 테스트 210개, 호스티드 93개, UI 19개야. 시뮬레이터 id는 기본값이 없고 꼭 줘야 해. Mac 하나의 시뮬레이터 목록을 여러 앱 세션이 같이 쓰거든. 판정은 걸러진 파이프가 아니라 로그가 내려. 스크립트는 ** TEST SUCCEEDED **를 grep해. 걸러진 파이프는 테스트 실행이 아니라 필터의 상태를 보고하니까.
게이트가 가르쳐 준 것
시뮬레이터 하나로 빌드 스무 개 넘게 밀면 흉터가 남아. Ariandel은 그걸 하우스 사인의 Gotchas 칸에 모아 둬. 그중 여섯은 어느 iPad 앱이든 훔쳐 갈 만해.
| 증상 | 원인 | 해법 |
|---|---|---|
| 어느 순간부터 UI 단계마다 60초씩 기다려. 앱은 CPU 0%로 놀고 있고 | 끌 수도 있는 뷰(붓 행, 갤러리 카드)에 붙은 컨텍스트 메뉴가 XCTest한테 애니메이션 끝났다는 말을 안 해. .onDrag도 똑같아 | UI 테스트를 ARIANDEL_NO_ANIMATIONS=1로 띄워서 UIKit 애니메이션을 꺼. 스위트가 1,984초에서 약 1,250초로 줄었어 |
초록불로 끝났는데 xcodebuild test가 10분을 멈춰 있어 | 런타임 경고 하나가 기본값 -collect-test-diagnostics on-failure를 건드려. 경고는 Thread Performance Checker가 낸 "메인 스레드가 더 낮은 QoS 작업을 기다린다"였고, 여기선 메인에서 시작한 AVAssetWriter가 원인이야. 그 바람에 simctl diagnose가 돌고, 그게 600초에서 타임아웃 나 | 우선순위 역전을 고쳐. -collect-test-diagnostics never는 반복 작업할 때만 써 |
| 새 테스트 하나가 타임랩스 테스트 뒤로 정렬되자 TestFlight 게이트에서 떨어졌어 | 호스티드 테스트는 앱 안에서 돌고 앱의 UserDefaults를 같이 써. 한 테스트가 바꾼 설정이 다음 테스트와 UI 테스트로 새 | 테스트용 스튜디오마다 자기 스위트를 줘(isolatedDefaults()). UI 테스트는 ARIANDEL_RESET_SETTINGS=1로 띄워 |
| iPad 팝오버 안의 Form을 스와이프하면 "visible frame is empty"로 실패해 | XCUITest는 그 Form을 스와이프 못 해 | 팝오버 자체 좌표로 드래그해(reveal). 행은 한 칸씩 짚어서 찾아. 스와이프 횟수를 박아 두지 말고 |
| 테스트가 필드에 입력했는데 값이 이상하게 들어가 | 더블 탭으로 필드 내용 전체 선택이 안정적으로 안 돼 | 오른쪽 정렬 필드는 끝을 탭하고, 지우고, 입력하고, 리턴으로 마무리해 |
| 컨트롤을 노린 탭이 화면 한가운데 떨어져 | 꽉 채우는 .frame 뒤에 붙인 접근성 수식어는 프레임 전체를 가리키고, XCUITest는 그 한가운데를 탭해 | 접근성 수식어는 .frame 앞, 컨트롤 쪽에 붙여 |
여섯 다 실패하는 모양이 같았어. 자기 이름을 말해 주는 에러가 아니라 느리거나 들쭉날쭉한 테스트로 나타났지. 해법 옆에 원인을 적어 둬야 다음 세션이 타임아웃 늘리기로 "고치는" 걸 막을 수 있어.
게이트가 못 보는 것
이제 정직해질 차례야. Ariandel 하우스 사인은 세 문장으로 말해. "The Simulator has no Apple Pencil pressure and no microphone. A green simulator run proves layout and logic, never feel or voice. Say what was exercised." 시뮬레이터엔 펜 압력도 마이크도 없고, 초록불은 레이아웃과 로직만 증명해. 느낌이나 목소리는 절대 아냐. 뭘 돌려 봤는지 말해. 다만 한 구절은 너무 세. 시뮬레이터도 오디오 입력은 받아. Mac의 마이크로. 시뮬레이터가 못 주는 건 iPad의 마이크, 스피커, 그 방의 소리야. 게이트도 음성 테이크는 한 번도 안 돌려. 그래서 목소리 증명은 여전히 iPad 몫이야. UI 테스트가 손가락으로 칠하는 것(ARIANDEL_FINGER_PAINTING=1)도 칠할 펜이 없어서야. 그래서 라운드마다 기록 행 끝에 Not exercised 목록이 붙고, 그걸 모으면 진짜 목록이 돼.
- 펜 압력, 기울기, 호버의 느낌. 압력 곡선의 느낌. 안정화와 테이퍼의 느낌.
- Apple Pencil Pro의 스퀴즈, 더블 탭, 배럴 롤 (제스처는 모델을 통해서만 시험했어).
- 유리에 닿는 진짜 손바닥. 그러니까 손이 닿았을 때의 손바닥 거부.
- TrueDepth가 있어야 하는 Face Paint, 그리고 카메라 자체.
- 외부 디스플레이, 하드웨어 키보드, iPad 사이 AirDrop.
- 펜 지연. 처음 엔진 평가가 "What was not checked"에 올려놓고, 증거는 첫 TestFlight 빌드와 함께 온다고 했어. 안 왔어. Ariandel 기록 행 어디에도 지연 얘기가 없어.
하드웨어가 증명한 건 전부 아빠 iPad에서 증명됐어. 피파가 말을 시작하자마자 음성 모드가 다 말한 걸로 받아들인 것(10월 1일. 세션 쿠키가 빠져서 음성 요청마다 401이 났어). 끝 신호가 안 온 터치 하나 때문에 펜이 죽어 버린 것(10월 3일). Generate의 Auto가 첫 획과 함께 꺼진 것(10월 4일). 셋 다 iPad가 먼저 찾았고, 보고서도 iPad를 증인으로 적어. 그렇다고 "시뮬레이터는 못 본다"로 읽진 마. 아빠가 Auto 버그를 짚자 라이브 UI 테스트가 시뮬레이터에서 그대로 재현했고, b14f113은 수정 옆에 라이브 Auto 테스트를 붙였어. 라이브 Ember 테스트를 청할 때만 도니까 기본 게이트는 여전히 건너뛰어. 그 버그는 시뮬레이터도 볼 수 있었어. 아무도 보라고 안 했을 뿐이야.
읽어야만 찾는 버그
세 번째 부류가 있고, 이게 제일 겸손해지게 만들어. 시뮬레이터도, 아마 아빠 손도 끝내 못 드러냈을 버그야. 이 퀘스트를 쓰던 2026-10-12에 4트랙이 C를 읽다가 둘을 찾았어. mypaint_brush_stroke_to는 barrel_rotation 인자를 받아서 안에서 360을 곱해. 그러니까 한 바퀴의 몇 분의 몇을 기대해. Ariandel은 도(degree)를 보내. 90° 롤이 0°로 도착해. viewrotation 인자는 libmypaint의 DEGREES()를 거치니까 라디안을 기대해. Ariandel은 여기도 도를 보내고, 캔버스를 90° 돌리면 116.62°로 도착해. 빌드 24 기준으로 둘 다 찾았고, 아직 안 고쳤어.
왜 아무것도 못 잡았는지 따라가 봐. 시뮬레이터엔 배럴이 없으니까 UI 테스트는 롤을 한 번도 안 만들어. 롤을 쓰는 엔진 테스트는 Liquify의 비틀기를 시험하는데, 그건 롤을 직접 읽고 제대로 돌아가. 붓에 롤을 먹이는 테스트는 하나도 없어. 엔진 테스트는 전부 뷰 회전 0에서 칠해. Ariandel 자체 변환의 단위 테스트는 통과해. Swift 쪽 값은 진짜로 90도니까. 하드웨어에서도 배럴 입력을 매핑한 붓이나, 돌린 캔버스에서 뷰에 따라 바뀌는 입력을 읽는 붓만 이상하게 굴 거야. 아빠는 그걸 "이 붓은 원래 이래"로 읽기 딱 좋아. 이 버그를 보는 도구는 경계를 건너는 테스트 하나뿐이야. 아는 값을 넣고, 받는 쪽이 그걸로 뭘 만들었는지 다시 읽어. 4트랙의 컴파일한 프로브가 벤더링된 엔진에 대고 정확히 그걸 해. 아래 스케치는 같은 생각을 작게 줄인 거야.