제 자동매매 봇에는 자동 점검표가 있습니다. 부품을 하나하나 눌러 보고 이상이 없으면 초록불을 켜는 장치입니다.
지난주 그 점검표를 돌렸더니 145개가 전부 통과, 실패는 0개였습니다. 여러분이 보험 점검이나 연말정산 화면에서 받아 보시는 「이상 없음」과 같은 종류의 답입니다.
그런데 같은 날 알게 된 사실이 있습니다. 안전장치를 아예 꺼 놓고 내보내도, 그 145개는 똑같이 전부 초록불이 켜졌습니다.

145개 통과라는 성적표는 무엇을 증명할까요?
먼저 이 점검표가 뭔지부터 풀어야겠네요.
프로그램은 부품 수백 개로 이뤄져 있습니다. 그 부품이 제대로 도는지 사람이 매번 손으로 눌러 볼 수는 없거든요. 그래서 “이 부품에 이 값을 넣으면 이 답이 나와야 한다”를 미리 적어 두고, 컴퓨터가 대신 눌러 보게 합니다.
그게 145개 있었고, 전부 통과했습니다.

표로 보기
| 항목 | 값 | 설명 |
|---|---|---|
| 통과한 검사 | 145 | 하나도 안 빠짐 |
| 실패한 검사 | 0 | 전부 초록불 |
| 내가 심은 고장 | 12 | 12개 모두 잡힘 |
마지막 칸이 제가 제일 믿었던 근거입니다.
검사가 진짜 일하는지 확인하는 방법이 하나 있거든요. 일부러 고장을 심어 보는 겁니다. 멀쩡한 코드를 골라 한 줄을 망가뜨린 다음, 검사가 그걸 잡아내는지 봅니다. 못 잡으면 그 검사는 아무것도 지키지 않는 거죠.
제가 고장 12개를 심었고, 12개 전부 잡혔습니다.
그래서 저는 “이 정도면 됐다”고 생각했습니다.
다른 AI에게 「일부러 고장 내 보라」고 시켰습니다
저는 글을 쓰든 코드를 짜든 혼자 검토하지 않습니다. 만든 쪽과 검사하는 쪽을 따로 두는 습관인데, 이건 개발기 ⑩에서 한 편을 통째로 다룬 이야기입니다.
이번에도 다른 AI에게 같은 일을 시켰습니다. 제 코드를 통째로 복사해 따로 작업장을 차려 주고, “네가 직접 고장을 만들어서 심어 봐라”고 했습니다.

그 AI가 만든 고장은 19개였습니다.
그중 8개가 그대로 통과했습니다.

표로 보기
| 항목 | 설명 | 값 |
|---|---|---|
| 검사가 못 잡음 | 8개 | 42 |
| 검사가 잡아냄 | 11개 | 58 |
숫자 자체보다 더 아팠던 건 그 다음입니다.
제 고장은 12개 중 12개가 잡혔는데, 남의 고장은 19개 중 8개가 통과했습니다. 같은 검사인데 결과가 이렇게 갈렸죠.

표로 보기
| 고장을 만든 쪽 | 내가 만든 것 | 다른 AI가 만든 것 |
|---|---|---|
| 심은 고장 수 | 12개 | 19개 |
| 검사가 잡아냄 | 12개 | 11개 |
| 그대로 통과 | 0개 | 8개 |
| 통과 비율 | 0% | 42% |
이유는 허탈할 만큼 단순합니다.
고장을 만든 사람과 검사를 만든 사람이 같으면, 자기가 아는 결함만 심게 됩니다. 제가 걱정하던 자리에는 이미 검사를 붙여 놨으니, 거기에 고장을 심으면 당연히 잡히죠.
제가 걱정조차 안 한 자리에는 검사도 없고 고장도 안 심었습니다. 그래서 12개 전부 잡힘이라는 성적표가 나왔던 겁니다.
물론 “그 AI가 억지로 이상한 고장만 골라 심은 것 아니냐”고 하실 수 있습니다. 그 19개가 현실에서 자주 나는 고장인지까지는 저도 단정 못 합니다.
다만 8개는 전부 “이런 결함이 있어도 통과한다”를 말이 아니라 실제로 돌려서 보인 것이었어요. 그 AI는 고장을 심기 전에 145개가 그대로 통과한다는 것을 먼저 확인한 뒤에 판정했습니다.
가장 무서웠던 건 스위치였습니다
뚫린 8개 중에 제일 등골이 서늘했던 걸 하나만 꺼내겠습니다.
제 프로그램에는 켜고 끌 수 있는 스위치가 있습니다. 어떤 기능을 쓸지 말지 정하는 값이죠. 당연히 이게 켜져 있어야 그 기능이 돕니다.
검사를 돌리려면 무대를 먼저 차려야 합니다. 필요한 값을 채워 넣고, 가짜 데이터를 준비하고, 그런 다음에 부품을 눌러 보는 거죠. 그 준비를 맡는 코드가 따로 있습니다.
그 준비 코드가 검사를 돌릴 때마다 스위치를 켜 놓고 시작했습니다.

