AI가 준비한 변경안을 사람이 승인했다. 그런데 실행 직전 다른 사람이 같은 기록을 고쳤다면, 그 승인은 여전히 그대로 적용해도 될까? 승인한 변경 내용과 그때 확인한 상태를 함께 묶고, 서버가 현재 상태와 일치할 때만 쓰도록 해야 한다. 충돌이 나면 최신값에 예전 변경안을 기계적으로 덮어쓰지 않고 무엇이 달라졌는지 다시 판단한다.
이 글은 여러 사람이나 자동화가 같은 업무 기록을 바꾸는 상황을 다룬다. HTTP의 ETag와 If-Match를 구체적인 예로 설명하지만, 모든 업무 API가 이 기능을 지원한다는 뜻은 아니다. 코드는 이해를 위한 가상 요청이며 특정 서비스에 직접 호출한 결과가 아니다.
승인은 “어느 기록의 무엇을 바꾸는가”에 붙인다
“이 카드 수정 승인”만 남기면 승인 뒤 AI가 변경 필드를 추가해도 같은 승인처럼 보일 수 있다. 이 글에서 제안하는 최소 확인 단위는 대상 ID, 읽은 상태의 식별값, 바꿀 필드와 값, 보존할 필드다. 예를 들어 카드 42의 담당자를 지수에서 민호로 바꾸되 마감일과 완료 상태는 건드리지 않는다는 식이다.
승인 유효시간만 짧게 두어서는 동시 변경을 막을 수 없다. 승인 직후에도 다른 사람이 저장할 수 있기 때문이다. 반대로 시간이 조금 지났다는 사실만으로 모든 변경안이 틀렸다고 단정할 수도 없다. 핵심은 실제로 어떤 상태가 바뀌었고 그것이 승인한 작업의 전제를 바꾸는지다.
ETag를 읽고 If-Match로 조건을 건다
RFC 9110의 If-Match 정의에 따르면 서버는 요청을 수행하기 전에 제공된 태그와 현재 선택된 표현의 태그를 강하게 비교한다. 이 조건은 다른 클라이언트의 변경을 덮어쓰는 lost update를 막는 데 쓰인다. ETag는 서버가 주는 불투명한 식별값으로 다루고, 클라이언트가 임의로 새 버전을 만들어 넣지 않는다.
아래는 강한 ETag를 제공하고 조건부 갱신을 실제 지원하는 가상 카드 API를 전제로 한다. 예시의 PUT 본문은 설명을 위해 축약했다. 실제 요청 본문의 전체·부분 갱신 규칙은 해당 API 문서에 맞춰야 한다.
GET /cards/42
응답 헤더: ETag: "card-42-v7"
PUT /cards/42
If-Match: "card-42-v7"
[승인한 변경을 반영한 요청 본문]
실행 시 현재 태그가 달라 조건이 거짓이면 서버는 그 요청 동작을 수행하면 안 된다. 412 Precondition Failed로 거절할 수 있다. RFC는 요청한 변경이 이미 반영된 것으로 판단되는 경우 성공 응답을 허용하는 예외도 설명하므로, 응답 코드만으로 새로운 쓰기가 일어났다고 단정하지 않는다. 필요한 실제 상태는 다시 조회한다.
If-Match: *는 “내가 읽은 버전과 같다”는 조건이 아니다. 현재 표현이 존재하는지 검사한다. 또한 W/로 시작하는 약한 ETag는 이 용도의 강한 비교를 만족하지 못한다. 헤더 문자열을 넣었다는 사실보다 서버의 지원과 비교 동작이 중요하다.
가상 사례: 담당자 승인 뒤 카드가 완료된 경우
운영 시험이 아닌 가상 상황이다. 오전에 카드 42의 담당자 변경을 승인했지만, 실제 쓰기 전에 다른 담당자가 카드를 완료 처리했다고 하자. 태그가 바뀌었고 가상 API는 예전 태그를 단 변경 요청을 412로 거절했다.
이때 최신 ETag만 받아 같은 요청을 다시 보내면 충돌 방지 장치를 우회한 셈이 된다. 완료된 카드에도 담당자를 바꿔야 하는지부터 판단해야 한다. 원래 승인 범위가 “진행 중인 카드 배정”이었다면 전제가 달라졌다. 최신 태그는 기술적인 갱신 조건을 맞출 뿐 새로운 업무 판단을 대신하지 않는다.
| 다시 읽어 확인한 변화 | 승인한 변경과의 관계 | 이 글의 권장 판단 |
|---|---|---|
| 담당자가 이미 민호로 바뀜 | 원하는 값과 같지만 누가 왜 바꿨는지 별개 | 현재 상태와 필요한 이력을 확인하고 추가 쓰기 필요성을 판단 |
| 카드가 완료됨 | 진행 중 업무를 재배정한다는 전제가 달라짐 | 이전 변경을 보류하고 완료 상태에서의 필요성을 판단 |
| 관련 없는 표시 문구만 수정됨 | 서버 태그는 바뀌었지만 업무 전제는 유지될 수 있음 | 실제 차이와 기존 위임을 확인해 범위 안에서 갱신안을 다시 구성 |
| 다른 고객의 카드 ID가 선택됨 | 승인 대상 자체가 달라짐 | 최신 태그로 해결하지 말고 대상 선택부터 바로잡음 |
표의 마지막 판단은 HTTP 표준이 정하는 업무 정책이 아니다. 변경을 계속할지 결정할 권한과 전제는 서비스와 조직이 정해야 한다. 모든 충돌을 사람에게 다시 승인받는 절차로 만들 필요는 없지만, 기존 승인이 허용하지 않은 대상·행동을 기술 재시도로 추가해서는 안 된다.
같은 항목을 대조하고, 쓰는 순간에도 조건을 검사한다

