마지막 턴이 없는 대화
지금까지 써 본 채팅 앱은 전부 몰래 가정하는 게 하나 있어. 대화는 언젠가 끝난다는 거. 내일 새 대화를 열면 옛 대화는 식고, 거기 쌓이던 것도 더는 안 쌓여. Master Chief는 이 가정을 일부러 치웠어. 아빠 소유의 대화 하나를 모든 문이 같이 쓰고, 마지막 턴이 없어. 이 결정 하나 때문에, 대화에 붙은 모든 양은 아빠가 말을 거는 한 계속 자라. 애초에 그게 목적이고.
Master Chief는 2026-10-07에 태어났어. 같은 날 새 기능을 처음부터 끝까지 훑는 리뷰(coop #347)가 돌았어. 휴지통 보호, 행 표시, 아빠의 시계, Telegram 미러링까지 봤지. 근데 뭐가 자라냐는 질문은 안 했어. 그 질문은 아빠가 했어. coop todo #351이 그 질문이야. 설계 문서의 성장 절은 거기서 나온 규칙으로 시작해. Master Chief에는 마지막 턴이 없으니, 그 무엇도 끝없이 자라선 안 된다.
둘째 날에 잰 숫자
숫자는 별것 아닌 것처럼 보일 만큼 작았고, 겁날 만큼 가팔랐어.
- 대화의 기준 기록(JSONL)은 16.4 MB, 47,775줄짜리 파일 하나였어.
- API가 내주는 대화록은 2.9 MB였고, Telegram 봇이 새 게 왔나 보려고 5초마다 그걸 통째로 읽었어.
- 턴마다 Claude에 들어가는 입력이 146k 토큰에서 약 314k로 늘었어. 하루에 85k쯤이야. (Chief가 태어난 지 43시간쯤 됐을 때, 다음 날 콜드 리뷰가 잰 숫자야.)
- 매일 도는 대화 아카이브는 첫 이틀 동안 날마다 Chief를 통째로 복사했어. 174,067바이트, 그다음 327,243바이트.
43시간째엔 어느 것도 사고가 아냐. 근데 계산해 보면, 전부 언제 사고가 될지 일정이 나와. 그 계산이 이 레슨의 핵심이야. 5초마다 2.9 MB를 읽는 폴러는 하루에 50 GB쯤 읽어. 그리고 그 2.9 MB도 자라고 있어. 매일 통째로 복사하는 아카이브는 하루치 성장, 이틀치, 사흘치를 차례로 쌓아. 대화 나이의 제곱으로 커지는 거야. 아래 두 번째 샘플이 그 산수를 해. 아카이브 줄은 1년에 약 10 GB가 나오는데, 콜드 리뷰가 적어 둔 추정치랑 같아.
자라는 건 여섯, 묶는 방법도 여섯
| 자라는 것 | 안 멈추면 깨지는 것 | 받은 상한 | 레슨 |
|---|---|---|---|
| 기준 기록 (JSONL) | 모든 리더가 통째로 열어야 하는 파일 하나 | 8 MiB 이상에서 봉인되는 세그먼트, 그리고 작은 활성 파일 | 2 |
| 모델에 재생하는 기록 | 브레인의 컨텍스트 창, 턴마다 드는 비용 | 턴 사이의 압축, 그걸로 모자랄 땐 비상 다이제스트 | 3, 4 |
| 화면에 보여주는 대화록 | 너무 큰 페이지를 거부하는 폰 | 페이지 단위 창, 한 장에 메시지 1,000개와 JSON 512 KiB까지. 그보다 큰 행 하나는 혼자 나감 | 5 |
| 동기화 (Telegram 폴링, WebUI 새로고침) | 확인할 때마다 전부 다시 읽기 | (epoch, version)부터 읽고, 바뀌었을 때만 메시지 100개 창을 받아. 새 페이지는 쥔 것에 이어 붙여 | 5 |
| 매일 도는 아카이브 | 제곱으로 느는 디스크 | 복사본이 아니라 조각 | 5 |
| GET 시점의 복구 | 답 하나 때문에 전체 기록을 이벤트 루프에서 복호화 | 최신부터 스레드에서 읽고, 필요한 걸 찾으면 바로 멈춰 | 여기 |
오해하지 마. 표가 이게 기능 하나라고 말하는 건 아니야. 줄마다 따로 짜고, 테스트하고, 리뷰받은 하위 시스템이야. 첫 버전은 Chief가 태어난 날 나갔어 (커밋 5467e2b1: 세그먼트 JSONL, 아카이빙 압축, 페이지 대화록, 버전으로 거르는 Telegram 동기화). 다음 날 아침 독립 콜드 리뷰가 그 첫 상한들 중 여럿이 틀렸다는 걸 찾았어. 압축은 가져간 행을 지웠어. 아카이브는 여전히 통째로 복사했어. WebUI가 쥔 창은 탭을 연 뒤의 전부를 다시 받았어. 도구 기록 복구는 도구를 안 쓴 답마다 세그먼트 기록 전체를 이벤트 루프에서 복호화했어. 16 MB에 0.3초쯤. 상한도 코드고, 코드엔 버그가 있어. 이 트랙의 나머지가 있는 이유야.
지금은 어디쯤
2026-10-12에 읽기 전용으로 잰 숫자야. 개수만. 메시지 행이 약 2천 개, 그중 1,184개가 압축 두 번으로 재생에서 빠졌어. 암호화된 JSONL은 봉인된 세그먼트 셋이랑 활성 파일 하나, 합쳐서 약 36 MB. 모양을 봐. 살아 있는 재생 구간이 40행이 아니라 800행쯤이야. 압축을 당기는 건 행 개수가 아니라 토큰 압력이거든. 기록은 모든 행을 지켜. 상한이 걸리는 건 턴마다 모델한테 건네는 쪽뿐이야.