Emetgate: LLM과 소스 코드 사이의 검증 게이트

Published · AI Daily — AI-assisted deep research, methodology & disclosure

Emetgate는 GitHub의 오픈소스 검증 커널로, Windows에서 언어 모델과 TypeScript/JavaScript 소스 트리 사이에 놓입니다. 모델은 변경을 제안만 할 수 있고 파일은 쓸 수 없습니다. 커널이 해시와 파싱 결과, 영향 범위를 검사하고 필요하면 샌드박스에서 테스트한 뒤 원자적으로 커밋하거나 거부합니다. README는 초기 단계라고 밝힙니다.

Emetgate란 무엇인가

Emetgate는 GitHub의 오픈소스 프로젝트(emetgate/emetgate)입니다. README는 스스로를 "언어 모델과 소스 트리 사이에 놓이는 결정론적 검증 커널"이라고 설명합니다. 구호는 "Nothing passes but the truth."(진실만이 통과한다)입니다. README에 따르면 프로젝트는 아직 초기 단계이고 범위를 의도적으로 좁혔습니다. 대상은 Windows뿐이고, Zig 0.16.0으로 작성되었으며, TypeScript와 JavaScript 코드를 다룹니다. 도구는 Model Context Protocol(MCP)로 노출되므로 Claude Code 같은 MCP 클라이언트가 바로 사용할 수 있습니다.

발상은 단순합니다. 언어 모델은 코드를 읽고 특정 심볼에 대한 변경을 제안할 수 있습니다. 하지만 파일을 쓸 수 없고, 작업이 끝났다고 선언할 수도 없습니다. 모든 제안은 작은 커널이 검사하며, 원자적으로 커밋되거나 이유와 함께 거부됩니다. README는 이를 "모델은 제안하고, 커널은 검증한다. 검증되지 않은 것은 디스크에 닿지 않는다"라고 요약합니다.

작성자가 만든 이유

README는 LLM이 생성한 코드를 진지하게 써 본 사람이라면 아는 실패 유형을 나열합니다. 컴파일은 되지만 여전히 틀린 코드, 끝나지 않은 작업을 끝났다고 보고하는 모델, 세 턴 전에 정한 규칙을 조용히 잊어버리는 일, 세션 초반에 합의한 계획이 끝날 무렵 사라져 버리는 일입니다. 작성자는 이 문제들이 서로 다른 것처럼 보이지만 원인은 하나라고 주장합니다. 모델과 디스크 사이에 모델의 산출물을 확인할 책임을 진 존재가 없다는 것입니다.

README에 따르면 현재의 도구들은 자율성과 속도로 경쟁하고, 그 결과 검증되지 않은 출력의 양이 늘어납니다. 모델 스스로는 이 간극을 메울 수 없습니다. 모델은 "샘플러이지 신탁이 아니며" 지속적인 기억도 없기 때문입니다. 그래서 Emetgate는 모델에게 아무 권한도 주지 않고 모든 권한을 커널에 둡니다. README는 이를 LCF 방식의 정리 증명기에 비유합니다. 전술(tactic)은 무엇이든 제안할 수 있지만 정리를 만들어 낼 수 있는 것은 작고 신뢰할 수 있는 커널뿐이라는 구조입니다. 이름은 프라하 골렘 전설에서 왔습니다. 골렘의 이마에 적힌 emet("진리")라는 단어가 골렘을 움직이고, 첫 글자를 지우면 met("죽음")가 됩니다.

변경이 게이트를 통과하는 과정

README는 여섯 단계를 설명합니다.

1. **주소 지정.** 각 심볼은 참조(`Class.method`, `add`)와 현재 내용의 128비트 해시로 식별됩니다. 제안은 자신이 근거로 삼은 해시를 밝혀야 합니다. 그사이 파일이 바뀌면 해시가 맞지 않아 제안이 거부됩니다. 따라서 모델은 보지 못한 코드를 덮어쓸 수 없습니다.

2. **파싱.** 새 함수 본문을 바이트 범위로 끼워 넣고, 파일 전체를 tree-sitter로 다시 파싱합니다.

