본문 바로가기
C.W.K.
Lesson 05 of 05 · published

자체 구현이 먼저, 연결은 나중

~13 min · coupling, self-contained, deferred-design, contracts

Level 0밑준비
0 XP0/43 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

판정

일단 다른 앱에 의존하지 말고 자체적으로 구현하는 쪽으로 가.

판정 2는 이게 버전 1에서 뭘 막는지 하나하나 적어. Waystone이나 Vesta의 크럼은 안 쓰고, 사진 보관함 사진을 참조로 빌려 오지도 않고, Spark나 Forge 것도 안 받아. Sizzle은 자기 사진과 자기 기록을 직접 받아서 직접 지녀. 형제 앱과의 연결은 v1 다음이고, 그때도 주인이 풀어주는 포인터로만 붙어.

같은 문단이 이 판정을 말이 되게 만드는 선도 그어. cwkPippa랑 벤더링한 cwkSiblingKit 배관은 가족의 토대고, 문서는 이걸 앱 의존성으로 치지 않아. 접시를 읽는 게 나니까 Sizzle은 나 없이 못 서. 킷은 레포 안에 복사해 넣고 드리프트 검사를 받는 코드라서 런타임 서비스가 아예 아니고. 가족이 공유 코드를 패키지로 묶지 않고 벤더링하는 이유는 Sibling Kit Quest가 설명해.

엔진이 걸 수 있는 번호

이런 판정은 코드로 확인할 수 있어. 엔진이 거는 가족 주소는 전부 backend/settings.py에서 가족 레지스트리를 읽어 정해지고, 거기 나오는 가족은 둘뿐이야. cwkPippa는 읽기랑 대화 때문에 루프백으로 불러. Firelink 파사드도 루프백인데, 두뇌 슬롯이 거기 있어. 둘 다 Sizzle한테 접시나 사진이나 요리를 건네지 않아. Forge 주소도, Spark 주소도, Waystone 주소도 없어. 벤더링한 킷 모듈들도 자기 주소를 따로 들고 다니지 않고 이 설정에서 받아 써.

기다리는 설계

