[AI가 읽을 수 있는 코드베이스 4/5] Acceptance 증명이 리뷰를 바꾼다

"이거 돌아가?" — Code Review의 가장 비싼 질문
AI 코딩 에이전트가 PR을 만들었습니다. 리뷰어가 코드를 엽니다. 첫 번째 질문은 거의 항상 같습니다.
"이거 진짜 돌아가?"
이 질문에 답하는 비용을 생각해보겠습니다. 리뷰어는 코드를 읽고, 머릿속에서 실행 흐름을 따라가고, 엣지 케이스를 상상합니다. 복잡한 변경이라면 로컬에서 체크아웃해서 직접 돌려봐야 합니다. 이 과정에서 소모되는 인지 에너지는 상당합니다.
그런데 이 에너지가 향하는 곳을 보면, 동작 확인이지 설계 판단이 아닙니다. 리뷰어의 시간 중 가장 가치 있는 부분 — "이 추상화 수준이 맞는가?", "이 모듈 경계가 적절한가?", "이 변경이 다른 도메인에 의도치 않은 영향을 주지 않는가?" — 에 도달하기도 전에 에너지가 소진됩니다.
AI가 코드를 더 많이 생성하게 되는 시대에서, 이 병목은 심화됩니다. PR의 양은 늘어나지만, 리뷰어의 인지 자원은 늘지 않습니다.
병목의 전환: 동작 확인 → 설계 판단
flex가 찾은 답은 Acceptance 증명 우선 워크플로우입니다.

핵심 차이는 리뷰어가 PR을 열었을 때 이미 동작 증명이 존재한다는 것입니다. E2E 테스트 통과 결과, 그리고 선택적으로 데모 녹화 영상이 PR에 첨부되어 있습니다. "이거 돌아가?"는 이미 답이 나와 있으므로, 리뷰어는 "이 설계가 이 맥락에서 맞는가?"에 곧바로 집중할 수 있습니다.
E2E 테스트 자동화: Gradle 태스크의 설계
지난 3화에서 분석한 standalone-app의 E2E 인프라를 다시 보겠습니다. 이번에는 Gradle 태스크의 설계 관점에서 분석합니다.
서버 시작: startE2EServer
설계의 핵심은 세 가지입니다. 첫째, 이미 실행 중인 서버를 재사용합니다. 개발자가 bootRun으로 서버를 띄워놓은 상태에서도, AI 에이전트가 반복 실행할 때도 매번 재시작하지 않아 피드백 루프가 빨라집니다. 둘째, PID 파일로 프 로세스를 추적하여 stopE2EServer에서 안정적으로 정리합니다. 셋째, 타임아웃 초과 시 로그 파일 경로를 포함한 에러를 던져 2화에서 이야기한 "에러 메시지에 맥락을 담아라"를 실천합니다.
E2E 테스트 실행: e2eTest
Playwright E2E 테스트는 프론트엔드 디렉토리에서 실행됩니다. frontend/e2e/tests/ 디렉토리에 테스트 시나리오가 있고, frontend/e2e/fixtures/에 테스트 데이터가 있습니다.
전체 라이프사이클: e2eTestWithServer
tasks.register("e2eTestWithServer") {
group = "e2e"
dependsOn("frontendBuild", "startE2EServer", "e2eTest")
finalizedBy("stopE2EServer") // 성공/실패 관계없이 서버 정리
}이 태스크 하나가 전체 E2E 라이프사이클을 관리합니다.

finalizedBy("stopE2EServer")는 E2E 테스트가 성공하든 실패하든 서버가 반드시 정리되도록 보장합니다. stopServer 함수는 PID 파일을 읽어 graceful shutdown을 시도하고, 실패하면 force kill로 재시도합니다. AI 에이전트가 E2E를 반복 실행하더라도 포트 충돌이나 좀비 프로세스 가능성을 크게 줄입니다.
Demo 녹화: recordDemoWithServer
E2E 테스트의 확장으로, 데모 녹화 기능이 있습니다.
playwright.config.demo.ts는 일반 E2E 설정(playwright.config.ts)과 별도입니다. 데모용 설정은 영상 녹화, 스크린샷 캡처, GIF 변환 등 시각적 산출물을 생성하도록 구성됩니다. onlyIf { !isCi }로 CI에서는 실행되지 않고, 로컬에서만 동작합니다.
이 녹화물은 PR에 첨부할 수 있습니다. 리뷰어는 코드를 읽기 전에 데모 영상으로 변경 사항의 동작을 확인할 수 있습니다.
AI PR에 Acceptance 증거가 붙는 워크플로우
이 인프라를 AI 에이전트의 워크플로우와 결합하면 다음과 같은 흐름이 만들어집니다.

