2026.07.04 작업일지 v1.0.0
02:06, 자기 전에 앱 심사만 걸어두려다 스크린샷 한 장에서 옛날 화면을 발견했다. 07:29, 제출을 막던 진짜 범인은 스샷도 구독도 아닌, 애플이 갱신한 계약서 재동의였다. 그 사이 낮에는, 다른 컴퓨터들이 올린 코드 열 몇 개를 하나씩 내 손으로 다시 돌려보며 병합했다.
7월 4일은 두 개의 이야기가 겹친 날이었다. 하나는 새벽 내내 이어진 한줄일기 iOS 심사 대장정, 다른 하나는 낮부터 저녁까지 이어진 자동화 인프라 버그 사냥과 병합(merge) 게이트 마라톤. 하루 동안 여러 저장소에 62개의 커밋이 쌓였고, 그 대부분은 작업 노드들이 올린 제출서(PR)를 검증하고 합치는 과정에서 나왔다. 결론부터 말하면 — 앱은 계약서 서명 하나로 벽을 뚫었고, 인프라는 “초록불이라는 워커의 말”을 곧이곧대로 믿지 않은 덕에 여러 함정을 피했다.
1. 자정의 스위치 — “합쳤어”를 자동으로
하루의 시작은 자정 직후였다. 작업 노드 한 대가 올린 기능(PR#384) — 내가 무언가를 병합할 때마다 손으로 “합쳤다”고 알려주던 걸, 자동으로 폰과 봇 채팅방에 쏴주는 알림으로 만드는 것이었다. 인프라 성격이라 서브에이전트에게 정밀 리뷰를 맡겼고 8개 항목 전부 통과(직접 API 호출 0, 플래그 없으면 발신 0인 이중 게이트, 실패 시 loud 전파 등)를 확인한 뒤 6b75e80으로 병합했다.
스위치를 켜자마자 스모크 발신을 한 방 쐈고, 폰에 실제로 알림 두 건이 도착한 스크린샷으로 실도착까지 확인했다. 코드 검사가 통과해도, 실전에서 엉뚱한 방으로 가지 않는지는 결국 한 번 켜서 눈으로 봐야 한다.
2. 새벽 두 시, 스크린샷이 멈춘 심사
“심사는 며칠 걸리니 자기 전에 걸어두자”는 한마디로 한줄일기 iOS 제출이 시작됐다. 준비 상태는 100%로 보고됐고(빌드 valid, 구독 2종 완비), 마지막 제출 버튼만 남은 상황. 그런데 제출 직전 화면 스크린샷에서 상품 페이지 하단에 v1.1.0 — 며칠 전 지적됐던 옛날 버전 스샷이 iOS에는 아직 남아 있었다.
이미 한 번 제출이 나간 뒤였다. 옛 스샷 + 첫 구독앱의 “구독 동반 제출 누락” 가능성이 겹치면 애플 가이드라인 2.1(b)로 반려될 위험이 있어, 나간 제출을 취소하고 재정비에 들어갔다. 6.5인치 스샷을 현행으로 교체하고 URL 세 종류를 옛 도메인에서 현재 주소로 갈았다. 그런데 구독은 계속 MISSING_METADATA. 이름·가격·설명·심사용 자료를 전부 채웠는데도 풀리지 않았다.
3. 진짜 벽은 계약서였다
처음 세운 가설은 “유료 앱(Paid Apps) 계약 미체결”이었다. 첫 유료 상품의 전형적 패턴이라 유력해 보였다. 하지만 아침에 App Store Connect 웹을 직접 진단해 보니 — 유료 앱 계약은 오히려 정상·활성이었고, 진짜 범인은 따로 있었다. **개발자 프로그램 사용권 계약(Apple Developer Program License Agreement)**을 애플이 갱신했고, 계정 소유자의 재동의가 필요한 상태. 이 하나가 구독 활성화와 제출을 동시에 막고 있었다.
계정 화면의 배너에서 약관에 서명하자 애플이 곧바로 “Agreement signed: Apple Developer Program License Agreement” 확인 메일을 보냈다(08:10). 그 순간 벽이 뚫렸다. 흥미로운 대조 — 안드로이드는 이미 앞서 있었다. 같은 앱의 구독 상품 월 ₩3,300·연 ₩29,900이 스토어에 이미 판매 활성 상태였고, 빌드도 준비 완료였다.
배운 것 — 막힌 화면이 가리키는 곳과 진짜 원인이 같은 경우는 드물다. 스샷을 의심하고 구독을 의심했지만, 정작 범인은 눈에 안 띄는 계약서 재동의였다. 유력한 첫 가설(유료 앱 계약)일수록 실측으로 반증될 준비를 해둬야 한다.
4. “안전한 건 묻지 마” — 그리고 실측이 워커를 이긴 순간들
낮에는 흐름이 완전히 바뀌었다. 세션을 비우고 다시 켜면 밀린 작업을 스스로 이어받는 구조 덕에, 대기 중이던 30여 개 할 일을 훑고 메모요 월 구독(프리미엄) 구현 계획을 10개의 테스트 우선(TDD) 태스크로 문서화했다. 그다음부터는 작업 노드들이 올린 제출서가 줄줄이 도착했다.
훅(자동 장치) 버그를 고친 PR이 연달아 왔다 — device-id 훅이 자기 자신을 ”🤖 unknown”으로 인식하던 버그(PR#386), 형제 훅 동종 수리 + 이 버그 계열을 아예 봉인하는 자동 검사기(PR#387), 공유 헬퍼로 리팩터링(PR#388). 훅 수정은 폰으로 알림이 나가는 R3라 원래 매번 물어봐야 하지만, “안전한 건 묻지 마”라는 한마디로 새 상시 규칙이 섰다: 풀그린 + 가역 + enforcement 무변경 + 소범위, 이 네 조건을 다 만족하는 훅 픽스는 앞으로 내가 직접 검증하고 자동 병합한다.
핵심은 매번 워커의 “초록불”을 그대로 믿지 않은 것이다. 한 PR은 워커 쪽에서 Ran 299 OK였지만 내 기계에선 처음에 에러가 떴다 — 알고 보니 pytest 미설치로 인한 모듈 로드 실패, PR과 무관한 환경 차이였다. 또 다른 병합 뒤에는 중첩된 유령 워크트리가 정책 파일(POLICY.md)을 7개에서 15개로 오염시킨 걸 발견했다. 저장소 안에 오래된 전체 복사본이 하나 살아 있었고, 정책 생성기가 그걸 긁어 들이고 있었다. 생성기를 “git이 추적하는 파일만 스캔”하도록 고쳐(PR#392, f5b87a5) main을 깨끗한 7개로 복구했다.
배운 것 — 워커의 ‘초록불’은 그 기계에서의 초록불이다. 게이트는 같은 코드를 내 손으로 다시 돌려볼 때만 게이트다. RED→GREEN을 직접 재현하지 않은 통과는 통과가 아니다.
가장 섬뜩했던 건 테스트가 진짜로 새어나가던 문제였다. 반복해서 뜨던 정체불명의 “[Codex result return]” 메시지의 근원을 추적하니, 테스트 픽스처가 격리 없이 라이브 세션에 실제로 주입되고 있었다. 한 테스트의 두 번째 호출이 로컬 노드 환경변수를 빠뜨려, 메인 노드에서 돌면 진짜 tmux 붙여넣기를 실행하고 있었던 것. stop-the-bleed로 격리를 채워 막았다(PR#398). 동시성 잠금 PR(#400)에서는 워커의 리눅스에선 안 보였던 SIGPIPE 플래키(간헐 실패) 테스트를 잡았다 — cat ... | grep -q에 pipefail이 걸려 8번 중 5번 죽던 것을, 파이프를 없애 25/25 안정으로 만들었다. 잠금 자체는 매번 승자 1명 불변식을 지키고 있었으니, 고장 난 건 테스트였다.
5. supply 라는 단어를 막아버린 문지기
저녁의 하이라이트는 빌드 잠금 문지기(build-lease guard) PR(#401)이었다. 스토어 빌드 명령을 가로채는 항상-켜진(PreToolUse) 방어 훅인데, 리뷰 중 과잉 차단 버그를 잡았다. 패턴 \bsupply\b가 명령어 어디에 있든 “supply”라는 단어만 있으면 막아버려서 — git commit -m "fix supply-chain-logic", echo supply and demand, cat docs/bundletool-notes.md 같은 멀쩡한 명령까지 전부 DENY됐다. 실행 맥락으로 좁혀(\bsupply\b 제거, bundletool은 명령 위치/.jar 형태로 앵커) 13개 케이스가 전부 올바르게 통과/차단되도록 고쳤다.
그런데 이 PR에는 “머지 금지, 수동 게이트 유지” 지시가 걸려 있어서, 검증은 끝냈지만 **병합은 보류(HELD)**했다. 이 과정에서 하나 더 배운 게 있다 — ~/.claude/hooks가 저장소 훅으로 심볼릭 링크돼 있어, 브랜치를 체크아웃하는 것만으로 그 문지기가 내 세션에 즉시 살아나 나를 막았다. 배포 전 반드시 알아둬야 할 라이브-온-체크아웃 특성이었다.
배운 것 — 안전장치가 과하게 막으면 그건 안전이 아니라 고장이다. 단어 하나(
supply)가 멀쩡한 커밋을 막았다. 방어 훅은 “무엇을 막느냐”만큼 “무엇을 막지 않느냐”를 테스트로 못 박아야 한다.
6. 그래서 뭐가 남았나
숫자로 보면 하루에 여러 저장소 62개 커밋, 병합·검증한 제출서 열 몇 개. 하지만 남은 건 숫자가 아니라 몇 가지 구조적 개선이다.
| 갈래 | 결과 |
|---|---|
| 한줄일기 iOS | 계약(PLA) 재동의로 구독 벽 해제 → 재정비 후 제출 준비 완료(스샷·URL·구독 필드), 마지막 제출 버튼만 남음 |
| 한줄일기 Android | 구독 월 ₩3,300·연 ₩29,900 이미 활성, 빌드 준비 완료 |
| 자동화 인프라 | 훅 버그 계열 봉인, 정책 파일 오염 복구, 테스트 유출 격리, 플래키 테스트 안정화, 봇 토큰 중앙화, 병합 4단계 래퍼(자기 자신으로 검증) |
| 정책 | ”안전한 훅 픽스 자동 병합” 규칙 확립, CPU 무거운 작업은 특정 노드 우선 배정 규칙 등재 |
일과 후에는 홈페이지 인사이트에 글 하나를 더 얹었다 — “Block은 3,500명을 안 가르쳤다: 50명으로 조직 전체를 자율화한 AI 챔피언 전략.”
다음 세션으로 넘긴 것들: 메모요 월 구독 구현(계획은 완성), 못자요 앱의 월/연 구독 분리(코드 완료, 병합 보류), 텔레그램 브릿지 종합 정비(리뷰에서 버그 20개·근본원인 2개 발굴), 그리고 한 번 롤백했던 코덱스 재절체 카나리의 재도전.
다음 이야기는 메모요의 첫 유료 구독과, 브릿지 대정비 이야기.
— 강대종 / @ssamssae