"모든 발견 surface는 canonical entry와 정확한 채택 버전으로 돌아가야 해."
우물이 자라는 방향
우물이 자라면 길어 올리기만큼 돌아가기도 중요해. 검색은 같은 엔트리와 오래 남은 상태로 이어져야 해. 따라 읽기는 먼저 끝난 draft가 아니라 채택된 text version을 말해야 해.
작은 계약으로 붙여
query할 때 live corpus row를 entry id와 keyword, 원문, 번역 text가 든 SearchDoc으로 투영해. 따라 읽기는 caller가 고른 text와 lang을 TTS에 보내고 돌아온 byte를 stream해.
확장이 주권을 훔칠 때
두 번째 search나 audio store를 영속화하면 drift가 생겨. 현재 검색은 canonical row에서 projection을 다시 만들고 음성은 on-demand라서 둘 다 text의 두 번째 주인이 되지 않아.
처음 약속으로 다시 시험해
이 기능이 생겨도 원문이 먼저고 펜은 저자 손에 있으며 늦은 결과는 허락을 물어야 해. 공유와 scheduler, search, audio가 각자 편의를 위해 원문 복사본이나 숨은 clock, 무제한 payload를 만들지 않는지 따라가. 새 기능이 오래된 불변식을 우회하면 성장한 게 아니라 다른 제품이 된 거야.
끝까지 실행해
글을 수정한 뒤 다음 search projection과 on-demand read-along 요청을 따라가. 정상 경로와 함께 중복 호출, source edit, 삭제, stale artifact, 권한 거절을 넣어. 화면의 한 번 성공보다 database row와 outbound payload, sibling reference가 같은 이야기를 하는지 증명해.
우물을 닫는다는 것
닫는 건 기능을 멈춘다는 뜻이 아니야. 한 번의 필사가 원문 생성에서 종이, 복구, 다시 찾기, 선택 공유까지 완결된다는 뜻이야. 그 사이 기술이 자신을 설명할 때만 보이고 나머지 시간에는 잉크 뒤로 물러나면 우물이 제대로 손을 얻은 거야.
이 확장의 실제 계약
검색은 live entry와 keyword, translation text로 in-memory SearchDoc을 만들고 canonical entry id를 돌려줘. 따라 읽기는 선택한 text와 lang을 TTS에 보내 byte를 stream하며 audio artifact table을 만들지 않아.
새 기능의 첫 질문은 “할 수 있나?”가 아니라 “원문 우선 약속을 깨지 않고 어디에 붙나?”야. 오래된 불변식이 새 경로에서도 같은 말을 해야 해.