"같은 걸 두 번 사야 할 때가 진짜로 있어. 그렇다고 '두 번 못 산다'는 보증을 헐어도 된다는 뜻은 아니야."
보증이 남기는 구멍
이 트랙 2번 레슨에서 세운 신원은 빈틈이 없어. 같은 오디오, 같은 provider 설정이면 유료 호출은 딱 한 번. 영원히. 그런데 아카이브가 실제로 만들어낸 상황은 이래. 어떤 영상의 transcript 가 나빠. 구조적으로 깨진 것도 아니고, 그냥 사람이 보기에 틀린 거야. 새 증거를 받고 싶어. 오디오는 안 바뀌었고 설정도 안 바뀌었어. 그러니 content-addressed key 도 그대로고, ledger 는 완료된 행을 찾아서 예전 응답을 영원히 돌려줄 거야. 보증은 설계대로 정확히 동작하는 중이고, 그게 정당하게 원하는 걸 앞에서 막고 서 있어.
대부분의 시스템이 자기 최악의 플래그를 얻는 순간이 바로 여기야. 틀린 해법 두 개가 떠오르는데, 둘 다 한 줄이라서 달콤해.
- ledger 행을 지운다. 키가 비니까 다음 시도가 결제하고, 끝. 동시에 처음에 돈을 냈다는 기록도 같이 사라져. 예약 ledger 가 존재하는 이유가 바로 그 기록인데 말이야. 돈 문제를 돈 이력을 지워서 고치는 셈이지.
- ledger 검사를 건너뛰는 플래그를 단다.
--force-pay든--ignore-cache든. 동작은 해. 그리고 동시에, 앞으로 영원히 모든 operator 의 반사신경 한 번 거리에 무방비 유료 POST 를 놓아두는 거야. 뭔가 막힌 것 같을 때 사람들이 반사적으로 집는 플래그가 어떻게 되는지는 트랙 5 에서 이미 봤지.
대신 신원을 늘려
Recall 의 답은 보증을 아예 안 건드려. 신원에 세 번째 성분을 더해. 유료 호출 키가 이제 쌍이 아니라 삼중항이야. 오디오 청크 해시, 설정 해시, 그리고 0 에서 시작해 늘어나기만 하는 rerun_generation 정수. DB 의 유일성 제약이 셋 다를 덮어.
이게 뭘 사주는지 보자. generation 0 안에서는, 그러니까 파이프라인이 지금껏 돌린 모든 평범한 transcription 에서는, 바뀐 게 없어. 같은 바이트 + 같은 설정은 여전히 한 키로 접히고, 여전히 완료된 행을 찾고, 여전히 두 번 결제를 거부해. 보증은 1 바이트도 안 약해졌어. 반면 새 generation 은 진짜로 다른 키라서, 아무것도 못 찾고, 정직하게 예약하고, 결제해. at-most-once 에 예외를 만든 게 아니야. at-most-once 가 똑같이 엄격하게 성립하는 두 번째 차선을 만든 거지.
그리고 generation 이 건너뛴 검사가 아니라 저장된 컬럼이라서, 흔적이 남아. 어떤 영상의 다음 generation 은 그 영상이 써본 최고값보다 하나 위야. 그러니까 그 숫자 자체가 "우리가 이걸 의도적으로 몇 번 다시 샀지?" 에 답해. 건너뛴 검사는 아무것도 답 못 하고. audit trail 과 구멍의 차이가 정확히 거기야.
누가 그걸 찍을 수 있나
차원은 그걸 움직일 수 있는 권한만큼만 안전해. 그래서 generation 을 찍는 건 자동으로 일이 돌아가는 어느 자리에서도 닿지 않게 일부러 떼어놨어. worker 도 아니고, retry 도 아니고, --force 도 아니야. force 는 트랙 5 에서 설명한 그대로 유료 키를 그냥 안 건드려. 유일한 경로는 operator 가 콘솔에서 특정 영상의 Retranscribe 를 누르는 것뿐이고, 그 액션은 움직이기 전에 먼저 preview 를 보여줘. preview 가 spends_scribe_credits 를 대놓고 말하고, 영상을 이름으로 짚고, 곧 찍힐 generation 이 몇 번인지 알려줘.
승인 한 번이 그 영상의 모든 오디오 청크를 덮어. 카운터가 영상 단위로 추적되고 job 에 찍히거든. 그게 맞는 granularity 야. 사람이 영상 하나를 보고 돈 쓸 가치가 있다고 판단했으면, 기계는 정확히 그 영상에만 돈을 쓰는 거지.
이 시스템엔 비슷해 보이지만 다른 문이 하나 더 있어. 구분해둘 값어치가 있어. ambiguous 제출을 명시적 유료 재실행 승인으로 해소하는 경로(트랙 4, 3번 레슨)는 같은 ledger 행을 다시 열어. 같은 키, 같은 generation 으로. 그 상황은 "내가 결제했는지 모르겠다" 니까. Retranscribe 는 새 generation 을 찍어. 그 상황은 "결제한 거 알아, 그리고 또 낼 거야" 니까. 불확실성이 다르면 문도 달라. 그리고 둘 다 반사적으로 누를 플래그는 아니고.
아무도 예상 못 하는 뒷정리
preview 안에 통째로 훔쳐갈 만한 디테일이 하나 있어. 뭘 큐에 넣기 전에, Retranscribe 는 이 영상의 현재 transcript 가 이미 지식 corpus 로 승인됐는지(트랙 7) 확인하고, 그랬다면 그 사실을 follow-through 로 job 에 실어 보내. 새 증거를 사면 새 release 가 나오고, 그 말은 하류에서 승인돼 있던 그것이 곧 틀린 것이 된다는 뜻이거든. 재구매가 자기가 무효로 만든 걸 고치러 가야 한다는 걸 기억하는 거야.
일반적인 모양이 이거야. 승인된 예외는 자기가 부른 결과를 스스로 쫓아가야 해. 문을 설계하고 나서, 하류의 모든 게 그 문이 방금 갈아치운 것 위에 지어져 있었다는 걸 잊기가 너무 쉬워.