"재구축할 수 있으면, 절대 수리하지 마. 재구축 못 하면, 그건 파생물이 아냐 — 그리고 넌 그걸 알아야 해."
두 종류의 상태, 그리고 어느 건지 알아야 해
Recall 의 모든 행은 둘 중 하나고, 유지보수 이야기 전체가 어느 건지 말할 수 있느냐에 달렸어:
- durable 상태 — 지우면 진짜 잃는 것들: 영상 record, 불변 run, release, 교정, job 이력. 이게 진실이야. 한 번 authored 되고, 버전 있고, 다른 어디서도 재생성 안 돼.
- 파생 상태 — durable 진실에서 계산된 투영: 전문 index, 품질 지표, (언젠가) vector index. 뭐든 지워도 아무것도 안 잃어, 재계산할 수 있으니까.
이 분류는 사소한 bookkeeping 이 아냐. 수리 절차를 결정해, 그리고 틀리는 게 시스템이 썩는 길이야.
파생 상태의 수리는 딱 하나: 재구축
검색 index 가 release 랑 어긋났다 치자 — 투영 중 크래시, 옛 버전의 버그, 뭐든. 경험 있는 엔지니어라면 다들 reconciliation 스크립트에 손 뻗어: index 를 release 와 diff 하고, 차이를 찾고, patch 해. 수술적이고 효율적으로 느껴져. 틀린 수야, 그리고 Recall 은 그걸 대놓고 금지해.
이유가 여기 있어. 그 patch 스크립트는 투영의 두 번째 구현이야 — index 에 뭐가 있어야 하는지 정하는 새 코드가, 이미 그걸 정하는 진짜 투영 코드 옆에 사는 거지. 진실 하나의 구현 둘, 그리고 갈라질 거야, 투영이 바뀔 때 아무도 reconciler 를 업데이트 안 하니까. 이제 조용히 살짝 틀린 행을 쓰고 고쳤다고 부르는 수리 도구가 있어. patch 가 버그 사는 데야.
맞는 수는 더 단순하고 지루해: 영향받은 파생 행을 purge 하고 durable 소스에서 replay 해. 투영 코드가 이미 있고 index 가 뭐여야 하는지 아는 유일한 거야. 다시 돌려. diff 없음, 두 번째 구현 없음, 갈라짐 없음. 이게 정확히 materialized view 야: 손으로 편집하는 테이블이 아니라 refresh 하는 cache. 그리고 형제 두뇌가 따르는 같은 규율이야 — 그 파생 mirror 가 어긋나면, 자기 append-only 진실에서 purge 하고 replay 하지, 절대 reconcile 안 해.
널 정직하게 유지하는 테스트
그러니 네가 소유한 모든 상태에 돌릴 질문이 여기 있어: 이걸 통째로 지우면, durable 한 뭔가에서 재구축할 수 있어?
- 응 → 파생물이야. 절대 patch 하지 마. 유일한 수리는 purge-and-replay 고, 마음 내키면 돌릴 수 있어야 해.
- 아니 → durable 이야, 네가 의도했든 아니든. 버릴 수 있는 cache 로 다뤄왔으면, 두 번 생각 없이 지울 것 안에 선언 안 된 진실이 앉아 있는 거야.
두 번째 경우가 위험한 놈이고, 놀랍도록 흔해: 아무도 재계산 못 하는 계산된 field, 뭔가의 유일한 사본을 쥔 cache, 소스가 더는 안 가진 행을 품은 index. 그걸 찾아 선택을 강제해 — 진짜 durable 하고 버전 있게 만들거나, 진짜 재구축 가능하게 만들거나. 못 하는 건 그 사이에 두는 거야, 사이 상태는 누가 그걸 cache 로 다루는 첫날 잃을 진실이니까.