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

코호트 정책

~12 min · cohort-policy, promotion, scale, reconciliation

Level 0Empty Shelf
0 XP0/39 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"문 없는 벽은 trust boundary 가 아니야. 아직 아무도 지키라고 요구하지 않은 약속일 뿐이지."

아카이브가 드디어 기준선을 넘는 날

두 레슨 전의 격리는 팔자가 편했어. 승인된 게 하나도 없고, 급할 것도 없고, 벽을 넘은 transcript 가 단 하나도 없는 채로 제품이 완벽하게 돌아갔으니까. 시작을 그렇게 하는 건 진짜로 옳아. 하지만 게이트가 시험받는 날은 누군가 저쪽 편에 진짜로 보내고 싶은 transcript 를 수천 개 들고 오는 날이야. 그때부터 질문이 바뀌어. "기본값이 거부여야 하나?" 가 아니라 훨씬 어려운 "이 규모에서 사람의 결정이라는 게 대체 무슨 모양이지?" 가 되는 거지.

정직한 문제는 이거야. release 하나하나 리뷰는 영상 수천 개로 확장이 안 돼. 그런데 된다고 우기면 제일 나쁜 결과가 나와. 다들 중요하다고 동의하지만 아무도 실제로 운영하지 않는 게이트, 그러다 누군가 일을 진행하려고 조용히 넓혀버리는 게이트. 게다가 사실 승인하고 있는 대상은 개별 transcript 가 아니야. 파이프라인이지. 이 provider, 이 model, 이 설정, 이 오디오 준비가 이런 구조적 품질의 출력을 낸다는 것. 표본을 봤고, 파이프라인에 대한 판단을 내렸고, 거기서 나온 release 라면 기꺼이 보증할 수 있다는 것.

인스턴스 말고 신원을 승인해

그래서 Recall 은 문을 코호트 정책으로 만들었어. operator 가 정책을 만들면서, 판단이 덮는 그 파이프라인을 정의하는 모든 걸 정확한 값으로 못박아.

  • providermodel.
  • 설정 해시오디오 proxy 설정 해시. 유료 ledger 가 쓰는 바로 그 content-addressed 지문이야.
  • 이 정책이 덮는 release 상태구조적 품질 등급.
  • 승인자, 그리고 결정의 근거.

그 정확한 신원에 맞는 release 만 정책 아래 선택될 수 있고, 하나를 선택하면 어느 정책에서 왔는지 이름이 박힌 release 별 승인 행이 durable 하게 남아. 판단은 한 사람이 정밀하게 기술된 모집단에 대해 한 번 내리고, 그다음엔 그 구성원들에게 기계적으로 적용돼. 승격은 자동화됐고, 판단은 절대 아니야.

여기서 설정 해시가 뭘 사주는지 봐야 해. 이게 안전한 이유 전체거든. 파이프라인에서 뭐 하나라도 어긋나면, 새 model 이든 바뀐 설정이든 다른 오디오 준비든, 지문이 바뀌고 그 어긋난 release 들은 그냥 정책에 안 맞아. 다른 것에 대해 내려진 판단의 힘을 빌려 슬그머니 딸려 들어오지 못하는 거야. 정책이 못박은 게 서술이 아니라 신원이라서, 승인자가 본 적 없는 출력까지 조용히 덮도록 자라날 수가 없어.

수동 게이트는 어디 안 갔어

원래 경로는 손대지 않았고 여전히 유효해. 사람이 개별적으로 리뷰하고 승인한 release 는 예전 그대로 적격이야. 코호트 경로는 그걸 대체하는 게 아니라 옆에 나란히 서고, 일부러 더 좁아. 완전히 다른 model 이 만들어낸 옛 레거시 transcript 들은 어떤 Scribe 코호트 정책에도 안 걸려서 격리된 채로 남아. 문이 둘, 둘 다 사람을 요구하고, 그중 하나가 결정을 모집단 전체로 실어 나를 수 있는 거지.

