C.W.K.
Stream
Lesson 03 of 04 · published

composer trio, 비타협

~10 min · composer-trio, attachments, prompt-macro, ask-pippa

Level 0식은 화로
0 XP0/34 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"셋 중 하나라도 빠진 composer 는 단순화된 게 아니라 미완성 구현이야."

세 능력, 모든 표면

Vesta 의 모든 입력 표면 — 스트림 composer, crumb 에디터, draft 소스 에디터, 미래의 어떤 캡처 시트 — 가 같은 세 능력을 지녀. 첨부(이미지, PDF, 파일). Prompt Macro(로컬 draft 위 preview-first projection). Ask Pippa(바인딩된 canonical 대화). Waystone 에서 상속했고 이유가 있어 invariant 로 명시돼 — 셋 중 둘만 내는 composer 는 가벼운 버전이 아니라 망가진 거야. trio 는 'Vesta 에서 작성' 이 뭔지의 baseline 이고, 다리 하나를 떨구는 게 조용히 제품을 바꿔.

첨부는 진짜 바이트로 resolve 돼야 해

첨부 다리는 trio 전체에서 가장 날카로운 invariant 를 져, PippaGo 에서 상속한 것 — 첨부는 실제 바이트와 미디어 타입으로 resolve 돼야 해 — 파일명만 있는 payload 와 침묵하는 텍스트-전용 fallback 은 금지야. 빡센 규칙으로 명시된 이유는 실패가 호출 지점에서 안 보여서 야. composer 가 이미지 바이트 대신 'photo.jpg' 문자열을 보내면, 아무것도 에러 안 나 — 요청이 나가고, 답이 오고, 다 괜찮아 보여 — Pippa 가 그 사진을 실제론 못 봤고 텍스트-전용 메시지인 양 조용히 답한 것 빼곤. 볼 수 있는 버그는 고쳐지고, 성공처럼 보이는 버그는 배포돼. 그래서 첨부 resolution 은 희망이 아니라 강제야 — 바이트와 미디어 타입, 아니면 첨부를 시끄럽게 거절.

위험한 실패는 안 보이는 것들이야. 크래시는 실패했다고 알려줘. 침묵하는 텍스트-전용 fallback 은 아무것도 안 알려줘 — 작동하는 멀티모달 기능처럼 보이면서 조용히 modality 를 떨궈. 실패 모드가 호출 지점에서 안 보일 땐, 코드 주석으로 부족해 — 나쁜 상태를 시끄럽게 거절하는 강제된 invariant 가 돼야 해, '작동한 것처럼 보임' 이 아무도 디버깅 안 하는 딱 하나의 실패니까.

Prompt Macro: preview-first, 절대 두 번째 뇌 아님

Prompt Macro 다리는 저장된 지시를 로컬 draft 위에 돌리고 preview 를 보여줘 — 네가 받기 전엔 draft 를 절대 안 변형하고, 절대 두 번째 Pippa 엔진으로 자라지 않아. 두 필드가 따로 남아 — 매크로의 지시(뭘 할지)와 composer 의 입력 텍스트(재료). 둘을 떼놓는 게 매크로를 draft 간 재사용 가능하게 하고 '내가 쓰는 것' 을 '내가 청하는 변환' 과 구별되게 유지해. 네 draft 위 projection 이고, 승인 받으려 내밀어져 — 조립이랑 같은 consultation 자세, composer 규모에서.

Ask Pippa: 바인딩된 대화지, crumb 아님

Ask Pippa 다리는 각 타이핑된 context 를 하나 이상의 평범한 canonical cwkPippa 대화에 바인딩해, origin_surface='vesta' 로 표시하고 서버-소유 VESTA 폴더에 투영해. 경계의 요점 전부: Ask Pippa 스레드는 대화지 crumb 이 아냐. 그 전체 history, 첨부, 도구, transcript 는 cwkPippa-소유로 남고, Vesta 는 바인딩만 쥐어. 그 질문이 그날의 항목이 되지 않고 하루에 대해 Pippa 한테 물을 수 있어 — consultation 과 저널이 깔끔히 분리되고, 뇌는 저널로 fork 되는 대신 canonical 로 남아.

Code

첨부: 바이트+타입으로 resolve, 아니면 시끄럽게 거절·typescript
type Attachment =
  | { ok: true;  bytes: Uint8Array; mediaType: string; name: string }
  | { ok: false; reason: string };

function resolveAttachment(file: File): Attachment {
  if (!file.type) return { ok: false, reason: "no media type" };      // reject
  const bytes = readBytes(file);
  if (!bytes?.length) return { ok: false, reason: "no bytes" };        // reject
  return { ok: true, bytes, mediaType: file.type, name: file.name };
}

// FORBIDDEN (the PippaGo invariant): sending just the name
//   send({ attachment: file.name })  // <-- looks fine, Pippa never sees it
// A silent text-only fallback is the invisible bug the invariant exists to kill.

External links

Exercise

첨부를 받는, 네가 만들었거나 쓴 멀티모달 기능을 찾아. 실제로 뭐가 wire 를 건너는지 추적해 — 진짜 바이트와 미디어 타입이야, 아니면 파일명이나 경로뿐이야? 그다음 바이트가 조용히 첨부에 실패하면 뭐가 일어나는지 물어봐 — 뭔가 에러 나, 아니면 평범한 텍스트 답처럼 보여? 그 안 보이는 실패를 시끄러운 걸로 바꿀 체크를 설계해봐.
Hint
안 보이는-실패 테스트는 간단해 — 파일을 붙이고, 바이트가 안 갔다고 상상해. 요청이 여전히 성공하고 답이 평범해 보이면, 침묵 fallback 이 있는 거야 — 최악의 버그. fix 는 바이트나 미디어 타입이 없을 때 경계에서 거절해서, '작동했어' 가 절대 거짓말이 될 수 없게 하는 거야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.