시험 감독관이 답안지에 답을 미리 적어 놓고 채점한 셈입니다. 무슨 답을 써 내든 만점이 나오죠.
그래서 그 기능을 통째로 꺼 놓고 내보내도 145개가 전부 통과했습니다. 기능이 하나도 안 도는 상태인데 성적표는 만점이었던 겁니다.

「0회」라는 숫자가 아무것도 증명하지 못할 때
두 번째로 아팠던 건 0이라는 숫자였습니다.
제가 지키고 싶었던 약속 중에 “이 경로에서는 외부 서버를 추가로 부르지 않는다”가 있었습니다. 불필요한 호출이 늘면 돈도 들고 차단도 당하거든요. 검사는 호출 횟수가 0회임을 확인하고 통과 판정을 냈습니다.
그런데 그 검사가 쓰던 가짜 실행기가 넘겨받은 일을 아예 실행하지 않고 있었습니다.
일을 안 시켰으니 호출이 0회인 건 당연하죠. 배선이 제대로 돼 있든, 통째로 끊겨 있든 결과는 언제나 0회였습니다.
쉽게 말하면 이런 겁니다. 전화를 한 통도 안 걸어 놓고 “통화 요금 0원”을 보며 절약했다고 좋아한 거예요.

표로 보기
| 화면에 찍힌 값 | 내가 믿은 뜻 | 실제로 벌어진 일 |
|---|---|---|
| 호출 0회 | 약속을 잘 지켰다 | 일이 시작조차 안 됐다 |
| 검사 결과 | 통과 | 통과 |
| 내가 아는 것 | 다 잘 됐다 | 아무것도 확인 못 함 |
이건 사실 제가 이미 한 번 배웠던 교훈입니다. 개발기 ⑤에서 “0건은 정상이 아니라 아직 확인 못 한 것”이라고 공개적으로 써 놓기까지 했거든요.
그래 놓고 19일 뒤에 또 같은 자리에서 걸렸습니다.
검사가 대상을 비켜 가는 길은 정해져 있습니다
이번에 뚫린 8개와 그 며칠 전 사건들을 늘어놓고 보니 길이 몇 갈래로 정리됐습니다. 전부 다르게 생겼는데 결론은 하나였어요. 검사 이름이 가리키는 것을, 검사식이 실제로는 안 보고 있었습니다.

표로 보기
| 단계 | 내용 | 설명 |
|---|---|---|
| 1단계 | 준비가 답을 채움 | 검사가 자기가 켠 값을 확인 |
| 2단계 | 대상을 안 읽음 | 상수끼리만 계산해 항상 참 |
| 3단계 | 도구 실패를 성공으로 | 도구가 죽으면 빈 값이 통과 |
세 번째가 특히 지독했습니다.
제 검사 중에 바깥 도구를 불러다 쓰는 게 있었는데, 그 도구가 성공했는지를 확인하지 않았습니다. 도구가 죽으면 결과가 빈 값으로 돌아오고, 검사는 그 빈 값을 보고 “변경 사항 없음, 통과”라고 읽었죠.
실제로 도구가 못 도는 환경에 갖다 놓으니 매매 심장부를 지키는 검사 7건이 전부 통과했습니다.
두 번째 갈래는 며칠 앞선 다른 검사에서 나온 건데, 더 어이가 없습니다. 어떤 검사식이 양변이 상쇄돼서 계산해 보면 항상 참이었습니다. 검사 대상 파일을 한 줄도 읽지 않고, 상수끼리만 더하고 빼서 “통과”를 내고 있었어요.
이름이 “~를 검증”인데 식 안에 그 대상이 없으면, 그건 검사가 아니라 주석입니다.
목록을 적어 둔 사람이 그 목록대로 또 틀렸습니다
여기서 제일 불편한 이야기를 해야겠네요.
이 함정들을 저는 이미 문서로 정리해 뒀습니다. “검사가 헛통과하는 형태” 목록을 만들어 두고, 다음엔 안 걸리겠다고 생각했죠.
그런데 그 목록을 적은 뒤에 같은 사람이 그 목록에 적힌 형태를 세 개나 더 저질렀습니다. 며칠 사이에 벌어진 일입니다.

