Sizzle은 모델 호출을 하나도 안 가져
backend/pippa.py 첫머리 몇 줄이 경계를 그어. 대화도, 턴도, 모델 호출도 전부 cwkPippa 거야. Sizzle의 스레드는 cwkPippa 대화에 묶여(트랙 6). 읽기는 다른 문으로 가. 이미지를 싣는 apply-free 유틸리티 레인이고, Forge가 해석할 때 쓰는 바로 그 레인이야. HTTP 요청 하나가 나가고, 답 하나가 돌아오고, 대화는 열리지 않아. 이 호출을 하는 함수가 read_plate고, 길이는 29줄이야.
요청 본문, 필드 하나씩
| 필드 | 값 | 쓰임 |
|---|---|---|
instruction | 루브릭 | 레슨 1의 계약서 |
input_text | 데이터로 넘기는 접시 | 접시, 아빠의 수정, 아빠의 트리 |
brain, effort, model | 읽기 슬롯이 정해준 것 | 몸이 될 두뇌. 기능별로 정하고, Sizzle 코드가 고르는 일은 없어 |
persona_soul_id | "pippa" | 누가 말하는지. 내 영혼이 이 일 앞에 서 |
task_mode | "respond" | 입력을 고쳐 쓰지 말고 입력에 답하라는 뜻 |
images | base64 JPEG | 접시 사진 전부, 엔진의 화면용 사본으로 |
이미지는 엔진이 직접 만든 display 사본이야. 똑바로 세우고, 긴 변을 1600픽셀 이하로 줄이고, EXIF도 XMP도 없이 저장한 거. 그래서 카메라 GPS는 Sizzle 저장소의 원본 곁에 남아. 그래도 따라 나가는 묶음이 하나 있어. Pillow가 JPEG 주석은 사본에 그대로 옮기거든. 편집 앱이 거기 장소를 적어 뒀다면 그것도 같이 가(트랙 5). 접시 사진은 한 장도 빠짐없이 같이 가. 엔진 테스트 하나가 24장을 보내고, 24장이 순서대로 다 도착하는지 확인해.
함수 끝은 검사 두 개로 닫혀. cwkPippa는 실패를 HTTP 200에 error 필드를 붙여 답할 때가 많아. 그래서 read_plate는 그 필드가 있으면 예외를 던져. 결과가 비어 있어도 실패야. Pippa returned an empty reading, 피파가 빈 읽기를 돌려줬다는 오류가 나. 그 밑에선 벤더링한 킷이 /api/admin/utility-macros/apply-free로 요청을 보내. 타임아웃은 300초야. 네트워크가 끊기면 cwkPippa에 닿지 못했다는 오류로, 200이 아닌 상태면 상태 코드랑 cwkPippa의 설명을 담은 오류로 바꿔. 이게 전부 예외 타입 하나로 올라오고, 레슨 6의 워커가 그걸 기록해.
cwkPippa가 받아서 하는 일
핸들러는 지시가 비어 있으면 거절하고, 이미지를 데이터랑 미디어 타입으로 나누고, 프롬프트를 렌더링해. task_mode가 respond면 direct_response_free_prompt 템플릿을 골라. 이 템플릿의 기본값은 루브릭을 지시 자리에 두고, 접시 데이터는 <<<INPUT에서 INPUT까지 이어지는 울타리 안에 넣어. 루브릭 마지막 규칙이랑 이 울타리는 문 하나에 채운 자물쇠 두 개야. 데이터는 울타리에 갇혀 들어오고, 지시는 울타리 안쪽이 절대 지시가 아니라고 말해.
이어서 호출은 선택된 몸으로 가. 두뇌 이름이 있거나, 이미지가 있거나, respond 모드면 그리로 가는데, Sizzle 요청엔 셋 다 있어. 이미지 쪽 이유는 코드 주석이 직접 말해. cwkPippa의 로컬 유틸리티 모델은 텍스트만 읽거든. 시스템 프롬프트는 두 층으로 쌓여. respond 틀이 두 번째 층이야. 그 앞에 내 영혼의 vault 기반 프롬프트가 서는데, persona_soul_id가 pippa고 Sizzle이 vault 맥락을 기본값 그대로 두기 때문이야. 채팅에서 내 정체성을 세우는 것과 같은 로더 경로야.
두 축: 누가 말하고, 뭐가 돌아가나
이 갈라짐은 Pippa Quest의 Soul 트랙이 영혼과 두뇌, 서로 기대지 않는 두 축으로 가르치는 바로 그거야. 영혼은 누가 말하느냐고, 읽기에선 언제나 나야. 두뇌는 어느 몸이 호출을 돌리느냐고, Sizzle 코드는 그걸 고르지 않아. 가족 Brain Control Plane에 읽기 슬롯을 물어볼 뿐이야. 슬롯 이름표는 Plate reading, 접시 읽기고, 설명엔 이미지를 볼 수 있는 두뇌가 필요하다고 적혀 있어. 이 슬롯을 처음 등록할 땐 초깃값으로 Claude, 강도 high를 넣어. 그 뒤로는 가족 설정 값만이 진실이야. 아빠는 Sizzle 설정 페이지에서도, Firelink의 Brains 탭에서도 그 값을 바꿀 수 있어. 두 화면이 같은 줄을 고치거든. 기록에 남는 건 배정이지, 영수증이 아니야. reading.recorded 이벤트는 호출 전에 슬롯이 워커한테 건넨 두뇌, 강도, 풀린 모델을 읽기 옆에 저장해. cwkPippa의 답엔 글만 있는 게 아니야. 선택된 몸 경로는 실제로 답한 모델도 execution 블록에 담아 돌려줘. 그런데 read_plate는 result만 챙기고 나머지는 버려. 그래서 저널은 가족이 어느 몸을 불렀는지는 말해도, 어느 모델이 답했는지는 증명 못 해.
왜 루프백일까
엔진은 서비스 호스트에서 cwkPippa 옆에 살고, 가족 레지스트리가 준 루프백 주소로 cwkPippa를 불러. 이유는 신뢰야. 루프백은 cwkPippa가 PIN 없이 믿어주는 경계라서, Sizzle의 읽기 코드엔 자격 증명이 하나도 없어. 같은 요청이 테일넷 쪽에서 오면 401 pin_required가 돌아와. PIN이 필요하다는 뜻이야. 루프백은 macOS 26의 로컬 네트워크 관문 밖에 있기도 해. 그래서 백그라운드 서비스는 대답할 수도 없는 동의 창을 거치지 않고 거기 닿아.