3. **가드.** 결과가 깨끗하게 파싱되는지, 본문이 중괄호 밖으로 벗어나지 않았는지, 비어 있거나 자리표시자가 아닌지, 대상 범위 밖의 모든 바이트가 그대로인지를 확인합니다.

4. **경계 판정.** 커널은 변경의 영향 범위를 계산합니다. 이 분석은 긍정적인 폐쇄 세계 계수 방식입니다. 벗어날 수 있는 모든 경로가 배제되었을 때만 `BOUNDED`이고, 설명하지 못하는 것은 `UNBOUNDED`입니다.

5. **테스트.** `UNBOUNDED` 변경은 섀도 복사본에 적용되고, 프로젝트의 테스트 명령이 샌드박스 안에서 실행됩니다. 샌드박스는 kill-on-close, 실제 시간과 메모리 제한, 출력 상한을 갖춘 Windows Job Object입니다. 명령은 낮은 무결성 수준의 제한된 토큰으로 실행되며, 이 토큰을 만들고 검증할 수 없으면 제한 없이 실행하는 대신 명령을 거부합니다. 테스트가 실패하면 변경은 거부되고 출력이 모델에 반환됩니다.

6. **커밋.** 승인된 변경은 선행 기록 저널과 원자적 쓰기 후 이름 바꾸기를 거칩니다. 중간에 충돌하더라도 남는 것은 예전 파일이거나 새 파일이지, 절반만 쓰인 파일이 아닙니다. `recover` 명령은 저널을 재생하고 증명할 수 없는 항목은 거부합니다.

README는 커널을 fail-closed라고 부릅니다. 변경이 안전하다고 증명할 수 없으면 그 변경을 거부합니다.

MCP 도구와 lockdown

서버는 읽기 도구와 변경 도구를 노출합니다. 읽기 도구는 `emetgate_symbols`, `emetgate_skeleton`, `emetgate_read_symbol`, `emetgate_read_file`, `emetgate_list`, `emetgate_search`이며 뒤의 셋은 저장소 안으로 제한됩니다. `emetgate_mutate`는 쓰지 않고 구조 검증만 합니다. `emetgate_try`는 검증, 게이트 통과, 커밋을 수행합니다. `emetgate_try_batch`는 여러 제안을 하나의 단위로 다룹니다. `emetgate_scan`은 하나의 검사 표현식을 저장소에 대해 측정하며 아무것도 쓰지 않습니다.

`emetgate lockdown` 명령은 이 도구들만 쓸 수 있는 상태로 Claude Code를 시작합니다. 그래서 모델에게는 게이트 외에 디스크로 가는 길이 없습니다. 저장소에는 Claude Code 스킬 `md-audit`도 들어 있습니다. CLAUDE.md나 AGENTS.md의 각 지시 문장을 강제 가능, 메커니즘 대기, 검증 불가, 믿음으로 분류하고, 강제 가능한 것을 `emetgate_scan`으로 측정합니다. 아무것도 변경하지 않습니다.

커널 자체는 어떻게 검증되는가

README는 스스로 검증되지 않은 검증 계층은 "더 정교한 희망 사항일 뿐"이라고 말하며 두 가지 방법을 듭니다. 첫째는 뮤테이션 테스트입니다. 가드를 변형하고(검사 제거, 조건 약화, 비교 뒤집기) 변형마다 테스트 스위트가 실패해야 합니다. 엔진의 `cas`, `boundedness`, `symbol`, `functions`에 대해 README는 변이체 44개 중 37개 제거, 4개는 동등함이 증명됨, 1개는 다층 방어로 남긴 중복 가드, 2개는 미해결이라고 보고합니다. 둘째는 레드팀 테스트로, 중괄호를 벗어나는 본문, 오래된 해시, 찢어진 저널 항목, 오염된 저장소 설정, 저장소 밖 파일 접근 시도를 공격합니다.

토큰 벤치마크도 보고됩니다. 여섯 시나리오(그중 둘은 실제 파일)와 `o200k_base` 토크나이저 기준으로, 심볼 단위 제안은 검색 후 바꾸기 방식보다 중앙값 1.80배 적은 토큰을 썼고 범위는 1.15배에서 3.77배였습니다. 실제 파일에서는 1.15배에서 1.17배였습니다. README는 토큰 절감이 "부수 효과일 뿐 목적이 아니다"라고 말합니다.

