L34 — "다 했다는데, 값이 틀렸다" — 결과를 원본과 맞춰보기 (수정중)
1. "작업은 성공(success)이라고 떴는데요?"
알바생에게 서류 한 뭉치를 주고 이렇게 부탁했다고 하자. "여기 회사 49곳 서류에서 숫자 몇 개씩만 뽑아서, 이 엑셀 표에 회사별로 정리해 주세요."
잠시 뒤 알바생이 말한다. "다 했어요!" 표에도 숫자가 쭉 채워져 있다. 그럼 그대로 믿고 고객에게 넘겨도 될까?
실제로 이런 일이 있었다. 사람 대신 프로그램이 그 일을 했고, 끝난 뒤 기록을 보니 상태가 성공(success), 화면엔 초록불. 하마터면 그대로 넘길 뻔했다. 그런데 결과를 하나씩 열어보니 성격이 다른 문제가 세 개 섞여 있었다.
- ① 아예 빈 칸이었다. 49곳 중 19곳은 칸이 비어 있었다. 여러 회사를 한꺼번에 너무 빨리 읽는 바람에, Google이 "잠깐, 너무 자주 부르네요" 하고 잠깐 막았고(이걸
429라고 한다), 그 회사들은 값이 안 들어갔다. 그런데도 작업은 "성공"이라고 떴다. 3분의 1이 비었는데도. - ② 숫자를 잘못 읽었다. 어느 회사 값이
9,000으로 적혔는데, 맞는 값은69,000이었다. 서류 페이지가 넘어가는 자리에서, 일부만의 합계(9,000)를 전체 합계로 착각한 것이다. 프로그램은 이걸 "잘 뽑았다"고 여겼다. - ③ 달라 보이지만 사실 맞는 거였다. "서류에서 읽은 값"과 "표에 원래 있던 값"이 다른 회사가 여럿이었다. 그런데 대부분은 틀린 게 아니라 그럴 만한 차이였다 — 공식 서류가 회사가 예전에 직접 적어둔 것보다 최신이라 다른 것뿐이다.
오늘의 핵심은 딱 한 문장이다: "작업이 성공으로 끝난 것"과 "나온 값이 맞는 것"은 전혀 다른 얘기다. "성공" 표시를 "다 됐다"는 뜻으로 믿으면 안 된다. 특히 여러 개를 한꺼번에 처리하거나, 사람 대신 프로그램·AI가 숫자를 읽어내는 일일수록 그렇다.
2. 왜 한 번 쓱 봐서는 안 잡히나
방금 세 문제를 다시 보자. 각각 "어디를 봐야" 잡히는지가 다르다.
- ①(빈 칸)은 값을 하나씩 열어볼 것도 없다. 표를 멀리서 쓱 봐도 "왜 이렇게 빈 데가 많지?" 하고 눈에 띈다.
- ②(9,000/69,000)는 그렇게 봐선 절대 못 잡는다. 표엔 숫자가 멀쩡히 적혀 있으니까. 원본 서류를 다시 펴서 그 페이지를 읽어야 틀린 걸 안다.
- ③(그럴 만한 차이)은 "값이 다르네?" 까지는 보이지만, 그게 틀린 건지 아닌지는 원본을 봐야 판가름 난다.
그래서 한 눈금으로 다 재려 하면 꼭 놓치거나, 멀쩡한 걸 틀렸다고 오해한다. 확인을 세 단계로 나누는 이유가 이것이다. 순서는 빠르고 쉬운 것 → 느리고 품 드는 것이고, 그 단계에서만 잡히는 문제가 따로 있다.
그림처럼 아래로 갈수록 손이 더 가고, 대신 더 깊은 문제를 잡는다.
3. 1단계 — 결과 목록만 멀리서 훑기 (아직 값은 안 열어본다)
가장 빠른 단계. 원본이랑 대조하기 전에, 작업이 남긴 결과 목록만 놓고 훑는다.
- 성공이 몇 건, 실패·건너뜀이 몇 건인지, 그리고 그 이유를 본다. 실패가 우르르 많으면 "뭔가 빠졌다"는 신호다(너무 자주 불러서 막혔거나, 로그인이 풀렸거나, 원본이 없거나).
- 이상한 패턴이 없나 본다. 예를 들어 한 칸(열)이 전부 똑같은 값이면 "한 값을 그대로 복사한 거 아냐?" 하고 의심할 수 있다.
이 단계는 "19곳이 막혀서 비었다" 같은 걸 값 하나 안 열어보고 싸게 잡아낸다. 단, 여기서 든 의심은 아직 "확정"이 아니라 "3단계에서 먼저 확인해 볼 후보" 정도로만 둔다.
4. 2단계 — "적었다는 값"과 "실제로 적힌 값"이 같은가
두 번째 단계는 값을 옮겨 적는 마지막 손길을 의심한다. 프로그램이 속으로 뽑아낸 값과, 표에 실제로 적힌 값을 나란히 놓고 전부 맞춰본다. 속으론 69,000을 잘 뽑아놓고도, 엉뚱한 칸에 적거나 적다가 흘렸을 수 있기 때문이다.
여기서 초보가 꼭 걸리는 함정이 하나 있다: 일부러 바꿔 적은 것까지 "틀렸다"고 세는 것.
- 값이 없을 때 빈 칸 대신
-를 적기로 정했다면, "값 없음"과-는 같은 뜻이다. - 표에서 음수를 넣으면
(1,234)처럼 괄호로 보일 수 있다. 이건-1234와 같은 값이다.
이런 걸 글자 그대로 비교하면 멀쩡한 값이 죄다 "다름"으로 뜬다. 그래서 표기를 먼저 같은 모양으로 맞춰놓고 비교한다(콤마·괄호·빈칸·- 같은 걸 정리한 뒤). 이렇게 하고도 남는 차이는 "옮겨 적다 생긴 실수"이니, 이 단계의 목표는 차이 0이다.
5. 3단계 — 몇 개를 골라 원본과 맞춰보기 (제일 중요)
1·2단계를 다 통과해도 값 자체가 틀릴 수 있다. 앞의 ②번(9,000/69,000)이 딱 그랬다 — 상태도 성공, 뽑은 값과 적힌 값도 똑같았다. 그런데 애초에 원본을 잘못 읽은 것이다. 이건 원본으로 돌아가 다시 읽어봐야 잡힌다.
전부 다시 읽으면 품이 너무 드니, 몇 개만 골라서 본다. 대신 아무거나 찍지 말고, 정한 기준으로 고른다.
이 단계에서 지킬 다섯 가지:
- 크기만 보지 말고 부호(+/−)까지 보라. 크기는 맞는데 플러스·마이너스만 뒤집힌 실수가 은근히 많다.
- 파일 이름을 믿지 마라. 이름에 적힌 날짜·제목이 실제 내용과 다를 수 있다. 항상 안에 든 내용으로 판단한다.
- 한쪽만 보지 마라. 두 자료가 당연히 다를 수도 있다(③번의 최신본 차이). 차이가 큰 것만 후보로 좁힌 뒤, 원본으로 어느 쪽이 맞는지 정한다.
- 고르는 방식을 정해두라. 1·2단계에서 의심스러웠던 건 전부 + 일정 간격으로 뽑은 정상 몇 개. 다음에 똑같이 다시 해볼 수 있어야 한다("의심 3개 + 정상 2개" 식으로).
- 페이지가 넘어가는 자리, 이어지는 표를 특히 조심하라 — 일부 합계를 전체 합계로 잘못 읽기 쉽다(전체 합이 맞는지 더해서 검산).
마지막엔 어디까지 봤는지 꼭 밝힌다: "1·2단계는 전부 봤고, 3단계는 몇 개(의심 K + 정상 L)만 봤다." 몇 개만 보고 "전부 맞다"고 말하지 않기 위해서다.
6. 매번 손으로 해야 하나? — 대신 해주는 에이전트(output-verifier)
위 세 단계를 기능마다 손으로 반복하긴 번거롭다. 그래서 이 과정을 대신 해주는 에이전트(Agent)를 하나 만들어 뒀다. 에이전트는 Claude Code 에서 한 가지 일만 맡아 자기 창에서 처리하는 작은 프로그램이다(L12). 이름은 output-verifier 이고, 우리 공용 템플릿(standarda-template)에 들어 있어 기존 프로젝트에도 /update-from-template 로 가져올 수 있다.
쓰는 법은 간단하다.
- 알려줄 것 = 확인할 작업 하나(그 작업 이름표, 또는 "가장 최근 ○○ 작업"). 그게 전부다.
- 나머지는 에이전트가 프로젝트 코드를 읽어 스스로 알아낸다 — 결과가 어디 저장되는지, 값이 어느 표·칸에 적히는지, 원본이 어디 있는지.
- 그 작업이 로컬(내 컴퓨터)에 기록이 없으면 Production 서버에서 돌았을 수 있으니 거기까지 찾아본다.
- 읽기만 한다. 찾은 것만 알려주고, 값도 코드도 건드리지 않는다. 다시 돌릴지 고칠지는 사람이 정한다.
이름이 비슷한 spec-verifier(L03)와 헷갈리지 말 것. 둘 다 "verifier(확인 담당)"지만 보는 게 정반대다.
spec-verifier |
output-verifier |
|
|---|---|---|
| 묻는 것 | 코드가 계획대로 짜였나 | 이번에 나온 값이 실제로 맞나 |
| 보는 대상 | 코드 ↔ 계획 문서 | 표에 적힌 값 ↔ 원본 |
| 시점 | 코드 합치기 전 | 작업 돌린 뒤 |
계획대로 짠 코드가 잘 돌아가도 나온 값은 틀릴 수 있다(②번). 그 틈을 메우는 게 output-verifier 다.
7. 왜 "계산은 공용 창고에, 판단은 에이전트에게" 나눴나
마지막으로, 이걸 여러 프로젝트가 두고두고 쓰게 만들 때의 생각 하나. 두 갈래로 쪼갰다.
- 답이 딱 정해지는 계산은 팀 공용 창고(standarda-core)에 넣었다. "성공·실패 개수 세기, 표기 맞춰 비교하기, 몇 개 골라내기" 처럼 값만 넣으면 답이 나오는 것들이라, 어느 프로젝트나 똑같이 가져다 쓴다.
- 상황을 봐야 하는 판단은 에이전트에게 맡겼다(
output-verifier). "무엇이 작업이고, 결과·원본이 어디 있는지"는 프로젝트마다 다르고, 코드를 읽고 판단해야 하기 때문이다. - 그 프로젝트에만 있는 세부(표가 어떻게 생겼는지 같은 것)는 부르는 쪽에 남긴다.
기준은 간단하다: 답이 정해지면 공용 창고, 상황 판단이 필요하면 에이전트, 그 프로젝트만의 것이면 부르는 쪽. (L14 에서 여기저기 흩어진 같은 코드를 공용 창고로 모은 것과 같은 이야기다.)
오늘 정리 + 다음
- 정리: "작업 성공 ≠ 값이 맞음." 자동으로 뽑아 정리한 결과는 세 단계로 확인한다 — ① 결과 목록만 멀리서 훑기(빠짐·반복 실수) → ② 적었다는 값과 실제 적힌 값 맞춰보기(잘못 옮겨적음, 일부러 바꾼 표기는 먼저 맞춰놓고) → ③ 몇 개를 원본과 대조(값 자체가 맞나 — 여기서만 잡히는 게 제일 위험). 크기만 말고 부호까지, 파일 이름 말고 내용, 한쪽만 말고 원본으로 확정, 고를 땐 정한 기준으로. 번거로우면
output-verifier에이전트에게 맡긴다. - 흔한 함정: (1) 초록불을 "다 됐다"로 착각 — 한꺼번에 많이 처리하다 막히면, 성공 표시가 떠도 3분의 1이 비어 있을 수 있다. (2) 일부러 바꿔 적은 걸 "틀렸다"고 세기 —
없음↔-, 괄호↔음수 같은 표기 차이는 먼저 맞춰놓고 비교한다. (3) 몇 개만 보고 "전부 맞다" — 어디까지 봤는지 꼭 밝힌다. - 다음 시간: 교훈 전파(L32) — 한 프로젝트에서 겪은 이 일이 어떻게 팀 전체의 공용 자산(standarda-core·standarda-template)으로 퍼졌는지가 그 이야기의 실제 사례다.
- 자습 권장: 방법론 원문은 팀 wiki 의
lessons/general/verify-run-output-3-layer.md.output-verifier정의 원문은 standarda-template 의.claude/agents/output-verifier.md. 내 프로젝트에 자동으로 값을 뽑아 정리하는 기능이 있으면, 최근 작업 하나를 골라output-verifier를 한번 돌려보자.