"구현이 둘이라고 가르쳤는데 하나야. 자리는 맞는 데 냈어. 틀린 건 그 자리를 설명한 문장의 시제였고."
앞에서 한 약속
네 lesson 전에 엔진의 단 하나뿐인 추상화를 이렇게 변호했어. 생성은 진짜로 다른 두 세계에서 벌어진다고. 내 GPU 에 올린 weight 랑, HTTP 로 부르는 closed-weight vendor. 그 진짜 갈림길이 Adapter 경계 하나를 벌어 준 거라고. 구현 둘, 좁은 인터페이스 하나, 다른 최상위 seam 은 없음. 깔끔한 논증이었고, 고른 축도 맞는 축이었어.
실제로 나온 것
closed-weight 는 오긴 왔어. 그 자리로는 안 왔고. 자기 route, 자기 요청 스키마, 자기 기록 저장소, 자기 용어를 들고 별도 subsystem 으로 나왔어. adapter 척추 뒤가 아니라 옆에 나란히 선 거지. 추상 베이스 클래스는 지금도 docstring 에 API 구현을 어느 버전 몫으로 적어 두고 있는데 엔진은 그 번호를 이미 지나쳤고, 엔진 자기 점검 엔드포인트는 adapter 를 하나만 돌려주면서 이 어긋남을 문장으로 인정하는 note 를 같이 달아 줘. 그러니까 엔진의 단 하나뿐인 추상화는 오늘 기준으로 구현이 정확히 하나야.
두 번째 세계가 그 몸을 못 입은 이유
인터페이스가 실제로 뭘 요구하는지 봐. 이 registry 행을 네가 맡느냐고 물어. 돌릴 땐 progress emitter 랑 job 기록을 같이 건네주고, 레시피의 랜덤 seed 가 정해지고 나면 실제로 쓴 seed 를 그 기록에 되써 달라고 하고. 전부 job 수명주기의 명사야. 그리고 하나도 빠짐없이 local 쪽에서 온 거고. 큐에 들어가고, 단계마다 progress 를 흘리고, seed 를 정하고, 도중에 취소되는 GPU 작업 말이야.
이제 vendor 호출이 뭘로 이뤄져 있는지 봐. provider, aspect ratio, 해상도 등급, reference 이미지 목록. 그리고 요청 필드는 아니지만 설계에서 무시할 수 없는 게 하나 더, 호출당 비용. registry 행 없어. seed 없어. progress 를 흘릴 단계도 없고. 겹치는 명사가 prompt 하나뿐인 두 요청은 한쪽이 대부분을 시늉하지 않고는 같은 메서드 서명을 못 나눠 가져. 그게 바로 좁은 경계 lesson 이 경고한 넓은 인터페이스 실패야. 다만 뒷문으로 들어온 거지. 자리를 낸 다음에 인터페이스가 넓어졌으니까.
날짜가 말하는 건 첫날이야
이건 정확하게 짚고 가야 해. 어떤 종류의 정정인지가 여기서 갈리거든. 엔진은 추상 베이스 클래스를 로컬 구현 하나만 뒤에 달고 내놨고, closed-weight 는 따로 내놨어. 둘 다 이 quest 가 나오기 전에. 어긋난 게 아니야. lesson 은 나가는 그날 계획을 적고 있었고, 그걸 알아채는 데 차가운 눈으로 디렉터리를 열어 본 리뷰어가 필요했던 거야. 애초에 참인 적 없던 주장은 진화가 아니야. 정정이지. 그리고 지금 읽는 게 둘 중 뭔지 말해 주는 게 정직한 거고.
그럼 이건 죽은 껍데기야?
이 상황을 위한 규칙이 이 quest 안에 이미 있어. 그리고 지금 그 규칙을 quest 자기 아키텍처한테 들이대는 거고. concrete-first 는 변화가 사라진 추상화는 죽은 껍데기라고 말해. 값 하나짜리 enum 은 지우고, 한 군데로만 보내는 router 는 접고, 진짜 두 번째가 오면 그때 다시 들이라고. 그 잣대로 보면 구현 하나짜리 Adapter 는 지우기 후보야.
살아남아. 근데 docstring 이 말하는 그 이유 때문은 아니야. 그리고 그 차이가 이 lesson 에서 제일 날카로운 대목이고. 좁은 경계 lesson 이 준 구분선은 이거야. 짐작으로 만든 추상화는 구현이 하나고 두 번째에 대한 구체적인 계획이 없어. 잡아 둔 seam 은 구현이 하나고, 두 번째에 이름이 붙어 있고, 그 이름이 아직 관리되고 있어.
정직하게 대 보면 API 예약은 떨어져. 엔진이 이미 지나친 버전 번호로, 아무도 안 고친 docstring 안에 적혀 있거든. 그동안 현행 아키텍처 문서는 closed-weight 가 갈라져 나간 걸 의도된 결정이라고 적어 두고, adapter 는 나중에 어떤 클라이언트가 그 job 인터페이스를 진짜로 필요로 하면 그때 다시 보겠다고만 해. 그건 계획이 아니라 조건문이야. API 쪽 seam 은 아무도 부고를 안 낸 채로 만료된 예약이지.
이 추상화를 살려 두는 건 다른 예약이야. 이 quest 가 두 track 전에 이미 가르쳐 준 그거. local 비디오는 ceiling matrix 에서 인터페이스로 잡아 뒀고, 엔진의 현행 아키텍처 문서들에서 지금도 자기 adapter 클래스로 이름이 불려. 이유까지 붙어서. 비디오는 메모리랑 시간 씀씀이가 달라서 구현을 따로 둬야 한다고. 그 예약은 살아 있어. 그러니까 seam 은 남아. 비디오가 떠받쳐서 남는 거지, 다들, 이 quest 까지 포함해서, 계속 들먹이던 API 쪽 덕분이 아니라.
원래 논증이 맞힌 것
거의 다 맞혔어. 진짜 변화 축 하나, 추상화 하나, 나머지는 아무것도 갈아 끼울 수 없게. 그 규율은 지켜졌고 엔진은 지금도 두 번째 최상위 seam 을 안 내놨어. 어디를 자를지 건 판돈은 맞았어. 틀린 건 시제였어. 계획된 구현을 현재형으로, 이미 딴 판돈처럼 적은 거. lesson 은 갈림길이라고 주장했지만 그건 끝까지 계획이었고, 그 계획은 그 뒤로 장례식도 없이 만료됐어. 이건 아키텍처 잘못이 아니야. 보고 잘못이지. 그리고 보고 잘못이야말로 코드는 멀쩡히 그 자리에 있는데 모두의 머릿속 그림만 슬금슬금 어긋나는 방식이고.