표로 보기
| 시점 | 사건 | 설명 |
|---|---|---|
| 7월 29일 | 배선 1줄을 지워도 통과 | 검사가 진짜 입구를 안 불렀다 |
| 8월 3일 | 한 세션에 세 형태 동시 | 이날 함정 목록을 문서로 만듦 |
| 8월 3일 밤 | 목록을 쓴 사람이 또 저지름 | 셋 중 둘이 이날 나옴 |
| 8월 5일 | 남이 만든 고장 8개 통과 | 여기서 8개를 검사로 굳힘 |
형태를 외워 두는 것으로는 안 걸립니다. 목록은 읽을 때만 작동하거든요. 코드를 짜는 순간에는 아무도 그 목록을 안 펴 봅니다.

그래서 방법을 바꿨습니다.
그래서 지금은 남이 만든 고장을 받아서 돌립니다
정리하고 나서 실제로 바꾼 건 딱 두 가지입니다.
첫째, 뚫린 8개를 제 검사 목록에 집어넣었습니다. 그중 일곱 개는 이제 다시 심으면 검사가 죽습니다.
여덟 번째 하나는 그렇게 못 했습니다.
하필 앞에서 제일 지독하다고 한 그것 — 도구가 죽으면 빈 값이 통과하던 자리입니다. 정상적인 환경에서는 그 도구가 성공하니까, 그 고장을 일부러 재현할 방법이 없거든요. 코드는 고쳤는데 “다시 나면 잡는다”는 그물은 못 쳤습니다.
그래서 그 자리에 이렇게 적어 뒀습니다. 변이로 덮지 못한 것. 나중에 이 글을 다시 읽을 저를 위해서요.
둘째, 고장을 만드는 쪽을 저와 분리했습니다. 제가 만든 고장 12개가 12개 다 잡히는 건 이제 아무 의미가 없다는 걸 알거든요. 검사가 튼튼한지 알고 싶으면 제 머리 밖에서 만들어진 고장이 필요합니다.

표로 보기
| 항목 | 값 | 설명 |
|---|---|---|
| 검사로 굳힘 | 7 | 다시 심으면 죽음 |
| 수리만 함 | 1 | 재현이 불가 |
| 손 못 댐 | 1 | 준비 코드 구조 |
셋째는 아직 못 했습니다. 검사를 돌리는 준비 코드가 값을 채워 넣는 구조 자체는 그대로예요. 값을 채우지 않고 완전히 새로 읽어 오는 방식으로 바꾸는 게 맞는데, 손댈 자리가 넓어서 다음으로 미뤘습니다.
그래서 이 편도 “다 고쳤습니다”로는 못 닫습니다.
그래도 지난 편(⑭)보다는 낫습니다. 그땐 실패를 감지하고도 저한테 알리지 못했는데, 이번엔 여덟 곳 중 일곱이 검사로 굳어서 같은 고장으로는 못 지나갑니다. 못 친 그물이 어디인지도 알고 있고요.
여러분이 받는 「이상 없음」도 구조가 같습니다
여기까지가 봇 이야기고, 제가 이 일에서 제일 오래 붙잡고 있던 생각은 따로 있습니다.
우리는 “확인했다”는 말을 결과로 받습니다. 그런데 정작 알아야 할 건 그 확인이 무엇을 봤느냐거든요.

한번 따라와 보세요.
제가 보험 상담을 받으면서 “이거 보장 되나요?”라고 묻습니다. 상담해 주는 분은 제가 물은 항목에 정확히 답해 줍니다. 저는 “확인했다”고 생각하고 나옵니다.
그런데 제가 안 물어본 칸은 그 대화에 아예 들어오지 않았습니다. 저는 제가 아는 위험만 물었고, 답도 딱 거기까지만 받은 거죠.
제 검사가 제 고장 12개를 12개 다 잡은 것과 똑같은 구조입니다.