실행 직전에 GET으로 다시 읽는 것도 도움이 되지만, 그 뒤 쓰기 전까지 또 바뀔 수 있다. 조건 확인과 갱신을 서버에서 하나의 보호된 처리로 묶어야 이 틈을 막을 수 있다. 조건부 요청의 실제 보장이 필요한 경우에는 격리된 시험 대상에서 다른 갱신을 끼워 넣고 오래된 조건의 쓰기가 거절되는지 확인하는 방법을 제안한다. 이 글에서는 그 시험을 실행하지 않았다.
ETag 하나가 업무 전체의 상태를 대표하는지도 확인해야 한다. 카드 표현의 태그가 같아도 별도 저장소의 고객 동의 상태나 재고가 달라질 수 있다. 승인 판단이 여러 자원에 걸리면 해당 전제를 함께 보호할 수 있는 서비스 기능이 필요하다. 한 자원의 If-Match만으로 여러 시스템을 한 번에 잠갔다고 볼 수 없다.
지원하지 않는 API에 임의 헤더를 추가하는 것으로는 해결되지 않는다. 문서화된 버전 조건이나 원자적인 비교 후 갱신 기능이 있는지 확인한다. 없다면 그 한계를 명시하고 단일 실행 주체로 좁히는 등 실제 가능한 통제와 위험을 판단해야 한다. 프롬프트에 “최신 상태만 수정”이라고 적는 것은 서버의 동시성 제어를 대신하지 않는다.
자주 묻는 질문
충돌이 나면 무조건 사람에게 다시 승인받아야 하나요?
현재 위임이 허용하는 변경인지와 달라진 전제에 따라 다르다. 관련 없는 문구 변경까지 매번 새 승인으로 만들 필요는 없다. 대상·금액·수신자처럼 승인 의미가 달라진 경우에는 그 판단 권한을 가진 담당자가 다시 결정해야 한다.
PATCH를 쓰면 다른 사람의 수정은 보존되나요?
전송 필드를 줄이는 것과 동시 변경을 막는 것은 다른 문제다. 같은 필드를 동시에 바꾸거나 다른 필드의 변화가 업무 전제를 바꾸면 여전히 충돌할 수 있다. PATCH 방식 자체보다 API의 갱신 조건과 적용 범위를 확인한다.
서버가 조건부 갱신을 지원하면 승인 내용도 검증하나요?
그렇지 않다. 상태 조건, 실행 권한, 승인한 변경 내용은 따로 맞춰야 한다. 변경 미리보기의 검사 범위와 함께 보면 사전 검사 통과가 무엇을 남기는지 구분하기 쉽다.
기본적인 위임 범위는 AI 에이전트의 권한과 승인 경계를 참고할 수 있다. 조건을 맞춰 실행했어도 뒤 단계가 실패할 수 있으므로 여러 단계의 부분 성공과 보상 판단은 별도로 다룬다.
“승인 뒤 값이 바뀌었다면: AI 자동화의 ETag와 If-Match”에 대한 1개의 생각