포스트

AI Agent Complexity Ratchet — 90% 테스트 커버리지가 AI 코딩의 새 표준이 된 이유

목차

  1. 개요
  2. 소프트웨어의 패러다임 전환
  3. 에이전트 복잡성 래칫
  4. 대부분의 바이브코딩 프로젝트가 죽는 이유
  5. 제도적 기억으로서의 테스트
  6. 관측 가능한 모든 것은 테스트 가능하다
  7. 왜 하필 90%인가
  8. 개념 증명과 새로운 복잡성 천장
  9. 결론

개요

지난 한 해 동안 AI와 함께 코딩한 한 개발자가 단순한 프롬프트가 아닌 실제 소프트웨어 두 개를 만들었다. GStack과 GBrain이라는 오픈소스 프로젝트 두 개를 합쳐 약 97만 라인의 코드와 665개의 테스트 파일을 보유한다. 대부분의 코드는 동시에 15개의 Conductor 세션을 돌리며 Claude Code와 Codex가 작성했다. 지난주에는 72시간 동안 14개의 PR을 머지했고, 거의 2만 9천 라인의 새 코드를 추가했다. 그리고 각 릴리스는 이전 릴리스보다 더 잘 테스트되어 있었다.

빠르게 출시하면 품질이 떨어지고, 천천히 만들면 출시가 늦어진다는 50년간의 통념을 이 사례는 깨뜨린다. 저자는 그 잠금 해제 열쇠를 90% 테스트 커버리지로 지목한다. 지난 50년 동안 90% 커버리지는 인간의 의지력으로 감당하기에 너무 비쌌지만, AI 에이전트가 그 비용을 사실상 0으로 만들었다. 그 결과가 바로 그가 말하는 복잡성 래칫(complexity ratchet), 즉 시스템이 오직 한 방향으로만 더 좋아질 수 있는 메커니즘이다.

소프트웨어의 패러다임 전환

예전 소프트웨어는 부서지기 쉬웠다

50년 동안 소프트웨어 엔지니어링이라는 학문 전체는 단 하나의 아이디어를 중심으로 조직되어 있었다. 오류를 예방한다, 왜냐하면 오류는 재앙이기 때문이다.

코드는 처음부터 옳아야 했다. 엣지 케이스를 하나라도 놓치면 프로덕션이 멈췄고, 잘못된 DB 마이그레이션을 배포하면 고객 데이터가 사라졌다. 미묘하게 동작하는 함수를 짜놓고 그 의도를 아는 단 한 명이 퇴사하면 아무도 그 코드가 왜 동작하는지 모르게 됐다. 전체 시스템이 인간이 신중하기를 전제로 했지만, 인간은 신중하지 못하다. 그래서 코드 리뷰, 스테이징 환경, QA 팀, 릴리스 트레인 같은 정교한 프로세스가 만들어졌다.

이 방식은 어느 정도 동작했다. 그러나 느렸고, 어떤 소프트웨어 시스템의 복잡성도 한 팀이 동시에 머릿속에 담을 수 있는 양이라는 단단한 천장에 묶여 있었다.

지금 소프트웨어는 말랑말랑하다

여기서 말랑말랑하다는 말은 허술하다는 뜻이 아니라, 예전엔 불가능했던 방식으로 회복력이 있다는 뜻이다.

AI 코딩 에이전트가 이제 코드를 읽고, 컨텍스트를 이해하고, 오류를 진단하고, 수정 패치를 작성할 수 있다. 완벽하지는 않지만 소프트웨어의 오류 모델 자체가 바뀔 만큼은 잘한다.

마이그레이션이 깨졌다면 에이전트가 오류 메시지를 읽고 45개 버전에 걸친 DB 스키마 이력을 이해한 뒤 수정과 테스트를 작성한다. 파일 동기화가 백만 개의 심볼릭 링크 때문에 멈췄다면 에이전트가 파서 타임아웃을 진단하고 30초로 묶은 뒤 테스트와 함께 출시한다. 추출 파이프라인에 귀속 버그가 있다면 크로스 모델 평가가 이를 잡아내고, 프롬프트가 반복 개선되며, DB 계층에서 강제 적용 로직이 추가된다.

코드 레벨의 대부분 오류(로직 버그, 파싱 실패, 깨진 엣지 케이스)에 대해 에이전트가 이제 다음 턴에 진단하고 수정한다. 재앙으로 남는 오류는 상태를 파괴하는 것들이다. 프로덕션 데이터에 대한 잘못된 마이그레이션, 탐지되기 전에 익스플로잇된 보안 구멍, 한 번 새면 되돌릴 수 없는 프라이버시 누수 같은 것들이다. 래칫은 이 영역에도 도움이 되지만, 진짜 핵심은 코드베이스의 압도적 다수의 오류가 이제 고칠 수 있는 종류가 되었다는 점이다.

