"경계는 버텼어. 배관이 안 버텼지. 그게 좋은 쪽 실패인데도 다시 쓰는 값을 치렀어."
현실이 된 문장
지난 레슨은 조건부 약속을 했어. 만약 Recall 에 "이 영상에 대해 물어보기" 기능이 생긴다면, 형제 엔진들이 하는 것과 똑같이 이미 빌려 쓰는 brain 의 대화에 바인딩할 거라고. 자기 모델도, 두 번째 정체성도 절대 없이. 그건 아키텍처로 쓴 문장이야. 그리고 그건 아무도 아직 그걸 데리고 살아본 적 없을 때 썼다는 말의 공손한 표현이고.
그리고 기능이 도착했어. Video Detail 이 이제 transcript 옆에 접히는 dock 을 띄우고, 약속한 그대로 동작해. dock 은 brain 자기 표면을 embed 한 뷰고, 거기 나열되는 대화들은 brain 자기 저장소에 있는 평범한 대화야. 정확한 release 하나당 하나씩. dock 도, 전체 brain 인터페이스도, 그 아카이브 폴더도 전부 같은 대화를 읽어. Recall 을 위해 새 대화 기계장치를 발명한 것도 없고, 마이그레이션한 데이터도 없고, 아카이브 엔진이 '대화란 무엇인가' 에 대한 의견을 갖게 된 것도 없어.
이걸 이름뿐이 아니라 진짜로 깨끗하게 지키는 디테일이 둘이야. embed 된 뷰는 origin 경계를 넘어 Recall 로 되돌아 못 뻗으니까, 완전한 release 신원이, 그러니까 영상과 release 와 content hash 와 버전 번호와 제목이 그걸 여는 URL 에 실려 가. 그리고 brain 은 transcript 를 통째로 건네받지 않아. 읽기 전용 도구로 필요할 때 segment 를 읽어. 그래서 긴 transcript 가 그걸 보여주는 표면을 막는 일이 없어. 수정이 일어났을 때 이미 진행된 대화 밑의 증거가 슬쩍 바뀌는 대신 새 context 가 생기는 것도 같은 이유야. 대화는 정확한 release 를 이름으로 부르고, 정확한 release 는 절대 움직이지 않으니까.
말할 값어치가 있는 부분: 첫 버전이 틀렸어
깔끔한 설명이 빼먹은 게 여기 있어. 첫 구현은 dock 이 아니었어. 빈 팝업을 열고, 그다음 POST 요청 안에서 모델 턴을 통째로 돌리는 버튼이었어. transcript segment 를 최대 이천 개까지 읽고, 높은 effort 로 생각하고, 제목 방향 몇 개를 만들어내면서. 그동안 브라우저는 정적인 빈 페이지에 앉아 있었고. 잠깐이 아니라 몇 분씩. 아빠의 평은 짧았고 전적으로 받아 마땅했어. 시스템 통틀어 최악의 파이프라인이자 UI 라고.
이제 그걸 트랙 2 의 3번 레슨에 대고 읽어봐. 이 퀘스트가 직접 가르치는 그 레슨. 요청은 긴 일을 절대 소유하면 안 된다. 엔진은 그걸 번호 붙은 invariant 로 적어놓기까지 했어. 아카이브 파이프라인은 어디서나 그걸 지켜. batch 는 큐에 넣고, worker 가 시간을 소유하고, 노트북을 덮어도 아무 일 없어. 그런데 시스템의 가장 새로운 이음매에서, 그 규칙을 제일 잘 아는 사람이, 아무도 확인할 생각을 안 한 그 한 자리에서 규칙을 깼어. 파이프라인이 아니라 통합에서.
늘 따라오는 동행들도 같이 왔지. 같은 외부 요청 id 를 다시 보내서 유일성 충돌을 엉뚱한 에러 메시지로 드러내는 재발화 경로. 그리고 턴이 진짜로 넘겨버릴 수 있는 클라이언트 타임아웃. 브라우저가 포기한 뒤에도 서버에서는 토큰을 계속 태우고 있었고. 이것들은 희귀한 버그가 아니야. 아무도 규칙을 적용하지 않은 자리에 항상 자라나는 것들이야.
경계 말고 표면을 고쳐
달콤한 수리는 턴을 빠르게 만드는 거야. segment 를 줄이고, effort 를 낮추고, 타임아웃을 올리고. 전부 요청이 일을 계속 소유하게 두면서 위반만 덜 보이게 만들어. 실제 수리는 턴을 사람에게 돌려주는 거였어. 여는 동작이 요청 안에 모델 작업이 전혀 없는 즉시 바인딩이 되고(라이브 시스템에 대고 81 밀리초로 측정, 이전의 몇 분에 맞서), 첫 턴은 사람이 추천 프롬프트를 눌러서 시작하는 눈에 보이는 스트리밍 턴이 됐어. 요청은 요청이 하는 일로 돌아간 거지. durable 한 의도를 기록하고 반환하기.
그리고 이 사건 전체에서 들고 나갈 구분이 이거야. 대화 모델은 내내 옳았어. 불변 release 하나당 정식 대화 하나, 공유된 폴더, 읽기 전용 도구. 전부 손대지 않은 채 살아남았어. 틀린 건 표면뿐이었어. 뭔가 망가진 느낌이 들 때 이 둘을 안 가르면, 맞았던 쪽을 다시 쓰는 걸로 "고치게" 되고, 등 뒤에 더 많은 작업을 쌓은 채 더 나쁜 데 도착하게 돼.
그러니까 예언은 지켜졌고, 지킨 것만으로는 부족했어. 아키텍처는 물건이 정확히 어디 속하는지 알려주면서도 거기에 나쁘게 짓는 걸 허락할 수 있어. 가장 오래된 규칙은 가장 새로운 이음매에서 깨져. 그 규칙을 구현하려고 쓴 코드에서가 아니야. 거긴 뻔하고 테스트도 잘 돼 있거든. 자기가 이미 그 규칙을 이해한다고 확신하는 사람이 새 표면을 붙이는 자리에서 깨지는 거야. 표면을 추가할 땐 자기 invariant 를 그 표면에 대고 다시 읽어. 본능이 대신 안 해주는 유일한 자리거든.