
plimsoll을 만든 캐럴 게르틴(Carroll Guertin)은 AI가 작성한 로봇 주문 어댑터가 응답을 받지 못해 주문을 반복하는 사례를 공개했다. 이 예제는 어댑터의 보고를 믿는 대신 업체의 주문 장부를 확인해 중복을 판별하고, 신뢰하지 않는 코드를 제한된 환경에서 실행하는 방법을 보여준다.
피자 가게에 주문한 뒤 응답을 듣기 전에 전화가 끊기면, 주문이 접수됐는지 알 수 없어 다시 전화하게 된다. 창고 로봇도 마찬가지다. 업체가 주문을 접수한 뒤 응답만 사라지면 어댑터는 실패로 판단하고 재주문할 수 있다. 예제에서 adapter-v1.js는 주문 번호인 command_id를 보내지 않아 같은 명령으로 로봇 r2에 두 건을 주문했다. 로봇은 같은 장소로 두 번 이동했다.
반면 adapter-v2.js는 재시도할 때 같은 command_id를 보낸다. 업체는 이미 접수한 주문 m2를 돌려주므로 장부에는 명령당 주문이 하나만 남는다. 여덟 가지 규칙을 검사하는 채점기는 첫 어댑터가 one_order_per_command 규칙을 위반했다고 판정하고, 두 번째는 여덟 규칙을 모두 통과시킨다. 두 어댑터 모두 완료했다고 보고했지만, 장부는 첫 번째가 중복 주문을 냈음을 보여준다. 첫 번째 어댑터 실행과 두 번째 실행은 예제 페이지에서 재생할 수 있다.
게르틴은 첫 번째 어댑터가 예제를 만든 세션에서 작성됐으므로 독립적인 시험은 아니라고 밝혔다. 별도의 세션에서 도구 없이 계약과 규칙만 받은 Claude Haiku, Sonnet, Opus는 모두 주문 번호를 사용했다. 예제의 요점은 AI가 이 문제를 틀린다는 주장이 아니라, 플랫폼이 어댑터의 말에 의존하지 않고 결과를 검사할 수 있다는 것이다.
업체가 주문을 접수한 뒤 계속 응답하지 않는 silent 상황에서는 어댑터도 주문 여부를 알아낼 수 없다. 두 번째 어댑터는 작업별로 재시도를 포함해 40번, 약 0.25초 간격으로 호출한 뒤 unresolved 오류를 반환한다. 업체가 주문을 보유했을 수도, 아닐 수도 있다고 알리는 방식이다. 예제에서는 실제로 업체 장부에 주문 m2가 남아 실행 중이다. 의도적으로 고장 낸 어댑터 중 하나는 세 번 시도한 뒤 refused를 반환하지만, 채점기는 업체가 주문을 보유한 사실과 맞지 않는다며 report_is_true 규칙에서 실패시킨다. 이 오류를 믿고 다시 주문하면 중복이 생길 수 있다.
plimsoll은 중복 주문 자체를 막지 않는다. 예제에서 바뀌는 것은 신뢰하지 않는 코드를 어디서 실행하는지, 코드가 무엇에 접근할 수 있는지, 실행 뒤 판정을 확인할 수 있는지다. 어댑터는 네트워크가 차단된 샌드박스에서 실행되고, 브로커를 통해 허용된 여섯 가지 요청만 업체에 전달한다. 브로커는 해당 실행에만 유효한 인증 키를 요청에 추가하므로 어댑터는 업체의 실제 키를 보유하지 않는다. 채점기는 어댑터의 보고가 아니라 업체의 장부를 읽는다.
예제의 경계 검사에서는 샌드박스에서 업체로 직접 보낸 요청이 ECONNREFUSED로 거부됐고, 브로커를 거치지 않은 DELETE /robots/r1 요청은 403을 받았다. 환경과 클라이언트에서도 인증 키를 찾지 못했다. 업체에 연결된 51회 실행에서 서로 다른 키 50개가 관찰됐으며, 각 키는 95초 동안 유효했다. 업체가 과부하로 503을 반환하면 브로커의 회로 차단기가 열려 다음 호출을 1초간 늦췄다.
다만 채점기는 예제에 포함된 일반 코드이므로 plimsoll만의 기능은 아니다. 게르틴은 신뢰하지 않는 코드에 실제 키가 닿지 않게 한 채 검사를 실행하고, 다른 사람이 근거를 확인하도록 전달하는 데 샌드박스가 쓰인다고 설명한다. 그는 10월 14일과 15일 두 차례 시험에서 AI 에이전트의 초안 어댑터를 평가하던 도우미가 자신의 컴퓨터에서 샌드박스 밖으로 실행됐으며, 이 사실은 보안 검토에서 이틀 뒤 발견됐다고 밝혔다. 이후 도우미는 브로커를 통하는 샌드박스에서 실행하도록 바뀌었고, 비밀 환경 변수를 심어 어댑터가 이를 읽거나 홈 디렉터리를 나열하지 못하는지 검사하는 테스트도 추가됐다.
각 실행과 판정은 샌드박스에 들어간 내용과 나온 내용을 해시로 묶고 서명한 기록으로 보관한다. 저장된 내용을 바꾸면 서명 검증에 실패한다. 다음 명령은 저장소 복제본에서 두 번째 어댑터의 실행 기록 한 줄을 검증하는 예다.
$ go build -o plimsoll-attest ./cmd/plimsoll-attest
$ cd docs/examples/adapter
$ ../../../plimsoll-attest verify-entry -pub harness.pub -line 13 bundle.jsonl
entry verified: line 13, signed by key 02c7b7eed354d6297e60f1f69eb7579acc1fcdc5a35cd1c398f05ddf5fd94fc7: record 3c54bdfe1ccb0b753d9e44238afc250fc7e7212f5aa444242f5fe59319ac674e, a single run; the signed record states provider docker and isolation "kernel". It authenticates the recorded messages, not that what the guest printed is true. Not established by this check: the bundle around the line, and for a session call that its session's chain is whole; plimsoll-attest verify checks a whole bundle
기록에서 어댑터가 주문을 네 번 확인했다고 적힌 값을 다섯 번으로 바꾼 뒤 검증하면 체인이 깨졌다는 오류가 난다.
$ ../../../plimsoll-attest verify-entry -pub harness.pub -line 13 bundle-altered.jsonl
plimsoll-attest: attest: broken bundle chain: the line's link signs other content
go run ./examples/adapter -verify docs/examples/adapter는 근거로 판정을 다시 계산한다. 예제는 51개 실행 기록과 51개 적격성 판정을 모두 검증했다고 보고한다.
서명은 기록에 서명한 주체가 해당 바이트를 확인했다는 뜻이지, 기록 내용이 참이라는 증명은 아니다. 업체는 게르틴이 만든 시뮬레이터이며, 실제 로봇 업체의 장부와 대조한 결과가 아니다. 서명 키 자체를 보증하는 자료도 없다. 기록에는 plimsoll 서버가 샌드박스 설정을 docker under gVisor의 kernel 등급으로 보고했다고 적혀 있지만, 이는 설정과 시작 단계 검사이며 하드웨어 증명은 아니다. 또 Opus는 여덟 시나리오를 모두 통과했고, Haiku와 Sonnet은 과부하 상황에서 복구 전에 연결을 끊고 이를 보고한 경우에만 실패했다. 이 예제의 목적은 모델 순위를 매기는 것이 아니라 채점 방식을 보여주는 데 있다.
통합 코드를 만드는 경우 각 명령에 업체가 인정하는 주문 번호를 붙이고, 어댑터가 모른다고 답할 수 있게 하며, 어댑터의 설명보다 업체의 상태를 기준으로 판정해야 한다. 실행 중인 코드가 비밀 키에 접근하지 못하도록 하는 것도 이 예제가 제시하는 조건이다.
증거 검증은 Go만으로 가능하다. 전체 실행에는 Docker가 필요하며, plimsoll 서버를 소스에서 빌드해 51회 실행한다. 공개된 증거와 같은 gVisor 실행에는 SANDBOX_DOCKER_RUNTIME=runsc를 사용한다. 계약, 업체 시뮬레이터, 채점기와 고장 난 어댑터는 예제 저장소에 있으며, plimsoll은 Apache-2.0 라이선스를 따른다. plimsoll 저장소
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요