에이전트 복잡성 래칫

래칫은 한 방향으로만 움직임을 허용하는 메커니즘이다. 소켓 렌치가 볼트를 한 방향으로만 돌리고 반대로는 못 돌게 만드는 것처럼, AI 에이전트로 만드는 소프트웨어에서도 같은 비유가 통한다.

래칫의 세 가지 구성 요소

AI 에이전트와의 코딩 세션은 코드베이스에 다음 세 가지를 더한다.

구성 요소역할
테스트무엇이 옳은지를 인코딩한 자동 검증. 코드가 바뀔 때마다 돌고, 깨지면 큰 소리로 실패한다.
문서왜 그런 결정을 내렸는지의 기록. 코드가 무엇을 하는지가 아니라 그 뒤의 추론과 트레이드오프를 담는다.
평가 결과점수가 매겨진 품질 임계값. 다음 버전이 더 나은지 못한지를 객관적으로 판단한다.

에이전트가 다음 번에 해당 코드베이스에서 작업할 때 이 세 가지가 모두 컨텍스트 윈도우에 로드된다. 테스트 스위트 아래로는 회귀할 수 없고, 컨텍스트에 박혀 있는 문서를 무시할 수 없으며, 기록된 평가 점수보다 낮은 품질로 출시할 수 없다. 품질의 바닥이 매 턴 위로 올라간다. 이것이 래칫이다.

GBrain 사례 — Holder Confusion 잡기

GBrain은 AI 에이전트에 장기 기억을 부여하기 위해 사람의 노트, 회의, 대화, 리서치를 저장·인덱싱·검색하는 지식 시스템이다. 그 중 한 기능이 인식론적 추출(epistemological extraction)인데, 수천 페이지를 읽고 누가 어떤 신뢰도로 무엇을 믿는지를 시간에 따라 뽑아낸다.

첫 추출에서 100,720개의 주장이 산출됐다. GPT-5.5와 Claude가 독립적으로 점수를 매기는 크로스 모델 평가의 종합 점수는 10점 만점에 6.8이었다. 가장 큰 문제는 저자가 “holder confusion”이라 부르는 것이었다. 예를 들어 “AI가 2027년까지 소프트웨어 엔지니어의 80%를 대체할 것”이라는 주장을 누가 믿는지를 시스템이 35%의 비율로 잘못 귀속시켰다.

대응은 평가 결과 문서화, 6가지 실패 모드 식별, 6가지를 모두 다루는 v2 프롬프트, DB 계층에서의 가중치 반올림 강제, 그리고 17개의 테스트로 계약을 잠그는 것이었다. 앞으로 어떤 버전의 추출 기능도 이 17개의 테스트를 통과하지 못하면 출시할 수 없다. 가중치 반올림이 왜 중요한지, holder confusion이 무엇인지 아무도 외울 필요가 없다. 테스트가 기억한다.

대부분의 바이브코딩 프로젝트가 죽는 이유

바이브코딩은 Andrej Karpathy의 용어로, 원하는 것을 자연어로 묘사하면 모델이 코드를 만들어내는 코딩 방식이다. 강력하지만 테스트를 건너뛴 프로젝트는 중간 정도의 복잡성(수천 라인, 몇 개의 상호작용하는 기능)에 도달하면 무너지기 시작한다.

이런 프로젝트는 래칫을 건너뛴다. 테스트도, 문서도, 평가도 없다. 에이전트가 복잡성을 추가하지만 회귀를 막을 장치가 없다. 모든 새 기능은 이전 기능을 깰 가능성을 가지고, 테스트가 없으니 사용자가 보고하기 전까지 알 수 없다. v0.5쯤 되면 코드베이스는 어떤 변경이든 예상치 못한 무언가를 깨뜨리는 유령의 집이 된다. 그러고 나서 개발자는 “AI 코딩은 동작하지 않는다”는 블로그 글을 쓴다.

AI 코딩은 잘 동작한다. 그들은 단지 래칫을 만들지 않았을 뿐이다.

테스트가 없으면 개선은 시끄러운(noisy) 프로세스가 된다. 좋은 변경과 나쁜 변경이 똑같이 보이지 않는다. 밀도 높은 테스트 스위트가 있으면 인코딩한 행동들에 대해서는 품질이 오직 위로만 갈 수 있는 래칫이 생긴다.

