"비디오 몫으로 잡아 둔 자리가 둘이었어. 하나는 요청 안의 필드, 하나는 클래스 계층 안의 칸. 비디오가 마침내 왔을 때 필드로는 걸어 들어왔고, 클래스는 돌아서 갔어."
잡아 둔 자리에 손님이 온 날
2026-09-21, 엔진이 local 비디오를 내놨어. open-weight 비디오 계열 셋을 엔진 자기 머신들에서 생성해. 이 quest 는 그날을 두 군데서 기다리고 있었어. ceiling matrix 는 비디오 자리를 요청 계약에 잡아 뒀지. 엔진이 첫 이미지를 뽑던 날부터 video 라고 말할 수 있었던 modality 필드 말이야. 그리고 바로 앞 lesson 은 adapter 척추 전체를 두 번째 예약에 기대 세웠어. 엔진 문서들이 하나뿐인 추상화의 다음 구현으로 이름 불러 온 VideoAdapter. 둘 다 같은 미래에 건 판돈이었는데, 결과는 서로 달랐어.
필드가 한 일
요청 계약은 설계한 그대로 버텼어. 같은 generate 엔드포인트가 이제 이미지 요청이든 비디오 요청이든 받고, modality 값이 본문을 어느 모양으로 읽을지 정해. 비디오 요청은 비디오한테 필요한 걸 들고 와. 프레임 수, 프레임 속도, 그리고 역할이 붙은 reference 들. 첫 프레임, 마지막 프레임, 참고 이미지, 참고 영상, 참고 오디오. 이미지를 부르던 쪽은 한 바이트도 안 바꿨어. 이미지 스키마는 지금도 다른 modality 를 경계에서 돌려보내는데, 이제는 그 값을 '구현 안 됨' 이라고 하는 대신 비디오 요청 쪽을 가리켜 줘. 첫날 한 줄 값이던 필드가 넉 달 뒤 완전히 새로운 종류의 일을 실어 날랐고, 어느 클라이언트도 눈치챌 필요가 없었어.
클래스가 한 일
클래스 계층은 우회당했어. local 비디오를 돌리는 녀석 이름이 심지어 VideoAdapter 야. 잡아 둔 이름을 그대로 가져다 쓴 거지. 그런데 Adapter 를 구현하지 않아. 따로 선 클래스야. local 이미지 adapter 를 협력자로 받아 들고 있는데, 비디오 job 이 메모리를 쓰기 전에 이미지 모델을 비워 내려고 그래. 비디오 계열마다 자기 네이티브 런타임을 자식 프로세스로 띄우고, 그 자식의 프로세스 그룹이 전부 거둬질 때까지 디바이스 문의 표를 쥐고 안 놔. 결과는 비디오 파일이랑 옆에 붙는 기록으로 자기 저장소에 써. 같은 날 저녁엔 업스케일이 자기 modality 를 가진 큐 job 이 되면서 똑같은 모양을 따랐어. 이름은 adapter 인데 Adapter 는 아닌 클래스가 또 하나 생긴 거야. 넉 달 된 추상 베이스 클래스는 지금도 구현이 딱 하나야. 그리고 docstring 은 아직 미래 둘을 부르고 있어. 엔진이 이미 지나친 버전 번호로 적힌 API 구현, 그리고 다른 데로 나가 버린 비디오 구현.
비디오가 그 서명을 못 입은 이유
앞 lesson 이 인터페이스가 뭘 요구하는지 보여 줬지. 모델 행 하나, progress emitter 하나, 정해진 seed 를 되써 넣을 job 기록 하나. 프로세스 안에서 도는 이미지 job 의 명사들이야. 비디오도 그중 몇 개는 같이 써. 큐에 들어가고, progress 를 알리고, seed 를 정해. 나머지는 뿌리부터 달라. 이미지가 denoise 랑 sampler 를 드는 자리에 비디오 요청은 프레임이랑 역할을 들어. 일은 이 프로세스 말고 별도 프로세스에서 벌어져. 결과물은 이미지 바이트가 아니라 비디오 파일이랑 곁들인 기록이고. 게다가 비디오가 제일 먼저 하는 일이 이미지 모델을 메모리에서 밀어내는 거라서, 이미지 adapter 가 되는 게 아니라 이미지 adapter 를 쥐고 있어야 해. 세 종류의 일이 진짜로 같이 쓰는 건 전부 클래스 아래층에 있어. 큐 하나, 디바이스 문 하나, progress 통로 하나, registry 하나, 그리고 이제 어느 머신에 맡길지 정하는 배정 단계 하나. 엔진이 실제로 공유하는 추상화는 adapter 가 아니라 job 이었던 거야. 큐 하나에 올라가는, 종류가 붙은 요청.
router 에 대한 정정
이 트랙 두 번째 lesson 은 모델의 registry 행을 읽어서 어느 adapter 가 그 모델을 맡는지 알아내는 멍청한 router 를 그렸어. 그건 설계 문서 속 router 였어. 코드에는 엔진이 첫 이미지를 뽑은 날부터 2026-09-21 까지 router 자체가 없었어. job 은 전부 하나뿐인 adapter 로 곧장 갔고, 주인을 적어 둔 registry 행은 한 번도 없었어. router 는 비디오가 올 때 드디어 생겼는데, 그 lesson 이 칭찬한 딱 그 뜻으로 멍청해. 모델마다 갈래를 치지도 않고 이름 패턴도 안 봐. 다만 registry 열이 아니라 요청의 종류를 읽어. 이미지냐, 비디오냐, 업스케일이냐가 돌릴 녀석을 골라. 새 종류의 일이 올 때나 움직이는 축에서 갈라지지, 매주 움직이는 축에서는 안 갈라져.
그사이 다른 축은 데이터가 됐어
adapter 가 기대 선 판돈, 그러니까 생성이 서로 다른 곳에서 벌어진다는 건 결국 맞았어. 서브클래스 모양으로 맞은 게 아니었을 뿐이야. 애초에 자기 문으로 나갔던 closed-weight subsystem 이 엔진의 Pro 작업 흐름으로 자랐어. 이제 그 카탈로그에는 지시로 편집하는 local 모델이 vendor provider 들이랑 나란히 올라가 있어. 카탈로그 행마다 어디서 실행되는지, 어떻게 과금되는지도 적혀 있고. local 모델은 따로 돈을 안 받고, 기본값이 된 Codex provider 는 구독제, vendor API 는 쓴 만큼 크레딧을 깎아. 위치가 열 하나가 된 거야. local 행은 여전히 척추를 지나가. 큐, 배정, local adapter, 경우에 따라 다른 머신까지. 나머지 행은 그 자리에서 바로 돌고. 그러니까 이 추상화가 받아 내려던 변화는 엔진이 내주는 카탈로그가 받아 냈고, 그 변화가 살 거라던 클래스엔 여전히 멤버가 하나야.
그럼 이제 죽은 껍데기야?
좁은 경계 lesson 의 규칙이랑, 마지막 트랙의 '한 군데로만 보내는 router 는 지워' 가 세운 규칙을 정직하게 대 봐. 구현 하나. 이름 붙은 두 번째 후보 둘. 하나는 만료됐고 하나는 다른 클래스로 나갔어. 추상화 뒤에 서 있는, 이름 붙고 관리되는 두 번째는 이제 없어. 이 quest 자기 잣대로 보면 Adapter 베이스 클래스는 이제 지우기 후보야. 엔진은 아직 그 걸음을 안 뗐어. 베이스 클래스도 docstring 도 그대로 있어. 딴 데서 일어난 미래 둘을 기리는 작은 기념비처럼. 이렇게 말하는 건 엔진을 향한 판결이 아니야. 이 트랙이 가르친 점검을 이 트랙 자기 척추에 돌려 본 것뿐이야.
VideoAdapter 라서 이름으로 찾으면 걸리고, 찾은 사람은 예약이 지켜졌다고 결론 내려. 아니라고 말해 주는 건 그 클래스의 첫 줄, 뭘 상속하느냐뿐이야. 예약은 이름이 아니라 코드가 뭘 상속하고 뭘 구현하는지로 점검해.