코호트 경로는 쉽게 쓸 수 있었던 지름길도 거부해. 정책 아래 release 를 승인해도 그 release 자신의 리뷰 상태는 고쳐 써. candidate 는 candidate 로 남고, 정책 승인은 그 옆에 별도의 durable 한 사실로 기록돼. 정책이 건드린 전부에 "reviewed" 를 찍는 게 얼마나 편했겠어. 그리고 그건 거짓말이었을 거야. 아무도 안 읽었으니까. 시스템은 편한 거짓 하나 대신 참인 문장 둘을 쥐기로 한 거야. 그 정직함엔 값이 붙고, 청구서가 어디로 오는지 볼 값어치가 있어. 1번 레슨의 export guard 는 candidate release 를 그냥 거부하거든. 그러니까 상태를 정직하게 두겠다는 건 guard 가 더는 검사 하나의 사슬일 수 없다는 뜻이야. guard 는 선택지 둘이 됐어. 수동 경로를 걸었으면 내보내거나, 아니면 살아 있는 정책 아래 살아 있는 승인 행을 쥐고 있으면 내보내거나. 두 branch 다 eligibility 가 명시적으로 approved 이고, release 가 current 이고, 영상이 은퇴하지 않았을 것은 여전히 요구하고. 문과 문간은 같은 변경에서 지어. 소비하는 쪽 경계에 자기를 위한 branch 가 없는 승격 경로는 벽을 향해 열리는 문이야. 그리고 조용히 닫힌 채로 실패하는데, 그게 제일 알아채기 어려운 종류거든.

발행은 버튼이 아니라 job 이야

Operations 에서 Publish to Lantern 을 눌러도 요청 안에서 발행이 일어나진 않아. 트랙 2 가 금지했고, 여기가 그 규칙이 압력 아래에서 버티는 걸 구경하기 좋은 자리야. 대신 기록되는 세 단계를 가진 durable job 하나를 만들어. 정책 종류에 맞는 남은 release 를 전부 승인하고, corpus 엔진에 완전 재색인을 요청하고, 그 의미 벡터를 재조정하는 것. job 도 각 단계의 응답도 페이지를 닫든 control plane 이 재시작하든 살아남아. 중단된 job 은 시작할 때 큐로 돌아가서 idempotent 한 단계들을 다시 밟고, 실패는 정확히 어느 단계였는지와 원격 에러를 기록해서 의도적인 재시도를 기다려. DB 인덱스가 동시에 떠 있는 발행 job 을 정확히 하나로 제한해.

설계가 끝났다고 말해주는 디테일은 이거야. 아무것도 승인하지 않는 실행도 돌릴 값어치가 있어. 지난 발행 이후의 수정과 은퇴도 전파돼야 하거든. 수정된 release 는 옛 버전을 feed 에서 떨구고, 은퇴한 실종 영상은 다음 재조정에서 사라져. 발행은 새 자료를 한 방향으로 밀어넣는 게 아니라, corpus 가 지금 담고 있어야 할 것의 재조정이야. 들여보낼 줄만 아는 게이트는 결국 더 이상 보증하지 않게 된 것들로 corpus 를 채우게 돼.

Code

정책은 신원을 못박고, 승인은 어느 정책에서 왔는지 이름을 댄다·sql
-- 판단을, 정밀하게 기술된 파이프라인에 대해, 한 번 기록한다.
CREATE TABLE corpus_approval_policies (
  policy_id                    TEXT PRIMARY KEY,
  provider                     TEXT NOT NULL,
  model                        TEXT NOT NULL,
  configuration_sha256         TEXT NOT NULL,   -- 정확한 ASR 설정
  proxy_configuration_sha256   TEXT NOT NULL,   -- 정확한 오디오 준비
  release_status               TEXT NOT NULL,
  quality_class                TEXT NOT NULL,
  status                       TEXT NOT NULL,   -- active | revoked
  approved_by                  TEXT NOT NULL,   -- 누가 결정했나
  evidence_json                TEXT NOT NULL,   -- 무슨 근거로
  created_at                   TEXT NOT NULL
);

