2026.07.01 작업일지 v1.0.0
01:52, 세션을 지키려던 안전 훅이 오히려 세션을 얼려버렸고, 그게 내 폰에 “다 멈춤”으로 찍혔다. 02:40, 밤새 워커를 돌리려고 maxing을 켰는데 정작 집을 일감이 없었다. 23:53, 결국 다섯 노드 전부로 머지 자격을 열어 하루를 닫았다.
7월 1일은 전날 예고 그대로 “Codex maxing을 밤새 돌린다”로 시작했다. 여러 대의 워커 노드가 놀지 않도록 밤새 유용한 작업을 시키자는 계획이었는데, 막상 켜보니 워커에게 줄 일감도, 그 일감을 안전하게 나눠주는 배관도 준비가 덜 돼 있었다. 그래서 하루는 “자동화가 일을 한다”가 아니라 “자동화가 워커를 먹이고, 겹치지 않게 나눠주고, 멈출 때 정확히 멈추게 한다”를 고치는 날이 됐다. 그리고 저녁엔 전혀 다른 결의 결정 하나 — 한줄일기의 수익 모델을 통째로 뒤집는 판단 — 이 끼어들었다.
1. maxing을 켰더니 집을 일감이 없었다
밤 작업의 첫 벽은 단순했다. 워커 backlog가 0이었고, 앱 개선 task를 자동 공급하는 seeder는 꺼져 있거나 연결이 끊겨 있었고, 작업 후보를 뽑는 lease 경로도 너무 좁았다(T-260701-14). maxing을 켜도 워커들이 집을 게 없으니 토큰만 태우고 헛도는 구조였다.
그래서 밤새 태울 안전한 “종잣일감”을 손으로 깔았다 — 단어요의 죽은 import 정리, 주식모니터·약먹자의 placeholder 위젯 테스트를 실제 검증으로 교체, 가계부(mini_expense)의 금액 유틸 순수 로직 테스트 보강 같은, 실패해도 위험 없는 것들이었다. 문제는 seeder 자체가 리눅스 워커에서 계속 넘어졌다는 것이다. 오래된 앱 경로, GNU/리눅스 stat mtime 처리, routing lock 계약이 겹쳐 PR이 #283·#284·#285·#286 네 개로 갈라졌다. 03:36, 나는 이걸 새벽에 무인 머지하지 않기로 했다 — 코어 fleet 라우팅·maxing 머신은 “아침 검토 게이트”로 붙잡아뒀다.
2. 안전 훅이 자기 탈출구를 막았다
가장 극적인 사고는 이거였다. heartbeat 훅은 브릿지가 아닌 세션이 10분 넘게 도구만 호출하면 데드락으로 보고 모든 도구를 차단하도록 돼 있었다. 그런데 훅이 “이 명령으로 빠져나가라”고 권한 복구 명령(notify-aniki.sh)마저 같은 규칙에 걸려 차단됐다. 탈출구가 잠긴 감옥이었다 — 세션이 완전히 정지했고, 그 모습이 내 폰에 “다 멈춤”으로 관측됐다(T-260701-09, 마침 directive 전달 버그 작업 도중 발생).
수정은 화이트리스트였다. 보고·탈출용 명령(notify-aniki·bonjin-report·mac-report·heartbeat-track)은 면제하고, 무관한 명령 차단은 그대로 뒀다. TDD 10/10 통과 후 354e69c(PR #279)로 머지.
배운 것 — 데드락을 감지하는 안전장치는 자기가 권하는 탈출 명령만큼은 절대 막지 말아야 한다. 아니면 안전장치가 사고의 원인이 된다.
3. 같은 일을 두 노드가 동시에 집었다
밤엔 조율 버그도 두 개 터졌다. 하나는 directive 전달 검증의 false-negative였다 — 워커가 바쁜(idle이 아닌) codex 세션에 지시를 붙여넣으면 echo가 안 돌아와 “미도달”로 오판했는데, 실제로는 도달해 있었다. 이 오판이 같은 task를 두 노드가 동시에 집는 중복 dispatch 사고를 만들었다. 검증 로직을 task-id 앞뒤 앵커 매칭 + 멀티바이트 안전 substring으로 단일화해 ef03e1a(PR #275)로 닫았다.
다른 하나는 공유 작업트리 오염이었다(T-260701-01). 라이브 checkout의 main 트리가 임의 세션의 feature 브랜치 + 미커밋 WIP로 파킹돼 다른 세션이 오염될 위험이 있었다. 근본 원인을 진단한 뒤, ~/claude-automations가 깨끗한 main이 아닐 때 git add/commit/브랜치 checkout을 차단하는 PreToolUse 가드를 넣어(PR #274) 모든 feature 작업을 격리 worktree로 강제했다.
4. 아침이 되자 붙잡아둔 머지가 내려왔다
붙잡아뒀던 새벽 머지들은 아침 검토 후 순서대로 내려왔다. 동시에 열네 개 남짓 repo에 통합 auto-merge 워크플로가 깔렸다(T-260627-24). maxing seeder가 첫 repo에서 죽던 bash 3.2 빈 배열 unbound 버그도 가드를 붙여 28df817(PR #290)로 고쳤고, 빌드·배포를 맡는 맥미니 노드에는 공유 풀 backlog를 스스로 집어가는 codex self-worker를 붙였다(a7ddef9). 세션이 끊겨도 하던 일을 이어받는 next-cycle 하이브리드 auto-resume도 Claude·Codex 양쪽 훅으로 복귀시켰다.
그런데 여기서 교훈 하나가 튀어나왔다. 방금 고친 seeder PR은 본문에 “수동 게이트”라고 적혀 있었는데도 auto-merge 봇이 무시하고 자동으로 머지해버렸다 — 스크립트 경로를 통째로 예외 처리하던 기존 구멍(T-260628-32) 때문이었다. 다행히 코드는 기본 read-only라 위험 실행은 없었지만, firing 계열 스크립트명 패턴(directive·fire-lease·worker-toggle·dispatch 등)을 민감 게이트에 추가해 구멍을 좁혔다.
배운 것 — “수동 게이트”라고 사람 언어로 적어두는 것만으론 부족하다. CI가 그 표기의 모든 변형을 읽어서 실제로 멈추는지까지가 안전장치다.
5. ₩1,900짜리 일기장을 공짜로 풀기로 했다
저녁엔 결이 다른 작업이 끼어들었다. 한줄일기의 ₩1,900 유료 다운로드 모델이 “한 줄은 너무 짧다”는 본질 딜레마와 맞물려 매력이 약하다는 문제였다(T-260701-80). 잘 팔리는 일기 앱들을 뜯어보니 신호가 분명했다 — Day One·Daylio·Journey 같은 승자는 대부분 무료 다운로드 + 프리미엄 구독이었고, ₩1,900 유료 다운로드는 시장 반대 방향이었다. AI 저널 앱은 취소·환불이 20~30% 더 빠르다는 경고도 있었다.
그래서 방향을 뒤집었다. 무료 다운로드 + 프리미엄 구독(정액제) 으로 가고, AI 답글은 프리미엄 결제자에게만 서버 측(Cloudflare Worker)에서 열어주고, 스토어 7일 무료체험으로 farming을 막고, 기존 유료 구매자는 평생 프리미엄으로 그랜드파더링하기로 했다. 설계 스펙을 확정(PR #38)한 뒤, 커스텀 뉴럴 보이스(직접 클론한 목소리)를 걷어내고 OS 기본 한국어 보이스로 내리면서 AI 프리미엄 게이팅을 붙였다(5bac1eb, PR #39). 실제 스토어 가격·모델 flip은 외부 영향이라 별도 확인 게이트로 남겨뒀다.
배운 것 — 입력을 더 짧게/길게 만드는 것보다 수익 모델과 리텐션 깊이가 앱의 생존을 가른다. “한 줄”의 약점은 통계·백업·구독 가치로 흡수하는 게 시장의 정답이었다.
6. 그래서 뭐가 남았나
마지막 함정은 아주 작았다. auto-ack-broker가 매 정각에 조용히 아무것도 안 보냈는데, 원인은 cut -c가 한글 멀티바이트를 중간에서 잘라 UTF-8이 깨진 것이었다. cut을 파이썬 슬라이스로 바꿔 77631c3(PR #308)로 고쳤다.
# 정각 발사가 무발송이던 이유
cut -c 1-N # 멀티바이트를 바이트 단위로 잘라 UTF-8 깨짐 → 발송 실패
그 위로 남긴 변화는 넓게 퍼져 있다. PR 머지 권한을 다섯 노드 전부에 열고 stale·충돌 방지 프로토콜을 글로벌 룰로 못박았다(같은 날 오전에 세웠던 “머지는 본진 위임” 룰을 저녁에 스스로 뒤집었다). merge_slot 자격도 다섯 노드로 확장해 0b14d48(PR #311)로 정합을 맞췄다. 토큰을 아끼려는 로컬 LLM 사이드카는 벤치 끝에 기본 모델을 qwen2.5:3b(약 152~155 tok/s, VRAM ~2.9GB)로 확정하고 advisory diff 사이드카까지 붙였다(9258c22, opt-in·advisory-only·로컬 한정). 출시 앱 쪽에선 로또계산기·포모도로·약먹자·주식모니터·한줄일기의 접근성/UX, 단어요 카드 레이아웃 안정화, 메모요 검색·휠 스크롤을 저위험 묶음 PR로 다듬었고, 더치페이 아이콘은 계산기형(네이비+₩)으로 새로 뽑아 task로만 붙잡아뒀다.
숫자로는, 코드·콘텐츠 repo 기준 약 115개의 커밋이 하루에 올라갔다(작업 상태 장부인 ~/todo의 기록성 커밋 356개는 별도). 대부분이 화면에 보이는 기능이 아니라 그 뒤의 배관이라는 게 이 날의 성격이다. 진짜 검증은 다음 며칠, 다섯 노드가 조용히 서로 겹치지 않게 일하고 멈출 때 정확히 멈추는지에 달려 있다.
| repo | SHA | 메시지 |
|---|---|---|
| claude-automations | 354e69c | heartbeat 데드락 탈출 명령 면제 + codex-relay fire forcing (#279) |
| claude-automations | ef03e1a | codex-directive delivery-verify busy-session false-negative (#275) |
| claude-automations | 28df817 | seeder bash 3.2 빈배열 unbound 가드 (#290) |
| claude-automations | a7ddef9 | macmini codex self-worker |
| claude-automations | 77631c3 | auto-ack-broker cut -c UTF-8 절단 → 무발송 fix (#308) |
| claude-automations | 0b14d48 | topology-v3 merge_slot eligibility → 5노드 |
| claude-automations | 9258c22 | local-llm advisory diff sidecar (#309) |
| hanjul | 5bac1eb | 커스텀 보이스 제거 + AI 프리미엄 게이팅 (#39) |
다음 이야기는 7월 2일, 운영 헌법을 원칙 중심으로 다시 쓰고 정책을 파일로 내려보내는 이야기.
— 강대종 / @ssamssae