C.W.K.
Stream
Lesson 04 of 04 · published

Citation 안 깨고 재구축

~11 min · index-is-derived, rebuild-safe, citation, recovery

Level 0불 꺼진 심지
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"인덱스 전체를 불에 던져. 처음부터 재구축해. 네가 만든 모든 citation 이 여전히 내려앉아. 마법이 아냐 — 산수야."

겉보기 모순

이제 들은 두 가지가 서로 싸우는 것 같아. 첫째: 인덱스는 파생이고 버릴 수 있어 — 의심스러우면 purge 하고 재구축하지, 절대 패치 안 해. 둘째: citation 은 내구성 있어야 해 — 저장된 citation 은 영원히 resolve 돼야 해. 근데 citation 은 인덱스 을 가리켜. 인덱스가 말썽 부릴 때마다 버리면서 어떻게 절대 안 깨지는 citation 을 가져? 서로 배타적으로 들려.

Content-addressing 이 모순을 녹여

id 가 배정될 때만 충돌해. Lantern chunk id 는 내용에서 계산되니까, 재구축은 재-라벨링이 아냐 — 정확히 같은 답에 닿는 재-파생이야. 인덱스 전체를 purge 하고, 같은 소스를 같은 얼린 profile 아래 걸으면, 모든 chunk 가 전에 가졌던 바이트 동일 id 로 재계산돼. 9f3ce1a7… 을 가리키던 citation 이 여전히 9f3ce1a7… 을 가리키고, 그 id 는 여전히 같은 문서의 같은 조각으로 resolve 돼. 버릴 수 있는 인덱스와 내구성 있는 citation 이 둘 다 참인 건 content-addressing 덕분이지 그럼에도가 아냐.

복구는 항상 purge-and-replay

이래서 Lantern 의 복구 이야기엔 수리 단계가 없어. 검색 인덱스가 오염됐거나, 어긋났거나, 그냥 의심스러우면, 고칠 행을 찾아 기어 다니지 않아. 지우고 권위 있는 소스에서 재구축해. 미묘하게 틀릴 diff-and-patch 로직도 없고, 케이스를 놓칠 화해 단계도 없어. purge, replay, 끝 — 그리고 id 가 content-addressed 라, 재구축된 인덱스는 올바를 뿐 아니라 건강한 빌드가 냈을 것과 동일해, citation 까지 전부.

결정론적 파생이 버림을 공짜로 만들어. 파생 저장소가 소스의 순수하고 결정론적인 함수로 재구축되면, 두려움 없이 버릴 수 있어: 재구축이 거기 있던 걸 정확히 재생성해. 거기에 content-addressed id 를 더하면 파생 저장소 안을 향한 참조마저 그 파괴를 살아남아. 결정론이 '그냥 재구축해' 를 완전한 복구 계획으로 만드는 거야.

두 종류의 상태, 깨끗이 이름 붙여

그래서 전체 그림엔 정확히 두 범주가 있어. 파생 상태 — FTS 인덱스, 벡터, chunk 테이블 — 는 버릴 수 있고, 결정론적 replay 로 재구축되고, 어떤 의심에도 purge 해 안전해. 귀한 상태 — captured 스냅샷, 그리고 나중엔 증거 레이어의 판단 — 는 append-only 에 보존돼, 아무것도 그걸 재생성 못 하니까. 엔진의 모든 저장소가 의식적으로 둘 중 하나야. 쥔 모든 바이트에 대해 어느 게 어느 건지 아는 것이, 자신 있게 복구할 수 있는 시스템과 건드리기 두려운 시스템의 차이야.

Code

purge, replay, 그리고 옛 citation 이 여전히 resolve 돼·python
# A citation saved long ago, on a machine since retired:
saved = {"chunk_id": "9f3ce1a7b2c4d8e0", "doc_relpath": "2026/investing/patience.md"}

# Disaster: the index is corrupt. The recovery is not repair — it's replay.
purge_entire_index()                      # throw ALL derived state in the fire
for doc in walk_declared_roots():         # same sources...
    for start, end in chunk_spans(doc, profile="md-para-v1"):   # ...same frozen profile
        cid = chunk_id(doc.sha256, start, end, "md-para-v1")     # ...same computed id
        insert(cid, doc, start, end)

fetch(saved["chunk_id"])   # -> resolves. The rebuild recomputed the SAME id.
# The index was disposable AND the citation survived. Both, because of the math.

External links

Exercise

네가 유지하는 파생 저장소를 잡아(검색 인덱스, 캐시, 생성된 리포트). 지금, 패치로 복구해 아니면 소스에서 재구축으로? 패치라면, reconcile 로직에 숨은 미묘한 버그를 상상해. 그다음 소스에서-재구축 경로를 스케치하고 — 그 저장소 안을 향한 저장된 참조가 재구축을 살아남을지 확인해. 안 살아남으면, 그게 content-addressing 틈이야.
Hint
속성 둘이 '그냥 재구축해' 를 완전한 계획으로 만들어: 재구축이 결정론적이고(같은 소스가 항상 같은 출력), 저장소 안을 향한 참조가 content-addressed 야(그래서 재구축 후 같은 걸로 resolve 돼). 둘 중 하나가 빠진 게, 사람들이 purge 를 두려워하는 이유야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.