이 워크플로우에서 에이전트의 자율적 수정 루프(B→C→D→B, E→F→G→H→B)가 핵심입니다. 빌드 실패와 E2E 실패 모두 에이전트가 자체적으로 분석하고 수정합니다. 사람(리뷰어)이 개입하는 시점은, 이미 동작이 증명된 후입니다.
Code Review의 무게 중심 이동
Acceptance 증명이 자동화되면 Code Review의 성격이 바뀝니다.
Before: 동작 중심 리뷰
## PR Review Comments (기존)
- [ ] API 응답 형식이 기존과 일치하는가?
- [ ] 에러 케이스에서 500이 나지 않는가?
- [ ] NULL 처리가 되어 있는가?
- [ ] 테스트를 추가했는가?
- [ ] 로컬에서 돌려봤는가?리뷰어의 에너지가 동작 정합성 검증에 소모됩니다.
After: 설계 중심 리뷰
## PR Review Comments (Acceptance 이후)
✅ E2E: 8/8 passed | Demo: recorded
- [ ] 이 UseCase의 책임 범위가 적절한가?
- [ ] 이 이벤트 발행 시점이 트랜잭션 경계와 맞는가?
- [ ] 이 모듈 간 의존성 방향이 설계 의도에 부합하는가?
- [ ] 이 추상화가 향후 확장성을 지원하는가?동작은 이미 증명되어 있으므로, 리뷰어는 설계 품질에 집중합니다.
이 전환이 가져오는 효과는 세 가지입니다.
| 효과 | 설명 |
|---|---|
| 리뷰 속도 향상 | "돌아가나?" 검증을 건너뛰므로, 리뷰 시간이 단축됨 |
| 리뷰 품질 향상 | 리뷰어의 인지 자원이 더 높은 가치의 판단에 투입됨 |
| AI PR 신뢰도 | "에이전트가 만든 PR"에 대한 경계심이 증거로 상쇄됨 |
Acceptance 증명의 한계와 보완
물론 E2E 테스트 통과가 모든 것을 보장하지는 않습니다.
E2E가 잡지 못하는 것:
- 성능 저하 (기능은 동작하지만 느려진 경우)
- 보안 취약점 (기능은 동작하지만 인가 우회가 가능한 경우)
- 데이터 일관성 (특정 동시성 조건에서만 깨지는 경우)
- 코드 가독성과 유지보수성
이 영역들이 사람 리뷰어가 여전히 필요한 이유입니다. Acceptance 증명은 "리뷰를 없앤다"가 아니라, 리뷰의 무게 중심을 이동시킵니다. 반복 가능하고 자동화할 수 있는 동작 확인을 인프라에 맡기고, 설계 판단에 사람의 시간을 집중시킵니다.
flex에서 이 접근을 "Acceptance 증명 우선"이라 부르는 이유가 여기에 있습니다. AI가 만든 코드든 사람이 만든 코드든, PR이 올라올 때 acceptance가 자동으로 증명되면 리뷰의 무게 중심이 달라집니다.
Acceptance 인프라가 AI 에이전트에게 주는 것
마지막으로, 이 인프라가 AI 에이전트의 자율성에 미치는 영향을 이야기하겠습니다.
빌드 가드레일(1~2화)은 에이전트가 "잘못된 방향으로 가지 않게" 막아줍니다. Standalone 환경(3화)은 에이전트가 "전체 시스템 없이 부분을 검증할 수 있게" 해줍니다. Acceptance 인프라(본 글)는 에이전트가 "자기 작업의 완결성을 스스로 증명할 수 있게" 해줍니다.

이 네 단계가 flex의 AI 협업 파이프라인입니다. 각 단계가 다음 단계의 전제 조건이 됩니다. 빌드가 올바른 방향을 보장하니까 standalone에서 의미 있는 검증이 되고, standalone에서 검증이 되니까 E2E로 acceptance를 증명할 수 있고, acceptance가 증명되니까 리뷰어가 설계에 집중할 수 있습니다.
1화에서 이야기한 것처럼, 이건 "문서가 아니라 빌드가 지킨다"와 같은 사고방식의 연장입니다. 동작 확인을 사람에게 맡기지 않고, 자동화된 인프라에 맡깁니다.
다음 화 — AI 접근성 등급으로 보는 코드베이스. flex가 내부적으로 사용하는 2축 평가 프레임워크의 상세 구조, L1~L5 등급 정의, 그리고 백엔드 서비스 L4(4.18) vs 프론트엔드 서비스 L3(3.37)의 비교 분석을 다룹니다. (2축 프레임워크의 A축: 자동 acceptance)

