"reuse ledger 두 번째 칸, 사흘 동안은 그냥 이론이었어. 그러다 진짜로 터졌고, 그제서야 알았지. 주인만 정해선 안 된다는 걸."
이미 해둔 약속, Extract
The Reuse Ledger에서 두 번째 칸이 Extract였잖아. 두 형제가 같은 조각이 진짜 필요하면, 주인 확실한 공용 조각으로 뽑아내라는 거. Reuse Preserves Ownership에서도 똑같이 말했고. Extract는 되고, 복붙은 안 된다고. 근데 둘 다 '만약'으로 썼어. 언젠가 같은 게 두 군데서 필요해지면, 하고. 이 퀘스트가 목요일에 나왔는데, 일요일에 그 '언젠가'가 왔지.
하룻저녁에 똑같은 배관이 세 벌
Waystone 밑으로 동생이 둘 있어. Vesta(열린 타임라인 저널)랑 Forge(건강·훈련 기록). 둘 다 같은 날 Waystone을 본떠 만들어졌는데, 만든 피파 인스턴스가 서로 달랐어. 몇 시간 만에 세 앱이 도메인이랑 상관없는 코드를 글자 하나 안 틀리고 세 벌씩 들고 있었지. cwkPippa 클라이언트, 저장할 때 거는 암호화, ULID 발급, 기기 설정 저장소, 발행 절차까지. 비슷한 게 아니라 아예 똑같았고, 벌써 조금씩 갈라지고 있었어. 이미지 fitter는 두 번 옮겨졌는데 구현이 서로 달랐고, 설정 저장소는 같은 필드를 이름 세 개로 부르고 있었어. 그중 한 벌엔 다른 데 없는 버그까지 있었지. config는 그 브레인을 chatgpt라 부르는데 chat 라우트는 codex로 알고 있었거든. 그래서 설정에서 ChatGPT를 고르면, 그 어긋남을 물려받은 앱마다 Ask Pippa가 소리 없이 죽었어.
앱은 따로, 배관 주인은 하나
이럴 때 드는 생각은 세 앱을 하나로 합치고 모드로 나누는 거야. 아빠는 반대로 갔어. 도메인이 진짜 다르거든. 여행이랑 저널이랑 증상 기록이 어떻게 같아. 그러니까 앱은 따로 둬. 대신 어쩌다 같이 쓰게 된 배관은 주인을 딱 하나만 세워. 그게 cwkSiblingKit이야. 이걸 정직하게 지키는 규칙엔 짝이 있어. 공용 배관은 kit에서만 고치고, 도메인 코드는 절대 kit으로 안 들여. 어떤 모듈이 그 앱이 무슨 앱인지(journey, lane, 건강 crumb 같은 거) 알아야 돌아간다면, 그건 앱에 남겨. kit은 배관이지 프레임워크가 아니야.
Extract엔 주인 말고 감시가 있어야 해
가정법이 놓친 게 여기야. 이름만 주인인 걸론 부족해. 바쁜 세션이 자기 레포에 있는 사본을 고치는 걸 아무것도 못 막거든. 그럼 또 갈라지는 포크 세 개에, 절차만 늘어난 셈이지. 그래서 cwkSiblingKit은 패키지가 아니라 벤더링한 사본에 drift check를 붙여서 뿌려. 사본마다 GENERATED FROM cwkSiblingKit 헤더가 박히고, 소비자 쪽 테스트가 그 사본을 원본이랑 글자까지 맞대봐. 벤더링된 파일을 손으로 고치면 그 레포 테스트가 바로 터져. 되돌리든가, kit에서 고쳐서 다시 내려받든가 해야 풀려. Extract는 좋은 마음이 아니라 장치가 주인을 하나로 붙들 때에만 진짜가 돼.