하네스 검증: 최종 결과
결론
자체 테스트 한 줄(②)이 합격률을 가장 크게 올린다. 지시문을 실제로 완수한 비율(합격률)은 ① 그냥 AI 84.9%, ② 자체 테스트 90.5%, ③ 하네스 83.3%, ④ 얇은 지침 81.9%. ②가 ① 대비 +5.6%p로 가장 높다. 하네스 계열(③④)은 오히려 ① 아래로 내려간다. 검증자 루프는 합격률을 못 올리고, 지침을 얇게 간 ④가 가장 낮다.
하네스는 합격률을 못 올리면서 비용만 크다. ③은 합격률이 ①보다 1.6%p 낮은데 시간 2.1배, 출력 토큰 2.7배, 정가 1.6배가 든다. 검증자 루프가 흠을 잡아 고치긴 하지만, 퇴짜 맞은 52런을 복원해 보면 이미 87%가 완수 상태였고 수리가 불합격을 합격으로 바꾼 런은 0건이었다. 반려-수리 루프가 합격률을 끌어올리지 못한다는 뜻이다.
권고: 기본은 ② 그냥 AI + 자체 테스트 한 줄이다. 지시문 끝에 "테스트를 짜서 스스로 확인하고 끝내라" 한 줄을 붙이는 것이 가장 싸게 합격률을 올린다(① 대비 +5.6%p, 드는 비용은 출력 토큰 +16%뿐). 하네스의 크로스 검증 루프는 기본에서 내리되 폐기하지 않는다. 대신 플랜을 짤 때 그 작업이 검증자만 값을 내는 도메인(개인정보·유출 검사, 구조·설계, blast-radius 리팩토링)에 걸리면 크로스 검증을 플랜의 디폴트로 켠다. 사람이 매번 초점을 짚는 게 아니라 도메인이 트리거다. 지침은 얇게 주입하지 않는다. 완료 기준에 이름을 적고 통과 뒤 재오픈을 기록하는 습관은 그대로 가져간다. 상세는 7절.
무결률은 참고 지표로 둔다. 결함이 하나라도 재현되면 탈락인 더 엄격한 기준으로 보면 ① 63.5%, ② 64.9%, ③ 63.5%, ④ 55.4%로 네 방식이 55~65%에 모인다. 합격률과 같은 순서로, ②가 상단이고 ④가 가장 낮다. 그래프는 3절 아래. 결함을 개수로(리뷰어 확인 67개를 같은 자로) 재면 하네스가 방식 전체로는 줄이지만 합격·무결 지표는 못 바꾼다는 측정도 3절에 있다.
1. 어떻게 쟀나
296런 전부 결과물이 보존됐다(8,484파일 1.95GB, 파일 지문 전건 검증). 판정자는 항상 어느 방식·모델이 만든 결과물인지 가린 채(블라인드) 판정했다.
2. 판정 3층
자동 채점(참고), 그리고 왜 안 썼나. 모델 발표에 인용되는 SWE-bench 계열의 표준 채점은 원래 커밋이 가져온 숨은 테스트를 그대로 돌린다. 그 테스트는 원래 개발자가 지은 모듈·함수·문구 이름을 그대로 import·assert 하므로, 같은 동작을 다른 이름으로 구현하면 파일을 못 찾아 불합격이 난다. 실제로 이 벤치에서 자동 채점이 불합격시킨 항목의 78%가 동작이 아니라 이름이 안 맞아서였다(과제 05는 훅 이름이 우연히 같았던 런만 자동 합격, 과제 40 테스트는 지시문에 없는 경로·전역 변수 이름을 요구). 그 결과 자동 채점 합격률은 ~21%로 찍힌다.
그런데 우리 지시문은 이름을 못 박지 않는다. 지시문은 "이런 동작을 하는 걸 만들어라"까지만 말하고 모듈·함수·문구 이름은 만드는 사람이 짓는다. 실제 업무도 그렇게 준다. 즉 이름-고정 자동 채점은 우리 작업 형태에 원천적으로 안 맞고, ~21%라는 숫자는 능력이 아니라 채점 방식이 만든 왜곡이다.
그래서 표준 대신 실작업 커밋을 꺼내 실행 - 판정으로 갔다. 우리 프로덕션 코드베이스에 실제로 머지된 커밋 37개를 커밋 직전 상태로 되돌리고, 원 개발자가 받았던 것과 같은 지시문을 그대로 줬다. 채점은 숨은 테스트가 아니라 판정자(Fable)가 요구사항을 하나씩 직접 실행해 확인하는 방식이다. 이름이 달라도 동작이 맞으면 통과가 되고, 사람이 결과물을 받아들이는 기준과 같아진다. 이 보고서의 합격률·무결률은 전부 이 실행 - 판정에서 나온 것이지 자동 채점이 아니다.
3. 결과
②의 강점은 합격률이다. 자체 테스트 한 줄이 시킨 일을 더 확실히 끝내게 해 합격률이 ① 대비 +5.6%p 오르고, 그 이득을 거의 공짜로(출력 토큰 +16%) 얻는다. 무결률(진한 안쪽)도 같은 방향으로 상단을 유지한다.
모델이 하네스에 반응하는 방식이 다르다. Opus 5 의 합격률은 네 방식에서 89~92%로 거의 흔들리지 않는다(89/92/89/89%, 폭 3%p). 하네스를 얹어도 그대로다. 반면 GPT-5.6-sol 은 76~89%로 크게 출렁이고(폭 14%p), 특히 하네스 계열에서 가장 낮게 떨어진다(③ 78%, ④ 76%). 자체 테스트(②)일 때 89%로 가장 높다. 무거운 운영 지침을 지키게 하면 sol 의 완수가 흔들리는데, Opus 5 는 같은 지침을 성능 손실 없이 흡수한다.
합격률·무결률과는 다른 각도다. 리뷰어가 진짜라고 확인한 결함 67개를, 네 방식이 최종적으로 내놓은 코드에 하나씩 똑같이 대보고 몇 개가 남아 있는지 센 것이다. (앞 절의 결함 사냥은 사냥꾼이 즉흥으로 공격해 방식마다 다른 결함을 잰다. 이건 정해진 67개를 네 방식에 똑같이 대서 공정하게 비교한다.) 232런을 실제로 돌려 확인했고, 다른 작업자가 독립적으로 다시 재확인했다(11/14 일치, 다른 3건은 재확인 쪽이 더 정확해 그대로 채택).
읽는 법. 이 67개 중 79%(53개)는 검증자를 안 쓴 방식(①②)에도 남아 있었다. 검증자를 안 써도 워커가 그 결함을 대부분 똑같이 만든다는 뜻이다. 검증자를 쓴 방식(③④)에서만 그중 일부가 최종물에서 사라졌다. 나머지 21%(14개)는 ①②에도 처음부터 없었다. 검증자 없는 워커가 그건 애초에 안 만든 것이다.
핵심. ①과 ②가 47로 완전히 같다. 자체 테스트 한 줄(②)은 남은 결함을 하나도 못 줄였다(②의 이득은 완수율뿐이다). 검증자를 붙인 ③은 32으로 가장 적게 남긴다. 얇은 지침(④)은 37으로 ③보다 5개 더 남긴다.
품질 점검이 워커에서 검증자로 넘어간다. 검증자 없는 ①은 이 67개 중 47개를 남기고 20개는 애초에 안 만든다(3분의 1은 워커가 스스로 피한다). 자체 테스트를 시킨 ②도 똑같이 47개라, "스스로 테스트하라"는 지시로는 이 결함이 안 준다. 검증자를 붙인 ③은 32개로 준다. 같은 모델·같은 과제라 워커의 기본 성향이 같다고 보면, ③이 ①보다 15개 적게 남긴 것이 검증자가 걸러낸 몫이다(④는 10개, 얇은 지침이 ③보다 덜 잡는다). 역산만이 아니라 직접 확인도 된다: 검증자가 잡아 통과시킨 45건 중 43건이 최종물에서 실제로 사라져 있다. 워커 혼자서는 못 거르는 걸 검증자가 대신 걸러 주는 것이다(다만 워커가 검증자를 믿고 더 대충 만드는지는 이 측정으로는 못 가린다).
이 표가 앞의 결론을 어떻게 바꾸나. 완수율과 무결률(런 하나에 결함이 하나라도 있으면 탈락)은 그대로다. 하네스는 완수가 ① 아래이고, 무결률은 네 방식 비슷하다(결함이 하나라도 남으면 그 런은 탈락이라, 총 개수가 줄어도 "결함 0인 런"은 안 는다). 바뀌는 건 결함 총 개수 하나다. 검증자가 지적하는 종류의 결함은 하네스가 방식 전체로 줄인다(③ 32 vs ① 47). 그래서 "하네스는 결함을 전혀 못 줄인다"는 과장이었고, 정확히는 "이 종류 결함은 줄이지만 그게 합격·무결 점수를 못 바꾸고 비용은 2배"다.
곁다리 발견: 검증자가 통과시켰다고 다 고쳐진 건 아니다. 검증자가 "고쳤다"며 통과시킨 45건 중 2건은 최종 코드에 그 결함이 그대로 남아 있었다(4.4%). 통과가 대체로 못 믿을 정도는 아니지만, 통과가 곧 수리를 뜻하지는 않는다는 실측이다(둘 다 독립 재확인).
같은 과제 일대일(무결 기준). ① 대 ③: ①만 무결 7, ③만 무결 8로 하네스가 그냥 AI 를 못 넘는다. ③ 대 ④: 7 대 2로 얇은 지침(④)이 밀린다. 무결 축에서도 합격률과 같은 방향이다.
"완수"=지시문 요구 충족(합격률), "무결"=완수+결함 0, "자동"=자동 채점 합격(참고, 이름-고정 왜곡). 시간은 과제당 중앙값, 토큰은 출력 합.
| 방식 · 모델 | 런 | 완수 | 무결 | 자동 | 시간 | 출력 토큰 |
|---|---|---|---|---|---|---|
| ① 그냥 AI · Opus 5 (claude-opus-5) | 37개 | 33개 = 89% | 24개 = 65% | 7개 | 16분 | 1.8M |
| ① 그냥 AI · GPT-5.6-sol (gpt-5.6-sol) | 37개 | 29개 = 81% | 23개 = 62% | 8개 | 13분 | 0.9M |
| ② + 자체 테스트 한 줄 · Opus 5 (claude-opus-5) | 37개 | 34개 = 92% | 25개 = 68% | 7개 | 17분 | 1.9M |
| ② + 자체 테스트 한 줄 · GPT-5.6-sol (gpt-5.6-sol) | 37개 | 33개 = 89% | 23개 = 62% | 8개 | 15분 | 1.3M |
| ③ 하네스(검증자 루프) · Opus 5 (claude-opus-5) | 37개 | 32개 = 89% | 24개 = 65% | 7개 | 40분 | 5.2M |
| ③ 하네스(검증자 루프) · GPT-5.6-sol (gpt-5.6-sol) | 37개 | 28개 = 78% | 23개 = 62% | 6개 | 26분 | 2.2M |
| ④ 하네스(검증자 루프)+얇은 지침 · Opus 5 (claude-opus-5) | 37개 | 31개 = 89% | 21개 = 57% | 7개 | 57분 | 6.0M |
| ④ 하네스(검증자 루프)+얇은 지침 · GPT-5.6-sol (gpt-5.6-sol) | 37개 | 28개 = 76% | 20개 = 54% | 8개 | 25분 | 2.2M |
4. 검증자는 뭘 했나
헷갈리기 쉬운 두 가지부터.
Q. 퇴짜 나기 전 상태면 ③④가 더 엉망 아닌가? 아니다. 퇴짜 맞은 52런을 수리 전 상태로 되돌려 다시 판정하니 87%가 이미 합격(완수) 상태였다. 퇴짜는 대부분 "과제를 못 했다"가 아니라 "결함·형식이 있다"는 지적이었다. 그래서 수리 전이라고 더 엉망인 게 아니라, 이미 대체로 합격이었다.
Q. 그럼 퇴짜 놓고 고친 게 의미가 없었나? 반반이다. 검증자는 진짜 흠을 잡아 고쳤다(퇴짜 89건 중 75%가 진짜 결함). 하지만 대표 지표는 두 축 다 안 움직였다. (1) 합격률: 불합격을 합격으로 바꾼 런이 0, 거꾸로 합격을 깬 런이 1이라 순효과 0. (2) 무결률: 무결은 결함 개수가 아니라 런 단위로 "이 런에 결함이 하나라도 있나"로 잰다. 결함은 여러 런에 흩어져 있어서, 고친 뒤에도 그 런에 다른 결함이 남으면 여전히 탈락이다(3개 중 2개 지워도 1개 남으면 탈락). 그래서 "결함 0인 런"의 수가 거의 안 늘고, 방식끼리 재도 결함 보유율이 하네스 22% 대 안 씀 24%로 거의 같다.
하네스 148런이 검증자를 거친 흐름.
수리 전 상태 실측(52런 복원 판정). 퇴짜 시점에 이미 87%가 완수 상태였고, 수리가 불합격→합격으로 바꾼 런 0, 합격→불합격 1(과제 28). 즉 검증 루프의 합격률 기여는 0이다.
검증자가 헛일만 한 건 아니다. 검증자가 낸 퇴짜 89건을 따로 감사하니 75%가 진짜 흠을 짚었고, 워커 수리율은 96%였다. 즉 검증자는 진짜 결함을 잡아 고친다. 하네스 추가 정가는 664달러다. (이 퇴짜 감사는 아래 "사냥"과 다른 방법이라, 두 결함 수를 직접 비교하지 않는다.)
사냥꾼의 독립 공격 기준으로는 방식 간 차이가 없다. 사냥꾼은 자기 공격으로 최종 합격 코드를 뒤진다. 그 결함 보유율은 ① 24% ② 28% ③ 22% ④ 31%로, 검증자를 돌린 ③④나 안 돌린 ①②나 비슷하다. 단 이건 사냥꾼이 노린 종류의 결함이다. 검증자가 지적한 그 결함 종류로 같은 자로 재면 그림이 다르다(3절 "방식별 남은 결함 총수").
실작업 원장(2026년 4~8월)의 대조도 같은 답이다. 퇴짜→수리 후 통과 플랜 253개와 무퇴짜 통과 플랜 783개의 사후 재발률: 확실 등급 0.4% 대 0.3%, git 교차 측정 통제 비교 61.9% 대 55.8%, 통계적으로 구분 불가. 퇴짜 횟수가 늘수록 재발이 준다는 경향도 없다. 검증 루프가 자기 통과를 루프 안에서 스스로 뒤집은 경우는 12건이다.
5. 비용
하네스 계열(③④)은 그냥 계열(①②)보다 시간 2.1배, 출력 토큰 2.7배, 정가 1.6배가 든다. 반면 자체 테스트 한 줄(②)은 ① 대비 출력 토큰 +16%뿐이다. 합격률은 ②가 최고이므로, ②가 가장 싸게 가장 높은 합격률을 낸다. (과제당 시간·토큰은 3절 숫자표에 이미 있다.)
- 74런 시간 합계
- 22.4시간
- 출력 토큰 합계
- 2.69M
- 정가 합계(두 모델)
- 478달러
- 74런 시간 합계
- 27.9시간
- 출력 토큰 합계
- 3.13M
- 정가 합계(두 모델)
- 586달러
- 74런 시간 합계
- 50.9시간
- 출력 토큰 합계
- 7.43M
- 정가 합계(두 모델)
- 859달러
- 74런 시간 합계
- 54.6시간
- 출력 토큰 합계
- 8.24M
- 정가 합계(두 모델)
- 869달러
6. 실작업 체감의 정체
실작업 검증 2,920건의 퇴짜율은 31%, 표본 60건을 사람이 읽으니 78%가 진짜 버그, 그중 90%는 검증자가 직접 실행해 찾은 것이다. 퇴짜의 품질은 실작업과 벤치가 같다(31% 대 벤치 35%).
검증자가 특별히 잘한 건 프로젝트가 아니라 발주 유형이다. "여기 이걸 봐"라고 초점을 짚어 준 세 종류에서 값이 집중됐다. 어느 프로젝트냐보다 발주에 초점이 있었느냐가 변수다.
보안 전수 발주. 개인정보·secret·절대경로 유출을 잡으라고 지정한 발주에서 검증자가 실제 유출 12건을 찾았다. 자동 게이트나 워커 자체 점검이 원천적으로 못 잡는 종류다. 예: 로컬 DB 암호화 키가 stdout 으로 새는 경로, 릴리스 기록의 절대경로·개인정보 노출, 공개 레포에 개인 이메일 노출, 챗봇 응답에 계정 이메일과 내부 절대경로 노출(전부 당시 수리 완료).
전체검수(blast-radius) 발주. "diff 만 보지 말고 호출부·참조·계약 전체를 훑어라"는 리팩토링·중복정리 발주 39건을 사람이 전수로 읽으니 28건이 진짜 검증이었고(오탐 11건), 그중 5건이 SSoT/SoC·No Silent Fallback 같은 구조·설계 결함이었다. 넓게 훑으라는 발주가 설계 결함을 잡는다.
초점을 항목마다 적은 발주. 플랜 항목에 "이 지점을 독립 검사하라"를 사람이 적어 준 검증은 29건 중 17건을 기각(59%)으로, 막연한 "뭐든 반증하라"(30%)의 2배다. 위 개인정보 검출도 이 초점형 발주에서 나왔다.
공통점은 프로젝트나 모델이 아니라 발주의 초점이다. 검증자는 사람이 볼 지점을 좁혀 줄 때 특별히 잘했고, 초점 없이 붙이면 일반 수준(약 30%)으로 돌아간다. 7절 권고가 크로스 검증을 기본에선 내리되, 플랜을 짤 때 이 도메인에 걸리면 디폴트로 켜는 이유다.
7. 그래서 뭘 바꾸나
- 근거
- 합격률은 ②(자체 테스트)가 90.5%로 최고(① 대비 +5.6%p)이고 하네스 계열(③ 83.3%, ④ 81.9%)은 ① 아래인데 비용은 2.1배·2.7배·1.6배다. 검증자 종류 결함은 ③이 ①보다 15개 적게 남기지만, 그게 합격·무결 점수를 못 바꾼다. 그래서 크로스모델 검증 루프는 기본에서 내리고, 워커가 지시문 끝에 "테스트 짜서 스스로 확인하고 끝내라" 한 줄로 닫는다
- 근거
- 발주마다 사람이 검증자에게 볼 지점을 손으로 짚는 방식이 아니다. 플랜을 짤 때 그 작업이 검증자가 유일하게 값을 내는 도메인에 걸리는지로 정한다. 그 도메인은 (1) 개인정보·secret·절대경로 유출 검사, (2) SSoT/SoC·계약 위반 같은 구조·설계, (3) diff 밖 호출부·참조·계약까지 봐야 하는 blast-radius 리팩토링이다. 이 셋에서 검증자는 자동 게이트·워커 자체점검·테스트가 원천적으로 못 잡는 걸 잡았다(6절: 보안 유출 12건, 전체검수 39건 중 28건 진짜, 초점형 발주 퇴짜율 59% 대 막연한 반증 30%). 그래서 플랜이 작업 도메인을 보고 크로스 검증을 자동으로 켜고, 도메인에 안 걸리는 일반 작업은 solo(자체 테스트 + 기계 게이트)로 닫는다. 매번 사람이 판단하는 게 아니라, 그때그때 도메인에 맞는 최적 플랜이 정하게 만드는 것이다
- 근거
- 검증자 퇴짜가 다 진짜는 아니다. 재현이 안 되는 잡음 퇴짜가 16건 섞여 있었다. 예를 들어 결과물은 맞는데 형식상 "DONE" 한 줄이 빠졌다거나, 환경 탓 오류를 코드 탓으로 오귀속했다거나, 지시문에 없는 요구를 갖다 댄 경우다. 이 잡음이 3라운드를 다 쓰고도 기각된 13런 중 9런을 "과잉 반려"로 만들었다(실전이면 이미 완수된 결과물이 미완료로 남는다. 4절 흐름도 그래프). 검증자에게 재현 스크립트·로그를 의무화하고 그걸로 실증되는 결함만 퇴짜로 인정하면, 이 잡음이 자동으로 걸러진다
- 근거
- 이번 실험의 얇은 지침(④, 2KB)은 full 지침(③, 30KB)을 기계적으로 줄인 것이라 실제 지시 일부가 유실됐고, 그 탓에 합격률(81.9 vs 83.3%)도 남은 결함(37 vs 32개)도 ③보다 나빴다(특히 GPT-5.6-sol에서 크게 흔들림, 3절 모델별 차이). 그러니 토큰을 아끼려 무작정 얇게 가는 건 하지 않는다. 다만 방향으로서 지침 정리는 맞다. 오래된 히스토리·중복·중언부언은 걷어내되 실제 요구·계약은 하나도 빠뜨리지 않고, 남긴 지침은 더 명확하게 만든다. 잘라내기(유실)와 정리하기(명확화)는 다르다
8. 원장과 재현
- 실행·채점:
practical/runs-2/(merged-index 296셀, 산출물 1.95GB sha 전건). 완수 판정:runs-2/spec-verdict/. 결함 사냥:spec-verdict/hunt/(공격 스크립트·재현 증거·전사 감사). 수리 전 판정:spec-verdict/round1/. 실작업 재발:retrospective/reopen/. 퇴짜 감사:catch-audit/. 재현:python3 build_plain.py --check. - 판정 신뢰: 완수 판정 독립 대조 19/20, 자동합격→완수불합격 0, 결함 사냥은 재현 증거 전건·블라인드 접근 감사 0건·모든 판정·검증이 독립 검증자 validator-pass 로 닫힘.
- 정가는 엔진 보고값 + 목록가 재도출(
runs-2/usage-rederived.json) + 전사 회전 45런의 셀 비율 환산 합. - 판정에서 빠진 런: 완수 판정불가 5(사유 기록). 이 실험이 잰 과제 유형은 커밋 하나 크기의 단일 작업이다.
부록 · 재현 확인 (반복 회차, 참고)
같은 조건·새 순서(seed 변경)로 한 회차를 더 돌리다 중단 지시로 멈춘 표본이다. 좌표 계정(전건 항등식 검증): 계획 288 · 실행 172 · 채점결함 1(운영자 귀책, 완전 제외) · void 18 · 판정·무결 분모 154. void 중 4(상한 도달 좌표)는 처음 방식 실패로 계상했다가, 실행 계정의 주간 한도 창(08:55 이후 워커·검증자 세션 응답 불가)의 세션 실물 증거로 인프라 void 재분류했다, 어느 쪽으로 세어도 아래 결론은 같다(검증자가 규약 4종 재계산으로 확인). 방식별 분모가 다르고(하네스 계열은 void 가 몰려 작다, void 18 중 17이 하네스 계열) 회차 설계 해상도(5%p)에 못 미치므로, 이 표는 "결론이 이 표본에서도 재현되는가"만 본다, 방식 간 우열 확정에 쓰지 않는다. 판정·사냥은 확정 회차와 같은 판정자·같은 공격 셋·블라인드로 했다.
- 확정 회차(각 74런)
- 47/74 (63.5%)
- 재현 회차
- 33/60 (55.0%)
- 누적
- 80/134 (59.7%)
- 누적 95% 구간
- 51.2~67.6%
- 확정 회차(각 74런)
- 48/74 (64.9%)
- 재현 회차
- 33/55 (60.0%)
- 누적
- 81/129 (62.8%)
- 누적 95% 구간
- 54.2~70.6%
- 확정 회차(각 74런)
- 47/74 (63.5%)
- 재현 회차
- 16/24 (66.7%)
- 누적
- 63/98 (64.3%)
- 누적 95% 구간
- 54.4~73.1%
- 확정 회차(각 74런)
- 41/74 (55.4%)
- 재현 회차
- 9/15 (60.0%)
- 누적
- 50/89 (56.2%)
- 누적 95% 구간
- 45.8~66.0%
합격률(대표 지표) 재현: ① 그냥 AI 84.9→88.1% · ② + 자체 테스트 한 줄 90.5→85.5% · ③ 하네스(검증자 루프) 83.3→91.3% · ④ 하네스(검증자 루프)+얇은 지침 81.9→100.0%. 재현 회차는 표본이 작다(특히 하네스 계열 15~23런, OFF 계열 55~59런의 절반 이하). 그래서 회차 단독 순위는 출렁이지만, 2차와 합친 누적에서는 ②가 합격률 최고(88.4%)를 유지하고, 무결률도 ②③이 ①을 앞서 ④가 최하인 확정 회차 순서가 재현된다. 표본이 불균형이라 이 회차는 헤드라인(균형 잡힌 2차)에 합치지 않고 재현 확인용으로 따로 둔다.