AI가 잘 고칠 수 있다는 말과 지금 이 회사 자료를 바꿔도 된다는 판단은 다른 일이다. 나는 바꾸려는 내용을 먼저 비교할 수 있고 검토 뒤 조건이 바뀌면 다시 멈추는 흐름을 만들고 싶었다.

이번 예제의 수정안은 고정 합성 값이다. 외부 모델을 호출하거나 실제 회사 기록을 보내지 않았다. 작성자와 검토자를 문자열로 둔 순수 계산이며 실제 로그인과 승인 서비스는 별도로 필요하다.

자유 문장이 바로 실행 명령이 되지 않게 한다

proposal은 수량과 메모만 바꿀 수 있다. 회사 ID와 revision을 임의 변경하는 제안은 받지 않는다. 수량은 정해진 정수 범위, 메모는 제한된 합성 문자 형식을 검사한다. 자연어를 실행하거나 코드 조각을 평가하는 경로가 없다. 어떤 종류의 변경을 다루는지 작은 계약으로 먼저 한정했다.

실제 AI가 만든 결과를 연결한다면 모델 응답도 이 계약 밖에서는 신뢰하지 않아야 한다. 잘 쓴 설명이 필드 허용 목록과 권한 검사를 대신하지 않는다. 이번 예제는 모델의 판단 품질을 평가하지 않고 제안 값을 받았을 때 어떤 단계로 검토할지 구현한다. 업무 권한을 AI 문장에 맡기는 기능은 만들지 않았다.

전후 차이와 기준을 같은 지문에 담는다

제안에는 회사, expected_revision, 작성자와 diff가 들어 있다. diff는 실제로 달라지는 필드의 before와 after를 담고 변화가 없으면 거절한다. 이 내용으로 SHA-256 지문을 만든다. 검토자가 읽은 내용과 적용하려는 내용이 같은지 다시 비교할 수 있게 하기 위한 값이다.

지문은 비밀도 서명도 아니다. 누군가 새 내용을 만들고 다시 해시할 수 있으므로 그 자체로 신뢰할 승인 증거가 되지 않는다. 실제 서버가 보관한 제안과 승인 기록의 출처가 필요하다. 나는 해시를 붙였다는 사실을 보안 인증이 완성됐다는 표현으로 쓰지 않고 내용 비교의 도구로만 설명했다.

검토는 원본을 바꾸지 않는다

review는 다른 검토자와 reviewer 역할을 요구하고 현재 상태에서 제안을 다시 계산한다. 원본과 맞지 않으면 검토 자체를 거절한다. 통과한 결과는 지문과 검토자, 승인 여부를 담은 영수증 값이다. 이때 원래 수량은 그대로 남는지 테스트했다. 읽고 동의하는 단계와 실제 적용을 구분한 것이다.

이 역할과 영수증은 신뢰할 서버에서 전달받아야 한다. 클라이언트가 role을 reviewer라고 쓰거나 영수증을 만들 수 있는 서비스라면 이 예제만으로 안전하지 않다. 실제 승인 기록의 저장과 열람 권한은 구현하지 않았다. 독립 순수 함수의 입력 전제를 공개해 재사용할 때 놓치지 않게 했다.

검토 뒤 바뀐 자료에는 예전 결정을 적용하지 않는다

apply_reviewed는 현재 상태에서 같은 검토를 다시 확인한다. 그 사이 revision이 바뀌었거나 제안의 수량이 달라지면 실패한다. 정상이라면 새 복사본의 값과 revision을 계산하고 원본은 보존한다. 이 함수도 DB에 쓰지 않는다. 동시에 들어오는 두 적용을 거래로 막는 책임은 실제 저장소에 있다.

로컬 검사에서는 검토 뒤 원본 버전 변경과 제안 내용 변경을 각각 거절했다. 다른 모듈과 연결한 검사에서는 그 실패가 사용자의 더 최신 초안을 지우지 않는지도 확인했다. 사람이 한 번 승인했다고 이후 모든 수정에 무한히 유효한 권한이 생기는 것은 아니라는 판단을 두 경계에서 확인했다.

AI의 역할을 제안 단계부터 넓힐 수 있다

공유 패키지에는 제안, 검토와 적용 계산을 따로 실행한 기록과 전체 코드가 들어 있다. 실제 AI 서비스, 운영 승인과 회사 자료 변경은 연결하지 않았다. 방문자는 어떤 차이를 먼저 보여 주고 어디서 다시 확인할지 자기 업무에 맞춰 검토할 수 있다. 모델 이름보다 검토할 내용과 권한의 관계가 먼저다.

실제 연결 때는 승인자의 로그인, 서버 측 제안 보관, 현재 버전 확인과 변경 이력을 함께 구현해야 한다. 적용 성공과 외부 후속 작업의 완료도 구분해야 한다. 나는 AI가 자동으로 처리한다는 한 문장보다 사람이 비교할 수 있는 제안과 범위가 유지되는 실행 조건을 공개하고 싶었다.