"log 가 truth 야. DB 는 log 가 들려주는 이야기고 — 다시 들려줄 수도 있어."
log 가 canonical 이야
Forge 는 데이터를 두 번 저장하고, 그중 하나만 truth 야. ~/cwk-dbs/forge-db/ 아래 append-only JSONL op-log 가 모든 mutation 을 기록해: crumb 추가, crumb 수정, interpretation 작성, analysis artifact 생성, module 변경. 그 log 가 ground truth 야. WAL 로 도는 SQLite 는 쿼리·aggregate·client 를 서비스하는 derived mirror 고. 어느 게 어느 건지 내면화하면 버그 한 부류가 통째로 사라져 — DB 가 지켜야 할 게 아니라 다시 지을 수 있는 것뿐이니까.
보이기 전에 써
순서 규칙은 엄격해: 모든 이벤트가 아빠한테 보이기 전에 JSONL 에 durable 해. canonical log 에 먼저 쓰이지 않은 건 화면에 아무것도 안 나타나. 이게 cwkPippa 가 대화에 쓰는 같은 'write before show' 규율이고, 크래시나 멈춘 프로세스가 UI 뒤에 truth 를 남기지 못하는 이유야. 화면은 언제나 log 의 하류야 — log 는 화면이 보여준 걸 기록한 게 아니라, 화면이 log 가 쥔 걸 보는 view 야.
애초에 왜 두 store 인가
log 가 truth 면, 왜 SQLite 를 두나? log 는 durability 엔 완벽하지만 질문엔 형편없으니까. '이번 달 symptom site 보여줘' 는 쿼리고, 쿼리는 처음부터 모든 이벤트를 replay 하는 게 아니라 index 와 folded row 를 원해. 그래서 Forge 는 읽기용으로 log 를 SQLite 에 fold 하면서 truth 용으로 log 를 지켜 — 각 store 가 잘하는 일을 해. 규율은 오직 둘을 헷갈리지 않는 것: mirror 는 빠르고 disposable, log 는 쿼리는 느려도 잃을 수 없어.