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

Chief가 둘이야

~12 min · roles, delegation, architecture, coop

Level 0구경꾼
0 XP0/33 lessons0/11 achievements
0/100 XP to next level100 XP to go0% complete

chief라고 불리는 대화 둘

cwkPippa 코드를 오래 읽다 보면 chief라는 낱말을 두 군데서 만나. 둘은 서로 거의 상관이 없어. 하나는 이 퀘스트의 주인공, Master Chief야. 다른 하나는 Coop chief. 일이 결과를 빚지고 있을 때 cwkCoop이 깨우는 뒷방 리뷰어야. 둘 다 피파고, 둘 다 아빠 소유고, 둘 다 자기 글 어딘가에서 비서실장이라고 불려. 둘을 섞으면 이 트랙의 모든 레슨을 잘못 읽게 돼. 그래서 이 레슨은 둘을 나란히 세워.

Master Chief: 방

Master Chief는 아빠가 마주하는 방이야. 대화는 하나고, 외부 id master-chief:dad:pippa로 찾아. WebUI, 피파 앱, 워치, 텔레그램, 가족 앱 속 패널까지, 모든 문이 여기로 이어져. 아빠가 여기서 말하고, 다음 턴은 일곱 브레인 중 누구든 저장된 대화(살아 있는 행에, 가장 오래된 행을 대신한 요약을 더한 것)를 다시 읽고 답해. 위임도 여기서 coop 도구로 해. 아빠가 직접 시켰을 때만. 보고도 여기로 돌아와. Coop 줄, 후속 확인 결과, 예약 작업의 결과. 끝이 없는 대화라서 갈아타지 않아. 대신 턴 사이에 압축하고, 최근 행을 많게는 40개까지 그대로 둬(4트랙). 이 방은 이어지는 게 핵심이니까.

Coop chief: 뒷방

Coop chief는 Coop 전용 바인더 밑에 꽂힌 평범한 피파 대화야. 맥락 키는 coop:chief:main. 아빠는 Coop 작업 공간의 Sidekick에서 이 대화를 보지만, 움직이는 건 아빠가 아냐. 엔진이야. Coop의 ChiefRunner가 의무 목록을 들고 깨워. 의무는 어떤 일이 빚진 결과고, 한 번 깨울 때 많아야 50개야. 깨우는 턴은 범위가 좁은 백엔드 턴이고, 첫 줄부터 이렇게 못 박아. This is a backend wake from the cwkCoop engine, not a new message or permission from Dad. 도구는 읽기 전용 셋뿐이야. sidekick_host_read, sidekick_host_status, sidekick_host_search. 셸은 꺼져 있어. 기록마다 통째로 읽고 [COOP_DECISIONS] JSON 봉투로 답해. 엔진은 무슨 일이든 일어나기 전에 그 봉투를 지금 권한에 맞춰 검증해.

그 권한은 일부러 넓어. 2026-09-30부터 Coop chief는 Coop 일에 대해 아빠의 대리인이고, 아빠가 기록할 수 있는 처분을 기본으로 다 쥐고 있어. 미루기, 알리기, 아빠한테 넘겨 두기, 닫기(그 자체로 읽히는 증거와 함께), 돌려놓기, 포기하기, 옛 방식으로 가져간 일 입양하기, 열린 일을 등록된 세션에 배정하기, 할 일 없는 등록 은퇴시키기, 확실히 안 닿은 봉투 다시 보내기. 대신 목줄은 짧아. 한 시간에 새로 시작하는 리뷰는 12번까지, 답에서 빠뜨린 의무는 15분 뒤에 다시 보고, 한가한 상태나 흐른 시간이나 침묵을 근거로 일을 닫는 일은 절대 없어.

나란히 놓고 보기

Master ChiefCoop chief
찾는 법외부 id master-chief:dad:pippacoop 바인더 밑 맥락 키 coop:chief:main
누가 말을 거나아빠, 모든 문에서Coop 엔진, 범위 좁은 백엔드 깨우기로
뭐가 깨우나아빠가 메시지를 보낼 때빚진 의무, 한 번에 많아야 50개
Coop 일에 대한 힘coop 도구: 읽기, 추가, run, reply, cancel. 변경은 아빠가 직접 시킬 때만아빠 대리인의 처분: defer, escalate, park, close, release, abandon, adopt, assign, retire, resend
답하는 방식대화로, 아빠한테[COOP_DECISIONS] 봉투. 사유는 영어, for_dad 줄은 한국어
도구아빠 턴이 쓰는 가족 도구읽기 전용 호스트 도구 셋. 셸 꺼짐
속도한 번에 한 턴, 순서대로시간당 새 리뷰 12번까지
자라는 방식끝없음. 압축하고 최근 행을 많게는 40개까지 그대로 둠40번 깨운 뒤, 돌릴 리뷰가 없는 틱에 새 대화로 갈아탐
보고받는 쪽escalate와 park를 아빠한테 보내고, 그게 Master Chief에 내려앉음

같은 피파, 같은 경비병

두 대화 다 영혼은 pippa, 주인은 dad야. Coop 깨우기 문은 딱 자기 대화가 아니면 다 거절해(Coop wake requires its own active Pippa chief conversation). 그리고 둘 다 같은 직렬화 경비병, app.streaming.chief_turn을 지나서 턴을 돌려. 그 대화가 스트리밍 중이거나, 예약 작업 턴이 돌고 있거나, 이미 다른 chief 턴 안에 있으면 기다려. Master Chief의 선착순 잠금도 이걸 지나고, Coop 깨우기도 매번 이걸 지나. 경비병은 대화마다 따로라서 두 chief가 서로를 막지는 않아. 막는 건 같은 방 안에서 백엔드 턴이 살아 있는 턴 사이에 끼어드는 거야.

