내구 실행의 핵심은 대화 내용을 되살리는 일이 아니라, 외부 효과와 내부 기록 사이에 생기는 불확정 상태를 다시 판정할 수 있게 하는 데 있습니다. 이 노트는 논리 의도, 승인, 세대, 취소를 하나의 실행 원장으로 연결하고 재개 시 무엇을 조회해야 하는지 설명합니다.
외부 효과와 완료 기록 사이의 조회·대사
외부 예약 서버는 성공했는데 실행기가 완료 checkpoint를 쓰기 전에 죽었다고 가정합니다. 새 세션의 기록에는 미완료만 남습니다. 무조건 다시 예약하면 중복이고 건너뛰면 실제 실패했던 경우 누락입니다. 내구 실행은 모델 대화를 복원하는 것 외에 외부 결과를 조회·대사하는 계약을 필요로 합니다.
작업 원장에는 작업 ID·단계·입력 버전·정규화한 인자·논리 키·물리 호출 ID·외부 결과 ID·검증 상태·소유 세대·사용 예산을 둡니다. 큰 산출물은 버전 고정 참조로 저장합니다. 내부 추론 전문 대신 결정된 인자와 관찰 증거가 필요합니다.
논리 의도별 동일 Key와 새 의도별 새 Key
상태 추적의 최소 예는 pending → dispatched → unknown → reconciled입니다. dispatched 뒤 응답 전에 죽으면 재개기는 새 물리 호출 ID를 만들기 전에 논리 키로 외부 상태를 조회하고, 이미 성공했다면 결과 ID를 기록해 reconciled로 전환합니다. 조회가 불가능하면 failed로 단정하지 않고 불확정 상태로 남겨 사람 확인이나 제한된 재시도 정책으로 보냅니다.
모델의 call_123은 한 물리 호출의 상관 ID일 수 있습니다. 재호출에서 call_456이 돼도 같은 예약 의도라면 runtime이 발급해 보관한 논리 키를 유지합니다. 사용자 A가 같은 날짜에 두 예약을 의도했다면 인자가 같아도 별도 키가 필요합니다. 인자 해시만으로 의도를 합치지 않습니다.
| 상황 | 처리 |
|---|---|
| 같은 key·같은 인자 | 기존 결과 조회 또는 멱등 재요청 |
| 같은 key·다른 인자 | 충돌·새 의도와 승인 확인 |
| 외부 성공·응답 유실 | 권위 결과 조회·대사 |
| dedup 보관 기간 경과 | 옛 보장 가정 금지·재실행 판단 |
| 외부 API에 조회·멱등 없음 | 불확정 보고·사람 확인 가능 |
예약·결제·메일은 서로 다른 효과입니다. 단계별 키와 상태를 연결하고 내부 DB 변경과 처리 기록은 가능한 같은 transaction에 둡니다. 하나의 workflow ID가 모든 외부 시스템에 exactly-once를 제공하지 않습니다.
구체적 변경안과 사람 승인 기록
메일 승인 화면은 수신자·본문·첨부의 고정 version/hash를 가진 변경안에서 생성하고, 실행기도 같은 변경안을 읽습니다. 승인 기록에는 사용자·작업·행동·기한·허용 재시도·대상 조건을 둡니다. 승인 뒤 모델이 수신자를 바꾸면 재승인이 필요합니다. 침묵이나 하위 에이전트의 “승인받음” 보고는 승인 기록을 대체하지 않습니다.
환불 승인 뒤 잔액이 바뀌면 실행 시 조건부 갱신으로 다시 확인합니다. 사람 승인은 현재 DB 제약·인가를 생략할 권한이 아닙니다. 승인 대기 중 취소·만료가 확정되면 늦은 승인 응답으로 실행을 되살리지 않습니다. UI에는 중요한 변경 전후 차이를 먼저 보여 승인 피로를 줄이되 실제 인자와 다른 요약을 보여 주지 않습니다.
그림을 글로 읽기
- 논리 의도·고정 인자·승인
- 실행 전 내구 기록·세대 검사
- 외부 예약·결제 등
- 결과 조회·대사·검증
- 완료 checkpoint·사용자 보고
- 논리 의도·고정 인자·승인 → 실행 전 내구 기록·세대 검사: 실행권 확인
- 실행 전 내구 기록·세대 검사 → 외부 예약·결제 등: 같은 논리 키
- 외부 예약·결제 등 → 결과 조회·대사·검증: 응답 유실 가능
- 결과 조회·대사·검증 → 완료 checkpoint·사용자 보고: 확인한 사실만
기록된 결정 replay와 새 관찰 기반 추론
재개할 때는 기록된 모델 결정과 도구 인자를 replay할 단계와 새 관찰로 추론할 단계를 먼저 나눕니다. workflow·모델·prompt·도구 버전이 바뀌었다면 옛 단계의 의미를 유지한 채 진행하거나, 명시적으로 migration한 뒤 진행합니다. lease가 만료된 뒤에도 옛 워커가 살아 있을 수 있으므로 checkpoint 저장과 가능한 실제 변경 지점에서 세대 검사와 쓰기를 같은 원자적 경계로 묶습니다. 외부 API가 fencing을 지원하지 않는다면 그 한계를 idempotency·상태 조회와 함께 드러냅니다.
취소 상태와 이미 발생한 외부 효과
취소 시 새 자식 생성부터 막고 대기 작업을 제거한 뒤 모델 요청·sandbox process group·원격 task에 지원되는 취소를 전파합니다. 실제 종료 뒤 연결·buffer·물리 동시성 permit을 반환합니다. 화면 응답 종료 시 바로 permit을 반환하면 잔존 작업이 상한 밖에서 계속 실행될 수 있습니다.
늦게 예약 성공이 확인되면 사용자 요청은 취소됐어도 “예약이 이미 생성됨”을 별도 기록·안내합니다. 이 사실을 버리거나 단순 cancelled 상태로 숨기지 않습니다. 보상은 새로운 외부 행동이므로 보상 권한·실패·현재 상태를 다시 검사합니다. 필수 detached 작업은 별도 owner·최대 수명·조회 경로가 있어야 합니다.
중단 지점별 실행 원장·외부 효과 대조
실무 선택에서는 외부 시스템이 제공하는 기능을 먼저 표로 고정합니다. 멱등 키만 있으면 재요청과 결과 조회를 함께 설계하고, 조회만 가능하면 외부 검색 조건과 대사 주기를 설계하며, 둘 다 없으면 자동 재시행을 보장으로 표현하지 않습니다. 이 선택은 “exactly-once”라는 용어보다 실제 복구 경로를 더 정확히 드러냅니다.
실행 전, 외부 commit 후, checkpoint 전, 사용자 보고 전, 승인 대기 중, 취소와 완료 동시 도착을 각각 시험합니다. UI 문구보다 실제 예약·원장·남은 process·재사용 key를 대조합니다. 이 노트는 내구 상태 설계이며 실제 외부 예약이나 결제 API로 실행한 실험은 아닙니다.