제도적 기억으로서의 테스트

전통적인 소프트웨어 회사에서 제도적 기억(institutional memory)은 사람 안에 있다. 캐싱 레이어가 왜 존재하는지 아는 시니어 엔지니어, 거의 DB를 망가뜨릴 뻔한 마이그레이션을 기억하는 아키텍트, 청구 시스템의 이상한 엣지 케이스를 설명할 수 있는 테크리드 같은 식이다.

사람은 떠난다. 은퇴하고, 스카우트 당하고, 번아웃에 빠진다. 모든 소프트웨어 회사는 결정적인 파일을 열었더니 “이거 절대 바꾸지 마세요 — Dave에게 물어보세요”라는 주석이 적혀 있는데 Dave가 3년 전에 떠난 상황을 경험해 봤다.

에이전트의 컨텍스트 윈도우는 퇴사하지 않는다. 스카우트 당하지도, 잊지도 않는다. “가중치 반올림은 0.05 단위를 사용해야 한다”가 테스트로 인코딩되고 “크로스 모달 평가에서 거짓 정밀도가 신뢰도 점수의 신뢰성을 떨어뜨렸기 때문”이 문서에 적혀 있다면, 그 지식은 영속적이다. 1인 프로젝트라면 테스트가 곧 유일한 제도적 기억이다.

관측 가능한 모든 것은 테스트 가능하다

래칫은 전통적인 코드에만 동작하는 것이 아니다. 컴퓨터가 관측할 수 있는 모든 것에 적용된다.

현대 시스템의 각 계층을 떠올려 보자. OS는 프로세스 트리, 파일 시스템 상태, 네트워크 소켓, 크론 스케줄을 준다. 터미널은 키 입력, 출력 라인, 인터랙티브 프롬프트를 준다. 브라우저는 렌더링된 페이지, 버튼 상태, 내비게이션 이벤트를 준다. API는 파싱·검증 가능한 구조화된 응답을 준다. 그리고 AI 에이전트는 관측 가능한 행동을 준다. 무엇을 말하고, 어떤 도구를 어떤 순서로 호출하고, 행동 전에 묻는지 같은 것들이다.

이 모든 것을 하네스(harness)할 수 있다. 하네스할 수 있으면 관측할 수 있고, 관측할 수 있으면 단언(assert)할 수 있으며, 단언할 수 있으면 래칫할 수 있다.

TTY 레벨 행동 계약 테스트

GStack은 저자의 오픈소스 코딩 에이전트 프레임워크다. 9만 3천 깃허브 스타, 70만 1천 라인의 코드, 46개의 스킬을 보유한다. 핵심 기능 중 하나는 인터랙티브 플랜 리뷰다. 아키텍처를 리뷰해 달라고 하면 에이전트가 플랜을 섹션별로 훑으며 질문을 던지고, 엣지 케이스를 캐내고, 가정에 도전한다.

문제는 Claude Code가 가끔 인터랙티브 부분을 통째로 건너뛰는 데 있었다. 플랜 파일을 읽고 모든 발견을 한 번에 쏟아낸 뒤 사용자에게 단 하나의 질문도 하지 않고 종료하는 경우가 있었다. 이런 행동을 어떻게 테스트할 수 있을까. “AI가 대화를 했는가”는 단위 테스트의 대상이 아니다.

저자는 Bun의 TTY 기능을 이용해 PR #1354에서 테스트 하네스를 만들었다. 이 하네스는 가상 터미널 안에 Claude Code를 띄우고, 특정 저장소 시나리오를 주고, 리뷰 스킬을 트리거한 뒤 터미널 출력을 실시간으로 지켜본다. 에이전트가 종료 전에 인터랙티브 질문을 던지는지를 테스트가 관측한다. 그냥 발견 사항을 뱉고 종료하면 테스트가 실패한다.

이는 코드를 테스트하는 것이 아니라 AI 에이전트가 행동 계약을 따르는지를 TTY 레벨에서 실제 동작을 보면서 테스트하는 것이다.

대응은 세 계층이었다. 스킬 지시문 안의 STOP 게이트로 “다음 섹션으로 넘어가기 전 반드시 사용자에게 질문해야 한다”는 규칙과 모델이 합리화로 회피할 수 없도록 실패 모드를 명시한 반(反) 합리화 조항을 박았다. 지름길 차단 조항으로 “플랜 파일은 인터랙티브 리뷰의 결과물이지 그 대체물이 아니다”라는 한 문장을 추가했다. 그리고 게이트 티어의 바닥 테스트로 통제된 시나리오에서 Claude Code를 띄워 최소 한 번의 인터랙티브 질문이 없으면 실패하는 TTY 하네스 테스트를 두었다.