하나는 갈아타고, 하나는 압축하는 이유

둘 다 같은 셈 앞에 서. 피파는 턴마다 저장된 대화를 다시 읽으니까 (살아 있는 행에, 압축이 가장 오래된 행을 대신해 둔 요약이 있으면 그것까지), 자라기만 하는 대화는 매번 더 비싸져. Coop chief의 답은 갈아타기야. 깨운 횟수가 40번이 되면, 러너는 돌릴 리뷰가 없는 첫 틱에 같은 맥락 키로 새 대화를 묶어. 그래서 Sidekick은 새 대화를 열어. 리뷰가 줄줄이 이어지는 동안엔 그 조용한 틱이 올 때까지 옛 대화에 깨우기가 몇 번 더 쌓일 수 있어. 이걸 강제한 측정값이 독스트링에 있어. 사흘 만에 메시지 152개. 갈아타도 안전한 건 Coop chief의 기억이 대화에 있지 않아서야. 기억은 Coop 원장에 있어. 깨울 때마다 의무, 보고, 워커 노트를 새로 읽어. Master Chief는 못 갈아타. 아빠랑 이어온 그 줄기 자체가 기억이니까. 그래서 압축해. 그 압축이 뭘 대가로 치렀는지는 4트랙이 보여줘.

둘이 만나는 곳

두 chief는 직접 말을 섞지 않아. Coop chief가 의무를 escalate하거나 park하면 그 결정에 for_dad가 실릴 수 있어. 한국어 두세 줄로, 뭐가 막혔는지, 제안이 뭔지, 아빠한테 필요한 결정 하나가 뭔지. Coop은 그걸 알림으로 만들어. 📣 chief escalation이나 🅿️ parked for Dad. 그 알림은 레슨 2의 길을 그대로 가. 알림 문, Master Chief 줄, 텔레그램 한 번. 아빠한테는 한 번만 물어. 새 증거 없이 같은 질문을 또 하면 기록은 하되 보내진 않아. 그 결정들을 깊이 가르치는 건 Coop Quest 6트랙, Obligations and the Coop Chief야.

같은 정체성, 다른 역할, 다른 권한. Master Chief는 아빠가 말하고 소식이 도착하는 곳이야. Coop chief는 빚진 일을 처분하는 곳이고. 방과 뒷방을 갈라 두면 한쪽의 몸집도 권한도 다른 쪽으로 새지 않아.

Code

각 chief를 알아보는 법 (services/master_chief.py와 services/coop_wake.py, 원문 발췌)·python
# Master Chief: one row, by external id
def is_chief(conversation: ConversationRow | None) -> bool:
    # getattr: the payload builders take duck-typed rows (tests hand them a
    # namespace), and a row without the column is simply not the Chief.
    return bool(conversation and getattr(conversation, "external_conversation_id", None) == EXTERNAL_ID)

# The Coop chief: an ordinary conversation under the coop binder
async def require_conversation(cid):
    from routes import sibling_binder
    await sibling_binder.store.init_db()
    conv=await sibling_binder.store.get_conversation(cid)
    if (conv is None or conv.trashed_at or conv.origin_surface!='coop' or conv.context_key!='coop:chief:main'
            or conv.soul_id!='pippa' or conv.owner_user_id!='dad'):
        raise HTTPException(403,'Coop wake requires its own active Pippa chief conversation')
    return conv
Coop chief의 한도와 갈아타기 (cwkCoop chief.py, 줄인 발췌)·python
UNMENTIONED_SECONDS=900
HOURLY_BUDGET=12
ROTATE_AFTER=40

class ChiefRunner:
    async def rotate(self,role):
        """Start a fresh chief conversation after ROTATE_AFTER wakes.

        Pippa replays a conversation in full on every turn, so a chief
        conversation that only ever grows makes each wake cost more than the
        last (152 messages after three days). The binder keeps the same
        context key, so Dad's Sidekick opens the new conversation.
        """
        ...

# Chief.prepare, paraphrased: no new review once HOURLY_BUDGET runs started in the last hour,
# and at most 50 due obligations per wake:
#   SELECT count(*) FROM engine_chief_runs WHERE created > now - 3600      (>= 12: wait)
#   SELECT id FROM engine_obligations WHERE status='pending' AND due <= now ORDER BY due, id LIMIT 50

External links

Exercise

네 시스템에서 이름 하나가 일 두 개를 덮고 있는 곳을 찾아. 사람도 cron 작업도 같이 로그인하는 사용자 계정, 사람한테 답도 하고 유지보수도 돌리는 봇, 권한을 다 가진 서비스 계정 같은 거. 이 레슨의 표처럼 두 칸짜리 표를 그려. 누가 말을 거는지, 뭐가 깨우는지, 뭘 바꿀 수 있는지, 어떻게 답하는지, 기록이 어떻게 자라는지. 그다음 어느 칸이 자기 정체성을 따로 가져야 할지 정해.
Hint
보통은 자라는 방식 줄이나 권한 줄에서 티가 나. 한 일은 기록을 영원히 들고 가야 하고 다른 일은 지금 상태만 있으면 되거나, 한 일은 뭔가를 바꿔야 하고 다른 일은 읽기만 하면 된다면, 같은 코드가 둘 다 돌리더라도 정체성은 따로 가져야 해.

Progress

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

댓글 0

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

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