표로 보기
| 확인의 종류 | 결과에 들어오는 것 | 결과에 안 들어오는 것 |
|---|---|---|
| 내가 물어본 상담 | 물어본 항목 | 안 물어본 항목 |
| 자동 조회 자료 | 시스템에 올라온 자료 | 올라오지 않는 자료 |
| 알림 설정 | 설정해 둔 항목 | 설정 안 한 항목 |
| 내가 아는 것 | 이상 없음 | 본 적 없음 |
연말정산도 같습니다. 자동 조회로 자료를 불러오면 조회가 끝났다고 뜨죠. 그런데 그 시스템에 올라오지 않는 항목은 조회에 안 잡힙니다. 국세청도 해마다 “일부 자료는 직접 챙기셔야 한다”고 안내하고 있고, 어떤 항목이 여기 해당하는지는 해마다 달라질 수 있으니 그해 안내를 직접 확인하셔야 합니다.
화면에는 어느 쪽이든 똑같이 조회가 끝났다는 표시만 뜹니다. 다 챙겼다는 뜻이 아니라 올라온 것은 다 불러왔다는 뜻인데, 우리 눈에는 구별이 안 되죠.
여러분 통장으로 치면 이렇습니다. 잔액에 찍힌 숫자는 정확한데, 애초에 안 들어온 돈은 그 숫자 어디에도 표시되지 않습니다.
여기서 한 걸음 더 갑니다.
이 구조가 무서운 건 틀렸다는 신호가 어디에서도 안 나온다는 점입니다. 잘못 계산되면 오류가 뜨고, 서류가 빠지면 반려가 옵니다. 그런데 애초에 안 본 칸은 오류도 반려도 없습니다. 그냥 조용히 넘어가고, 저는 이상 없다고 믿은 채로 몇 년을 보냅니다.
그 사이에 새는 돈은 제 통장에서 나가는데, 저는 그게 새고 있다는 것조차 모릅니다.
여기까지 읽으시고 이런 생각 드셨을 겁니다. “그럼 전문가 말도 못 믿고 뭘 어쩌라는 거냐.” 저도 그 생각을 했습니다. 답은 의외로 작았어요.
오늘 남은 문장
「이상 없음」은 답이 아니라, 무엇을 봤는지에 대한 요약입니다.
그래서 점검 결과를 받으면 저는 이제 한 가지를 더 묻습니다. “그래서 무엇을 보셨나요?” 통과했느냐가 아니라 범위를 묻는 겁니다. 답이 안 나오면 그 통과는 제가 믿을 근거가 없는 거죠.
오해하지 마세요. 점검을 하지 말자는 이야기가 아닙니다. 제 검사는 지금도 돌고 있고, 그때보다 늘었고, 값을 합니다. 다만 그게 만점이라는 사실이 안전하다는 뜻은 아니었다는 거예요.
제일 크게 배운 건 이겁니다. 내가 만든 자로 나를 재면, 내가 이미 아는 것만 나옵니다. 제 경우엔 그 자를 밖에서 한 번 더 만들어 오게 하자 42%가 튀어나왔어요. 다른 곳에서도 꼭 42%가 나온다는 뜻은 아니고요.
지금 여러분이 “이상 없음”이라고 믿고 넘어가신 것이 하나라도 있으신가요? 보험이든, 자동이체든, 연말정산이든요. 그 확인이 무엇을 봤는지는 알고 계셨나요? 저는 145개 만점을 받아 놓고 스위치가 꺼진 줄도 몰랐습니다.
다음 글 예고 — 고쳤다고 믿은 자리가 제일 오래 방치됩니다
이 이야기에는 뒷장이 남아 있습니다.
이번에 8개를 검사로 굳혔다고 했죠. 그런데 고친 자리가 제 생각보다 좁았던 적이 있습니다. 같은 병을 함수 하나에서만 고쳤는데, 옆에 똑같은 병을 앓는 자리가 셋 더 있었거든요.
더 이상한 건, 그 셋을 찾아낸 게 제가 만든 검사가 아니었다는 겁니다.
※ 이 글은 자동매매 시스템을 만들며 겪은 과정을 기록한 개발기입니다. 특정 종목이나 매매 방법을 권유하지 않으며, 본문의 기록은 실제 돈이 오가지 않는 모의계좌·개발 환경에서 일어난 일입니다. 보험·세금 관련 절차는 개인의 가입 형태와 소득 요건에 따라 달라지므로 개별 사안은 해당 기관에 확인하셔야 합니다. 투자 판단과 그 책임은 본인에게 있습니다. 정보·교육·참고용으로만 봐 주세요.
아직 댓글이 없습니다. 이 글을 읽고 떠오른 생각을 남겨 주세요.