엔드 투 엔드 플러그인 통합 테스트

PR #880은 새 OpenClaw 플러그인을 출시했다. 테스트는 단순히 컴파일되는지를 보지 않는다. 소스에서 플러그인을 빌드하고, 격리된 프로파일로 실제 OpenClaw 인스턴스를 띄우고, CLI를 통해 플러그인을 설치하고, plugins inspect를 실행해 런타임이 로드했는지 확인하고, config 슬롯을 설정한 뒤 검증하고, plugins doctor로 진단이 0건임을 확인한다. 두 개의 별도 프로그램을 가로지르는 완전한 엔드 투 엔드 왕복이다.

359 라인의 테스트 코드. 사람이라면 셋업이 너무 귀찮아 거의 손으로 쓰지 않을 종류의 테스트다. Claude는 약 5분 만에 작성했다. 노력의 벽이 실시간으로 사라지는 모습이 바로 이것이다.

이 원리는 일반화된다. OS 레벨에서 마이그레이션이 올바른 테이블을 만들었는지, 크론 잡이 발동했는지, 프로세스가 살아 있는지를 테스트할 수 있다. 브라우저 레벨에서 페이지가 렌더링됐는지, 에이전트가 폼을 올바르게 채웠는지를 테스트할 수 있다. API 레벨에서 모델이 올바른 스키마의 JSON을 반환했는지를 테스트할 수 있다. 행동 레벨에서 에이전트가 프로토콜을 따랐는지, 삭제 전에 물었는지, 멈추라고 했을 때 멈췄는지를 테스트할 수 있다.

왜 하필 90%인가

Capers Jones의 결함 제거 효율 곡선

Capers Jones는 10,000개 이상의 소프트웨어 프로젝트를 연구하면서 결함 제거 효율(Defect Removal Efficiency, DRE)을 측정했다. 사용자에게 도달하기 전에 잡힌 버그의 비율이다. 그의 Applied Software Measurement 데이터는 비선형 곡선을 보여준다.

커버리지 구간평균 DRE
70% 미만65 ~ 75% 수준
85 ~ 95%92 ~ 97% 수준

관계는 선형이 아니다. 약 85%에서 결함 누출이 급격히 떨어지는 무릎(knee)이 있다.

DO-178C와 Six Sigma의 교훈

항공 산업은 수십 년 전에 이미 이 사실을 알아냈다. FAA의 비행 임계 소프트웨어 표준 DO-178C는 Level A 시스템(버그가 곧 추락을 의미하는 시스템)에 대해 MC/DC(Modified Condition/Decision Coverage)를 요구한다. 브랜치 커버리지만으로는 결함의 10 ~ 20%를 놓치지만 MC/DC는 99% 이상의 DRE에 도달한다. 관료가 종이를 좋아해서 의무화한 게 아니라, 특정 커버리지 임계 아래에서는 사람을 죽일 수 있는 비율로 결함이 빠져나간다는 데이터가 있었기 때문이다.

신뢰성 공학의 평행 사례는 깔끔하다. 공장은 Six Sigma라는 시스템으로 품질을 측정한다. 100만 단위당 결함 수를 세고 그것을 시그마 레벨로 표현한다.

시그마 레벨100만 단위당 결함 수
3-sigma약 67,000개
4-sigma약 6,200개
5-sigma약 233개

4-sigma에서 5-sigma로의 점프는 점진적 개선이 아니라 상전이(phase change)다. 테스트 커버리지도 같은 곡선을 따른다. 70%에서 90%로 가는 것은 30% 더 좋아지는 게 아니라 결함 누출이 한 자릿수 단위로 줄어드는 일이다.

AI 에이전트가 깬 노력의 벽

Mockus, Nagappan, Dinh-Trong의 Windows Vista 연구는 커버리지가 출시 후 결함과 음의 상관을 가지지만 90% 이상에 도달하기 위한 노력은 가파르게 증가한다는 사실을 보였다. 커버리지의 마지막 20%는 처음 70%보다 훨씬 더 많은 작업을 요구한다. 이것이 대부분의 팀이 70 ~ 80%에서 멈추고 “그 정도면 충분하다”고 부르는 이유다.

그러나 한 가지가 바뀌었다. AI 코딩 에이전트는 노력을 경험하지 않는다.

에이전트는 열네 번째 엣지 케이스 테스트를 쓰면서 지루해하지 않는다. 금요일 오후 5시에 모서리를 자르지 않는다. 지저분한 통합 테스트를 보면서 “나중에 다시 와야지”라고 생각하지 않는다. 사람을 70%에서 멈춰 세웠던 노력 곡선이 에이전트에는 적용되지 않는다.