-- 적용: release 하나당 durable 한 행 하나, 정책 이름을 달고.
CREATE TABLE release_corpus_approvals (
  approval_id TEXT PRIMARY KEY,
  release_id  TEXT NOT NULL REFERENCES transcript_releases(release_id),
  policy_id   TEXT NOT NULL REFERENCES corpus_approval_policies(policy_id),
  status      TEXT NOT NULL,
  approved_at TEXT NOT NULL,
  UNIQUE (release_id, policy_id)    -- 재승인은 no-op
);

-- 설정이 어긋나면 지문이 바뀌고 -> 안 맞고 -> 승인 안 됨.
-- 정책은 승인자가 본 적 없는 출력까지 자라서 덮을 수 없다.

-- 그리고 소비하는 쪽 경계에도 이걸 알아보는 branch 가 필요하다:
--   (수동 경로를 걸었거나) OR (살아 있는 정책 아래 살아 있는
--    승인 행을 쥐었거나) 면 내보낸다 -- 두 branch 다 여전히
--   corpus_eligibility='approved', is_current, 은퇴 아님을 요구.
발행은 durable 하고 단계가 있고 idempotent 한 job·python
# 요청은 발행하지 않는다. job 하나를 만든다. (트랙 2.)
# 동시에 떠 있는 발행 job 은 최대 하나 -- operator 가 더블클릭
# 안 하기를 바라는 게 아니라 partial unique index 가 강제한다.

PHASES = ('approving', 'reindexing', 'vectorizing')

#  approving   -> 정책에 맞는 남은 release 전부 승인
#  reindexing  -> corpus 엔진에 완전 재색인 요청
#  vectorizing -> 그 의미 벡터 재조정

# 각 단계가 자기 응답을 기록한다. control plane 재시작 시 중단된 job 은
# 큐로 돌아가 다시 밟는다 -- 모든 단계가 idempotent 하니 반복은
# 공짜다.
# 실패는 정확한 단계 + 원격 에러를 저장해 *의도적인* 재시도를
# 기다린다. 원격 시스템으로 자동 재시도하는 건 없다.

# 그리고 쓸모없어 보이지만 아닌 부분:
#   approved_now == 0  도 여전히 유용한 실행이다.
#   수정은 옛 release 를 feed 에서 떨구고, 은퇴한 영상은 사라진다.
#   발행은 밀어넣기만 하는 게 아니라 RECONCILE 한다.

External links

Exercise

네 일에서 사람이 한 건씩 처리하는 승인 단계를 찾아봐. 항목 리뷰, 출처 화이트리스트, 기록 사인오프 같은 것. 리뷰어가 실제로 판단하는 게 뭔지 물어봐. 이 특정 항목이야, 아니면 그걸 만들어낸 프로세스야? 프로세스라면 코호트 정책을 설계해. 그 프로세스를 정의하는 입력을 전부 적고, 그중 어느 걸 정확한 지문으로 못박을 수 있는지 정하고, 새 항목이 판단 바깥으로 떨어지려면 뭐가 달라져야 하는지 이름 붙여. 그다음 반대 방향도 설계해. 철회나 수정은 승인된 집합에서 어떻게 빠져나가?
Hint
이게 막아주는 실패는 조용히 넓혀지는 확장용 게이트야. 구멍 두 개를 특히 봐. (1) 신원에 못박힌 게 아니라 말로 서술된 정책('그 좋은 모델'). 서술은 새것까지 덮도록 늘어나지만 지문은 안 늘어나. (2) 출구가 없는 승인 집합. 더하기만 되고 재조정이 안 되면, 그 집합은 갈아치운 버전 하나씩만큼 내가 실제로 보증하는 것에서 멀어져.

Progress

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

댓글 0

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

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