우리의 분석

눈여겨볼 점은 신뢰를 어디에 두느냐입니다. 많은 코딩 도구는 모델을 어떻게 더 믿을 만하게 만들지를 묻습니다. Emetgate는 모델의 신뢰할 수 없음을 어떻게 무해하게 만들지를 묻습니다. 검사가 입력의 결정론적 함수이기 때문에 검토자는 그것을 읽고, 테스트하고, 공격할 수 있습니다. 이는 모델이 스스로 "작업을 마쳤다"고 하는 주장과는 다른 종류의 보증입니다.

두 가지 세부 사항이 눈에 띕니다. 내용 해시는 "모델이 오래된 코드를 편집했다"는 조용한 버그를 거부되는 제안으로 바꿉니다. 그리고 폐쇄 세계 경계 규칙은 확신이 없을 때 기본적으로 테스트를 돌려 속도를 안전과 맞바꿉니다.

한계와 열린 질문

README는 한계를 솔직하게 밝힙니다. 파싱되고, 범위 안에 있고, 테스트도 통과하는 코드가 여전히 잘못된 동작을 구현할 수 있습니다. 테스트 게이트의 강도는 테스트의 질에 달려 있습니다. 보증은 게이트를 통과하는 변경에만 적용되므로 다른 도구의 편집은 게이트를 우회하고, 그래서 lockdown이 존재합니다. 낮은 무결성 토큰은 섀도 복사본 밖으로의 쓰기를 막지만 읽기와 네트워크 접근은 제한하지 않아, 악의적인 테스트 명령이 권한 있는 파일을 읽고 네트워크에 접근할 수 있습니다. AppContainer가 계획되어 있습니다. 아키텍처, API 설계, 사용자 경험은 커널이 검사할 수 있는 속성이 아닙니다.

상태 표를 보면 결정 원장은 아직 MCP 도구로 노출되지 않았고, 편집 게이트에서의 규칙 강제는 진행 중입니다. 지원 언어는 TypeScript와 JavaScript뿐이고 플랫폼은 Windows뿐입니다. 우리는 README만 읽었고 도구를 실행하지 않았습니다. 벤치마크와 뮤테이션 수치는 작성자 본인의 것입니다.

독자를 위한 실용적 제안

Windows에서 TypeScript나 JavaScript를 쓰는 팀은 릴리스 바이너리와 SHA-256 체크섬을 내려받아 대조한 뒤 `claude mcp add`로 서버를 등록할 수 있습니다. README는 바이너리에 코드 서명이 없어서 처음 실행할 때 SmartScreen이 경고한다고 적고 있습니다. 소스 빌드에는 Zig 0.16.0과 `zig build`가 필요합니다. 타입 검사와 테스트 명령은 운영자가 제공하며, `--typecheck`와 `--test`로 주거나 `--allow-repo-config`를 쓸 때 `.emetgaterc.json`에서 읽습니다. 모델이 직접 제공하는 일은 결코 없습니다. 다른 독자에게도 이 README는 간결한 원칙 선언으로 읽힙니다. 모델에게 쓰기 권한을 주지 말고, 받아들여지는 모든 변경이 사람이 점검할 수 있는 검증을 통과하게 하라는 것입니다.

Sources

FAQ

Emetgate는 무엇을 하나요?

언어 모델과 소스 트리 사이에 놓이는 결정론적 검증 커널입니다. 모델이 심볼에 대한 변경을 제안하면 커널이 검사해서 원자적으로 커밋하거나 이유와 함께 거부합니다.

테스트를 돌릴지 어떻게 결정하나요?

영향 범위를 계산합니다. 벗어날 수 있는 모든 경로가 배제되어야만 BOUNDED입니다. UNBOUNDED 변경은 샌드박스 안의 섀도 복사본에서 프로젝트의 테스트 명령을 실행합니다.

README가 밝히는 한계는 무엇인가요?

검사를 통과한 코드도 틀릴 수 있고, 테스트 게이트의 강도는 테스트에 달려 있으며, 다른 도구의 편집은 게이트를 우회합니다. 샌드박스는 아직 읽기와 네트워크를 제한하지 않습니다. Windows, TypeScript, JavaScript만 지원합니다.