이것이 진짜 잠금 해제다. AI가 코드를 더 빠르게 쓰게 해 준다는 사실은 많은 사람이 이미 눈치챘다. 중요한 점은 AI가 예전에는 유지하기에 너무 비쌌던 검증 수준을 가능하게 해 준다는 것이다. 90% 임계는 데이터가 마법적이라고 말하는 수치였지만 인간의 의지력으로 도달하기엔 너무 비쌌다. 이제는 공짜다.

핵심은 라인 커버리지를 허영 지표로 보는 게 아니다. 래칫의 본질은 행동 계약을 인코딩한 테스트들이다. holder confusion 테스트, 가중치 반올림 테스트, 인터랙티브 리뷰 게이트 같은 각각의 테스트가 학습한 교훈 하나씩을 잠가 둔다. 커버리지는 시스템 행동 중 얼마나 많은 부분이 계약 아래 있는지를 알려주는 프록시다. 90%에서는 거의 모든 행동 변화가 테스트 신호를 발동시킨다.

개념 증명과 새로운 복잡성 천장

두 프로젝트 모두 저자 혼자서 시작했지만 더는 1인 프로젝트가 아니다. GStack은 37명의 컨트리뷰터를 보유하며, v1.30은 단일 릴리스에 21개의 커뮤니티 PR을 통합했다. GBrain은 25명의 컨트리뷰터를 보유하며, v0.31.1.1은 22개의 커뮤니티 수정을 하나의 PR에 담았다. 래칫이 이를 안전하게 만든다. 외부 PR이 기존 테스트 스위트를 통과해야 한다는 것 외에 새 컨트리뷰터가 전체 시스템을 이해할 필요가 없다.

지난주 GBrain 릴리스는 다음과 같다.

버전변경 사항
v0.31.0실시간 메모리용 facts 테이블, 단기 기억을 장기 지식으로 승격시키는 dream consolidation 단계
v0.31.1사용자 실제 브레인이 아닌 빈 로컬 DB로 조용히 라우팅되던 CLI 명령 25개 수정
v0.31.1.122개의 커뮤니티 보고 수정을 단일 PR로 통합
v0.31.2심볼릭 링크가 많은 대형 저장소에서 영원히 멈추던 코드 동기화에 30초 타임아웃 추가

각 릴리스는 이전보다 많은 테스트와 함께 출시됐다. 에이전트가 코드와 나란히 테스트를 쓰기 때문에 커버리지가 슬립하지 않는다.

소프트웨어의 복잡성 천장이 한층 더 높아졌다. 한 팀이 머릿속에 담을 수 있는 양으로 묶여 있던 이 천장은 이제 한 명의 사람 더하기 전체 코드베이스, 스키마 이력, 테스트 스위트, 문서를 컨텍스트에 로드할 수 있는 에이전트들의 능력으로 묶인다. 컨텍스트 윈도우가 커지고 모델의 코드 추론이 좋아질수록 이 숫자는 계속 자란다.

결론

소프트웨어가 부서지기 쉬운 매체에서 회복력 있는 매체로 바뀌었다. 대부분의 코드 레벨 오류를 에이전트가 다음 턴에 잡아낼 수 있게 되면서, 진짜로 재앙적인 오류는 상태를 파괴하는 종류에 국한된다. 그리고 그 잠금 해제를 가능케 하는 메커니즘이 바로 래칫이다.

테스트는 무엇이 옳은지를 인코딩하고, 문서는 결정의 이유를 보존하며, 평가는 품질 임계를 고정한다. 이 세 가지가 합쳐져 한 방향으로만 움직이는 복잡성 래칫을 만든다. 관측 가능한 모든 계층(OS, 터미널, 브라우저, API, 에이전트의 행동)이 테스트의 대상이 되며, TTY 안에서 에이전트의 대화 패턴을 검증하는 것조차 가능하다.

90% 커버리지는 수십 년간 항공·의료 같은 영역에만 허락된 사치였지만, 노력을 느끼지 않는 AI 에이전트가 그 벽을 무너뜨렸다. 이제 질문은 90%를 감당할 수 있느냐가 아니라 감당하지 않을 수 있느냐다. 에이전트, 취향, 그리고 오직 위로만 가는 테스트 스위트를 채택하지 않는 모든 소프트웨어 회사는 이미 그것을 채택한 한 명의 개인보다 느리고 더 낮은 품질로 출시하고 있다.