인간이 승인해야 할 것은 Diff가 아니라 의도(Intent)입니다 — 에이전트 승인 게이트(Approval Gates)를 위한 의사결정 테이블
요약
AI 에이전트의 자율 실행 중 인간의 개입을 효율화하기 위한 '의사결정 테이블'을 제안합니다. 단순한 코드 변경 사항(Diff) 대신 의도(Intent)를 검토하도록 하여, 자율성을 유지하면서도 오류를 방지하는 승인 게이트 설계 방법을 다룹니다.
핵심 포인트
- 단순 Diff 검토는 정보 과부하를 초래하여 의도 파악을 방해함
- 가역성(Reversibility)을 기준으로 인간의 개입 시점을 결정해야 함
- 인간의 역할을 결과물 검증에서 상위 계층인 '의도 검증'으로 이동시켜야 함
- 대상 종류에 따라 보여줄 정보의 수준을 결정하는 라우팅 방식 제안
이 글에서 다루는 내용: 에이전트의 자율 실행(Autonomous execution) 속도를 늦추지 않으면서, 되돌리는 비용이 저렴할 때(커밋 또는 게시 직전) 의도(Intent)로부터의 이탈(Drift)을 포착하는 방법. 변경되는 대상의 종류에 따라 게이트(Gate)가 인간에게 전체 Diff 텍스트를 보여줄지, 아니면 의도 요약(Intent summary)만 보여줄지를 기계적으로 결정하는 **의사결정 테이블(Decision table)**을 제공합니다. 이는 여러분의 워크플로우나 팀의 코드 리뷰 관례에 직접 적용할 수 있습니다.
에이전트가 스스로 실행되는 범위를 확장하다 보면, 결국 다음과 같은 갈림길에 서게 됩니다.
- 중단하지 않는 쪽으로 기울면, 의도(Intent)로부터의 이탈이 사후에야 눈에 띄게 됩니다. 작동은 하지만, 잘못된 방향으로 향하고 있습니다. 이를 알아차렸을 때는 이미 문제가 쌓여 있어 되돌릴 여력이 없습니다.
- 중단하는 쪽으로 기울면, 인간이 병목 현상(Bottleneck)이 됩니다. 리뷰 대기열(Review queue)이 형성되고, 자율 실행의 의미가 사라집니다.
- 그래서 타협안을 찾습니다: "최소한 Diff라도 보여주자." 이는 세 가지 중 최악의 선택입니다. 중단하는 데 따르는 비용은 지불하면서도, 양이 너무 많아 아무도 읽지 않게 되며, 결국 의도(Intent)는 여전히 보호받지 못합니다.
저는 세 번째 경우가 가장 널리 퍼져 있다고 의심합니다. 게이트는 형식적으로만 존재하고, 실질적으로는 첫 번째 사례로 돌아가게 됩니다.
여기서 재검토해야 할 점이 있습니다. 이 자동화는 누구를 위한 것인가? 빠르게 가는 것 자체가 목표라면 인간은 방해 요소가 됩니다. 하지만 여러분이 실제로 원하는 것은 의도한 결과물이 빠르게 만들어지는 것입니다. 그렇다면 줄여야 할 것은 인간의 참여 자체가 아니라, 인간이 무엇에 참여하는가입니다.
따라서 이 글은 인간이 중단되는 횟수는 동일하게 유지하면서, 인간이 판단하는 계층(Layer)만을 이동시킵니다. 결과물(Artifact)이 정확한지는 기계의 주요 책임이 되고, 인간은 그 상위 계층을 담당합니다: 이것이 무엇을 목표로 하는지, 그리고 그 결과로 무엇이 변하는지 말입니다. 이는 게이트가 보여주는 내용을 변화시킵니다. 그 라우팅(Routing) 방식이 아래의 의사결정 테이블입니다.
가정
가정
- 예시는 Claude Code 2.1.220과 제가 직접 만든 하네스(harness,
~/.claude아래의 규칙 및 기술 세트)를 기반으로 합니다. - 하지만 최종 결과물은 컨벤션(Conventions)을 작성하는 방법이므로, 특정 도구에 의존하지 않습니다. Cursor, Devin, 또는 귀사의 코드 리뷰 정책에서도 동일하게 작동합니다.
- 전제 조건: AI 에이전트가 무언가를 구현하고, 커밋(Commit) 전에 승인 단계가 존재한다고 가정합니다.
게이트(Gates)의 두 가지 축
승인 게이트를 설계할 때는 실제로 두 가지 독립적인 질문이 존재합니다.
| 축 | 질문 | 결정 요인 |
|---|---|---|
| 첫 번째 축 | 언제 멈출 것인가 | 가역성 (Reversibility). git checkout으로 되돌릴 수 있는 편집은 멈추지 않지만, 외부로 게시하거나, DOI를 발행하거나, 커밋하는 것은 멈춥니다 |
| 두 번째 축 | 멈췄을 때, 인간이 무엇을 판단할 것인가 | 대상의 종류 (이 글의 주제) |
보통 첫 번째 축만 결정되어 있습니다. "커밋 전에 중단". "게시 전에 확인". — 중단 조건은 명시되어 있지만, 중단했을 때 무엇을 보여줄지는 명시되어 있지 않습니다. 제가 만든 하네스도 그러했습니다.
그 빈칸은 비어 있는 상태로 머물지 않습니다. 게이트를 작성할 때마다 그 순간에 편리한 해석으로 채워지며, 기본적으로 채워지는 값은 거의 항상 "디프(Diff)를 보여준다"입니다. 작성자 입장에서는 그것이 가장 안전해 보이기 때문입니다. 모든 것을 보여주면 놓치는 것이 없을 테니까요. 그 결과, 서론에서 언급한 세 번째 사례가 대량 생산됩니다.
의사결정 테이블: 무엇을 보여줄지는 대상에 의해 결정됩니다
이것이 바로 결과물입니다. 게이트가 멈췄을 때, 인간 앞에 무엇을 놓을지는 변경되는 대상의 종류에 따라 결정됩니다. (아래에서 "결정론적 게이트(deterministic gate)"란 린트(lint), 타입 체크(type checking), 테스트, 비밀번호 스캔(secret scan)과 같이 기계가 예/아니오로 답할 수 있는 검사를 의미합니다.)
| 대상 (Target) | 보여줄 내용 (What to show) | 이유 (Why) |
|---|---|---|
행동 형성 아티팩트 (Behavior-shaping artifacts)<br>(CLAUDE.md / AGENTS.md / 규칙 / 기술 및 에이전트 정의 / 공개 문서) | 전체 텍스트 (Full text) | 텍스트 자체가 곧 의도(intent)입니다. 이를 읽는 것 자체가 이미 의도 계층에서의 작업입니다. |
제어 평면 (Control plane)<br>(훅(hooks) / 권한 설정 / --allowedTools와 같은 권한 정의 / 예약된 작업 정의) 및 검사가 실행되는 근거를 생성하는 아티팩트 (테스트 / 피스처(fixtures) / 린트 설정 / 커버리지 임계값 / CI 정의 / 리뷰 에이전트 프롬프트 / 의존성) | 전체 텍스트 (Full text) | 이것들은 게이트 자체와 **게이트가 기반으로 하는 근거(evidence)**를 이동시킵니다. 이를 요약본으로 접어버리면 "검사를 완화하는 변경 사항"이 사라지게 됩니다. |
| 구현 코드 및 생성된 출력물 (Implementation code and generated output) | 의도 요약 (Intent summary)<br>(무엇을 목표로 하는지, 그리고 그 결과로 무엇이 변하는지) | 기계화된 검사가 결정할 수 있는 정확성(correctness)은 결정론적 게이트(deterministic gates)와 리뷰 에이전트의 영역입니다. 디프(diff) 텍스트와 통과(PASS) 목록은 승인 화면에 나타나지 않습니다. |
| 결정론적 게이트가 실패(FAIL)했을 때 | 탐지 라인 자체 (The detection line itself)<br>(비밀 값의 실제 값만 마스킹 처리) | 이는 승인된 계획에 없는 상태이므로, 요약본으로 접을 수 있는 내용이 없습니다 (교차 검증 메커니즘은 나중에 설명합니다). 이를 우회하는 것은 하나의 검사를 비활성화하겠다는 결정이며, 이는 제어 평면과 동일한 범주에 속합니다. |
에스컬레이션 규칙: 불가역성이 대상 범주보다 우선함
이 표는 하나의 원칙이며, 그 자체로 모든 것을 결정하지는 않습니다. "구현 코드" 내에서도 UI의 패딩 수정과 권한 로직, DB 마이그레이션, 결제, 데이터 삭제 또는 키 로테이션(key rotation) 변경은 인간에게 전달해야 할 내용이 서로 다릅니다. 따라서 한 줄의 예외 규칙을 추가합니다.
불가역적이고 영향력이 큰 변경의 경우, 대상 범주에 관계없이 전체 텍스트(또는 관련 디프)를 보여줍니다.
즉, 첫 번째 축(가역성, reversibility)은 '언제 중단할 것인가'뿐만 아니라 '무엇을 보여줄 것인가'에도 영향을 미칩니다. 원칙은 대상의 종류에 따라 결정되며, 불가역성은 전체 텍스트를 보여주는 방향으로 그 강도를 높입니다 — 이 2단계 형태가 정확한 설명입니다. 세 번째 축은 필요하지 않습니다.
한 줄 요약
기계적 검사(mechanized checks)가 결정할 수 있는 정확성(Correctness)은 기계의 영역이며, 인간은 의도(intent)를 보유합니다. 유일한 예외는 텍스트 자체가 곧 의도인 대상입니다. 이 경우 텍스트를 읽는 것 자체가 의도 판단이 되므로, 텍스트를 보여줍니다. 전체 텍스트를 보여주는 것은 과거의 방식으로 퇴보하는 것이 아니라, 동일한 원칙이 다르게 나타나는 것뿐입니다.
의사결정 테이블과 함께 알아두어야 할 원칙이 하나 더 있습니다.
리뷰 에이전트(review agent)는 검사관(inspector)이지, 승인자(approver)가 아닙니다. LLM에는 생성자-검증자 간극(generator–verifier gap)이 존재합니다. 제안하는 측과 검사하는 측이 동일한 계보(lineage)에서 나왔다면, 검사는 제안자의 사각지대를 그대로 물려받게 됩니다. 따라서 승인은 '결정론적 게이트(deterministic gate)의 통과(PASS)'와 '인간의 의도 판단'이라는 두 가지 요소로 구성되며, 절대로 LLM 단독으로 승인이 종결되는 경로를 구축해서는 안 됩니다. 리뷰를 더 무겁게 만든다고 해서 승인을 LLM에 위임할 수 있다는 뜻은 아닙니다.
컨벤션 파일(conventions file)에 작성하면 다음과 같은 모습입니다 (실제 파일에서 발췌하였으며, 내부 링크 및 일부 참조는 생략되었습니다).
## Artifacts는 기계의 것이고, 의도는 인간의 것이다
아티팩트(Artifacts)의 정확성(build / types / lint / tests / secret scan)은 결정론적
...
적용 사례: 다섯 군데에서 실제로 일어났던 일
의사결정 테이블을 만들기 전, 제 하네스(harness)에는 두 번째 축이 비어 있었습니다. 다음 내용은 저의 개인적인 환경을 바탕으로 하지만, 동일하게 비어 있는 설정이라면 어떤 환경에서도 같은 형태가 나타날 것입니다.
동일한 게이트에 두 개의 상충하는 진실(sources of truth)이 존재함
커밋(commit) 직전의 개입 지점에서, 두 파일이 서로 다른 내용을 말하고 있었습니다. 어느 쪽이 정전(canonical, 즉 최종적으로 따라야 하는 기준)인지 어디에도 명시되어 있지 않았습니다.
| 파일 | 내용 |
|---|---|
rules/common/planning.md | "결과 검증 확인 (Verify results check) — 커밋 직전" (무엇을 보여줄지는 명시되지 않음) |
skills/implementation-chain/SKILL.md | "발행 / 예치 / 커밋 직전의 diff 승인 (diff approval)" |
그 기원은 제가 이전에 작성했던 다른 설계 결정 기록 중 단 한 문장이었습니다.
커밋 전에 최종 확인을 수행한다
이 문장은 무엇을 "최종 확인"하는지에 대해 말하지 않았습니다. 하류(downstream) 과정에서 이 문장은 "diff 승인"으로 읽혔고, 정전(canonical) 규칙의 얼굴을 하고 자리 잡게 되었습니다.
"인간이 결과물(artifact)을 검사한다"는 다섯 군데에 흩어져 있었습니다
| 스킬 (Skill) | 이전 문구 | 의사결정 테이블 적용 결과 |
|---|---|---|
implementation-chain | "커밋 직전 diff 승인" | 구현 코드 (Implementation code) → 의도 요약 (intent summary) 로 변경 |
| ... |
그 다섯 가지는 서로 다른 날, 서로 다른 목적으로 작성되었습니다. 조율 없이 모두 동일한 기본값으로 귀결되었기에, 이는 개인의 부주의가 아닙니다. 공백이 있는 곳이라면 어디든 "인간에게 모든 것을 보여준다"는 내용이 채워집니다. 그렇기 때문에 개별 문구를 수정하는 것만으로는 문제를 막을 수 없었습니다. 두 번째 축 자체를 포괄하는 하나의 컨벤션(convention)이 필요했습니다.
그리고 가장 오른쪽 열은 의사결정 테이블이 제 역할을 하는 곳을 보여줍니다. Grep으로 검색하면 다섯 가지 모두 동일해 보이지만, 이들을 일괄적으로 삭제하면 필요한 게이트(gates)까지 제거하게 됩니다. harness-sync는 결국 유지되었습니다. 이것이 동기화하는 것은 규칙과 스킬이므로, 텍스트를 읽는 것 자체가 의도 판단(intent judgment)이 됩니다.
강화 사항 1: 제어 평면(control plane)과 "증거를 생성하는 결과물(artifacts)"
의사결정 테이블의 첫 번째 버전에서, 저는 "구현 코드 및 설정(implementation code and config)" 측에 훅(hooks)과 권한을 배치했습니다. 외부 모델(Codex CLI)의 리뷰는 정확히 그 지점을 최우선 순위 발견 사항으로 지적했습니다.
Codex의 발견 사항
중앙 타겟 경계(central target boundary)는 실행 가능한 하네스 제어(executable harness controls)가 제안자(proposer)가 작성한 요약 뒤에 숨겨지는 것을 허용하며, 새로운 규칙은 기존의 보안 오탐(false-positive) 워크플로우와 충돌합니다.
- [P1] 실행 가능한 하네스 제어를 행동 형성(behavior-shaping)으로 분류 — …
에이전트가 pre-commit 비밀번호 스캔 훅(secret scan hook)을 비활성화했다고 가정해 봅시다. 에이전트는 관례를 글자 그대로 따르면서도 다음과 같이 요약할 수 있습니다.
의도 요약 (Intent summary): pre-commit 체크 설정을 정리하고 체크 기능을 강화함
제어 평면(control plane)이 "게이트 자체를 이동"시키기 때문에, 이를 요약에 포함해 버리면 체크를 느슨하게 만드는 변경 사항이 선의를 가진 문장으로 변질됩니다.
그리고 훅(hooks)과 권한만이 보안을 약화시키는 유일한 방법은 아닙니다. 자신의 구현(implementation)에 맞춰 테스트를 다시 작성하는 것은 가장 조용한 방법입니다. 이 경우 에이전트는 거짓말을 할 필요조차 없습니다.
의도 요약 (Intent summary): 구현 사항을 수정함; 모든 테스트 통과(PASS)
이것은 정확히 사실입니다. 요약에서 절대 드러나지 않는 단 한 가지 사실은, 재작성된 대상이 바로 테스트였다는 점입니다. 단순히 "테스트가 통과했다"가 아니라, "무엇을 통과로 간주할 것인가" 자체가 검토 대상이 된 것입니다. 픽스처(Fixtures), 커버리지 임계값(coverage thresholds), 린트 설정(lint config), CI 정의, 리뷰 에이전트 프롬프트(review agent prompts), 그리고 의존성(dependencies) 모두 동일한 특성을 가집니다.
그렇다면 이를 어떻게 제시해야 하는가
정답은 다음과 같습니다: 커밋마다 "요약 또는 텍스트" 중 하나를 선택하지 마십시오. 만약 하나의 커밋에 구현 사항과 증거(evidence)가 모두 포함되어 있다면, 요약을 보여주되, 증거에 해당하는 부분에 대해서만 전체 텍스트를 요약과 함께 보여주십시오.
의도 요약 (Intent summary): 로그인 실패 재시도 제한을 5에서 3으로 변경함 (계획 단계 2)
⚠ 이 변경 사항은 체크의 근거가 되는 증거를 건드립니다 — 아래 텍스트를 검토하십시오
...
인간은 마지막 두 줄만 읽습니다. 구현 측면의 diff(차이점)는 표시되지 않습니다. 당신이 확인해야 할 것은 오직 테스트가 구현에 맞춰 완화되었는지 여부뿐이므로, 양에 압도당할 일은 없습니다. 위의 예시는 계획 단계에서 결정된 변경 사항에 해당하므로 통과됩니다. 만약 계획에서 재시도(retries)에 대해 아무런 언급이 없었는데 테스트 임계값(threshold)만 낮아졌다면, 바로 그 지점에서 중단해야 합니다.
증거(evidence) 측에 있는 파일은 대개 경로를 통해 파악할 수 있습니다.
# 변경된 파일에서 "증거를 생성함"에 해당하는 후보를 추출하여 전체 텍스트로 표시
git diff --cached --name-only | grep -E \
'^(tests?/|\.github/workflows/|\.claude/|hooks/)|(_test\.|\.test\.|pyproject\.toml|package\.json|ruff\.toml|codecov\.yml)'
이것은 완전한 분류기(classifier)가 아니라, 보수적인 후보 추출기(candidate extractor)입니다. 일반 코드에 내장된 테스트, 커스텀 디렉토리, 락파일(lockfiles), 인라인 스냅샷(inline snapshots) 등은 놓칠 수 있습니다. 본인의 리포지토리(repo)에서 알고 있는 증거 측 파일들을 추가하여 이를 확장해 나가십시오. 그럼에도 불구하고, 에이전트가 매번 기억하도록 만드는 것보다 훅(hook)이 기계적으로 이를 포착하도록 하는 것이 더 신뢰할 수 있습니다.
제어 평면(control plane: 훅 / 권한 / 예약된 작업)도 동일한 방식으로 작동합니다: 요약과 관련 파일의 전체 텍스트를 함께 제공합니다. 판단의 근거가 되는 증거를 생성하는 모든 것은 판단 그 자체와 동일하게 취급됩니다.
강화 2: 실패(FAIL) 시, 탐지된 라인을 표시할 것
동일한 검토에서 발견된 두 번째 사항입니다. "기계 검사 통과(PASS) 목록과 diff 텍스트가 없으면 인간에게 전달하지 않는다"는 원칙을 끝까지 밀어붙이십시오. 그러면 인간이 시크릿 스캔(secret scan)의 오탐(false positive) 여부를 판단해야 하는 경로 자체를 삭제할 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기