판정 2가 형제 앱들의 연결 제안까지 막은 건 아니야. 그 제안을 어떻게 다룰지를 정한 거지. 설계엔 두 가지가 자세히 적혀 있고, 둘 다 안 만들어졌어.

  • Spark 핸드오프(coop request #264). 가족의 통역 앱 Spark가 Sizzle이 설계되던 날 계약을 하나 내밀었어. 바탕은 cwkSiblingKit의 가족 항목 참조 {app, kind, id, parent}야. 항목은 주인이 책임지고, 연결하는 앱은 절대 복사하지 않아. Spark는 방향을 둘 꼽았어. Spark에서 번역된 메뉴 한 줄을 누르면 Sizzle에서 그 요리의 원리가 열리는 것. Sizzle에서 '이걸로 주문하기'를 누르면 문장 하나가 Spark로 넘어가 통역 카드가 되는 것.
  • Forge 연결. 출발 재료엔 아빠가 실제로 먹은 끼니가 참조 형태로 cwkForge 섭취 크럼이 되고, Forge 상태가 제약 조건으로 거꾸로 흘러드는 그림이 있었어. 판정 2와 3이 이걸 v1에선 아예 없는 걸로 좁혔어.

Sizzle은 Spark한테 신중하게 중간을 잡아서 답했어. 원칙적으로는 계약을 받아들이고, 반론 메모를 붙이고, 아빠랑 판정 2를 다시 볼 때까지 아무것도 안 만들어. 반론 메모 자체가 꽤 좋은 설계 작업이야.

  1. 소유한 종류는 둘. class(원리, 요리, 변형)와 plate(만남). 항목 하나를 읽는 라우트는 이미 있어. 그러니 계약을 받아들인다는 건 거기에 표시용 라벨을 더하는 거고, 새 라우트는 필요 없어.
  2. 메뉴 한 줄은 질문으로 도착해. 접시엔 사진이 있어야 하잖아. 그래서 Spark에서 온 한 줄은 Sizzle 스레드를 열고, 그 문장이랑 Spark 순간을 가리키는 포인터를 같이 넘겨. 포인터는 참조로만 두고 절대 복사하지 않아. 이러려면 Sizzle 딥 링크가 필요해. 웹 라우트 하나랑 cwksizzle:// 스킴인데, 둘 다 아직 없어.
  3. '이걸로 주문하기'는 제안대로 받아. 단, 피파가 카드를 쓰기 전에 아빠가 확인해.

보류가 정말 보류인지 확인하기

안 만들었다는 건 코드에 대한 주장이야. 그러니 확인해 봐. 레포에서 딥 링크 스킴, 킷의 항목 참조 모듈, Spark의 링크 파라미터를 찾아보면 나오는 건 아키텍처 문서뿐이야. iOS 프로젝트엔 URL 스킴 선언이 없어. 엔진이 벤더링한 kit_* 모듈 12개 중에 kit_item_ref는 없고. 앱에서 이 기능들을 찾아봤자 안 나와. 이 퀘스트의 어느 레슨도 이걸 기능으로 가르치지 않아.

왜 기다려

연결 하나가 늘 때마다 실패하는 길도 하나 늘어. Sizzle이 혼자 서 있는 동안엔 Spark가 없든 Forge가 자고 있든 접시 저장이나 읽기가 깨질 일이 없어. 문서의 시스템 표는 진짜 의존성 하나가 자리를 비우면 어떻게 되는지 적어둬. cwkPippa가 안 되면 저장이랑 둘러보기는 계속 되고, 읽기랑 답장은 기다리면서 대기 중으로 보인다고. 코드는 앞 절반은 그대로 지키고, 뒤 절반은 더 솔직하게 말해. 나한테 닿지 못한 읽기는 reading.failed를 남기고, 접시엔 실패가 Read again(다시 읽기) 버튼과 같이 떠. 나한테 닿지 못한 답장은 turn.failed를 남기고, 스레드엔 Ask again(다시 묻기)이 떠. 혼자 알아서 기다리는 건 없어. 그렇다고 잃는 것도 없어. 접시도, 사진도, 질문도 그 자리에 그대로 있으니까. 잘못될 수 있는 일의 목록이 짧아. 핵심이 돌아갈 때까지 그 목록을 짧게 두기로 한 건 아빠야.

보류된 계약은 기다리는 동안에도 제 몫을 해. 판정을 다시 볼 때 빈손으로 시작하지 않거든. Spark 쪽엔 계약이, Sizzle 쪽엔 반론 메모가 이미 있으니까.

원칙: 연동은 제안이 나왔을 때 적어둬. 만드는 건 데이터 주인과 결정하는 사람이 둘 다 하자고 할 때야.

Code

cwkSizzle, backend/settings.py: 엔진이 거는 가족 주소는 이 둘뿐이야 (원문 그대로, 25-36행)·python
# The engine runs on service host beside cwkPippa and reaches it over loopback,
# like Forge, Vesta and Waystone. Loopback is outside macOS 26's Local
# Network gate and is the boundary cwkPippa trusts without a PIN; a
# tailnet origin here answers 401 pin_required (Easel, 2026-09-25).
PIPPA_BASE = os.environ.get("SIZZLE_PIPPA_BASE", loopback_origin("cwkPippa")).rstrip("/")

# Brains are global family settings held by the Brain Control Plane, reached
# through Firelink's facade on loopback like every engine on service host. Sizzle's
# Settings page and Firelink's Brains tab edit the same per-function slots
# (brain_control.py). These two values only seed the reading slot's first
# registration; after that central is the only truth.
FAMILY_CONTROL_BASE = os.environ.get("SIZZLE_FAMILY_CONTROL_BASE", loopback_origin("cwkFirelink")).rstrip("/")
cwkSizzle origin/main d6212b7에서 실행: 보류된 연결은 설계 문서에만 있어 (명령과 출력 그대로)·shell
$ git grep -n -E 'cwksizzle://|kit_item_ref|link_app' origin/main -- .
origin/main:docs/SIZZLE-ARCHITECTURE.md:260:(cwkSiblingKit SIBLING-CONTRACTS §16, `kit_item_ref.py`) is `{app, kind,
origin/main:docs/SIZZLE-ARCHITECTURE.md:262:Spark receives links on the web (`/?link_app&link_kind&link_id&link_parent&link_label`)
origin/main:docs/SIZZLE-ARCHITECTURE.md:286:   and a `cwksizzle://` scheme in SizzleMobile, neither of which exists yet.
$ git grep -n 'CFBundleURLTypes' origin/main -- clients; echo "exit $?"
exit 1
$ git ls-tree --name-only origin/main backend/ | grep kit_
backend/kit_atomic_file.py
backend/kit_brain_control.py
backend/kit_brain_control_routes.py
backend/kit_brain_control_testing.py
backend/kit_log_format.py
backend/kit_pippa.py
backend/kit_pippa_brains.py
backend/kit_pippa_uploads.py
backend/kit_product_version.py
backend/kit_staged_uploads.py
backend/kit_ulid.py
backend/kit_webui_static.py
cwkSiblingKit, kit/python/kit_item_ref.py: 연결이 기대게 될 가족 항목 참조 (원문 그대로, 1-13행)·python
"""The family item reference: point at another app's item, never copy it.

Canonical here; the contract is SIBLING-CONTRACTS §16. A reference is
``{app, kind, id, parent}``: the owning app, its own word for the item, the
item's id, and the container the id is unique within when it is not unique
alone (a Waystone crumb id is unique inside its journey; a Vesta crumb id is
unique across journals and survives a move, so it carries no parent).

The linking app stores the reference, and at most a label it saw when the
link was made; everything else is asked of the owner when it is shown
(Forge's and Vesta's no-warehouse rule). :func:`resolve` asks the owner's
one-item route and folds the answer into one card shape, so a linking
surface draws a Waystone crumb, a Vesta crumb and a Spark moment the same way.

External links

Exercise

첫 버전이 런타임에 말을 거는 바깥 시스템을 전부 적어봐. 하나씩 토대와 의존성으로 나눠. 토대는 없으면 제품이 제품이 아니게 되는 거고, 의존성은 남의 데이터를 빌려 온 기능이야. 의존성 하나를 골라서, 나중에 쓸 포인터 계약을 {app, kind, id, parent} 모양으로 적고, 지금 v1은 그 대신 뭘 하는지 써. 그리고 코드를 검색해서 미뤄둔 연결이 정말 없는지 확인해.
Hint
포인터 계약은 항목의 주인이 누군지, 연결하는 쪽이 뭘 들고 있어도 되는지를 말해. 보통은 참조 하나, 많아야 그때 본 라벨 하나야. v1의 대안에 다른 앱 데이터의 사본이 필요하다면, 그건 이름만 바꿔서 의존성을 일찍 들인 거야.

Progress

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

댓글 0

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

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