「끝났다」를 무엇으로 판정하나

품앗이가 AI와 함께 일하며 남긴 실패 기록을 다른 조직이 다시 쓸 수 있게 옮긴 글입니다. 묶음 전체는 AI가 「됐다」고 할 때에서 볼 수 있습니다.

요지

서버 응답 코드, 로그, 프로그램의 종료 코드, AI가 쓴 보고서는 모두 「무언가 돌았다」만 알려 줍니다. 사람이 쓰려던 것이 실제로 되는지는 그 사람이 앉는 자리에서 재야 압니다. 이 노드는 「됐다」로 보였지만 실제로는 안 된 자리 여덟 가지와, 그것을 막으려고 우리가 바꾼 판정 방식을 적습니다.

1. 200은 화면이 아니다

웹 서버가 돌려주는 200은 「요청을 받아 무언가를 내보냈다」는 뜻입니다. 화면이 제대로 그려졌다는 뜻은 아닙니다.

우리 기록에 따르면 한 워크숍 진행 화면이 하루에 세 번 깨졌는데, AI는 매번 200만 보고 「정상」이라고 답했습니다. 첫 번째는 첫 주소가 없었고, 두 번째는 시험용 기본값이 실전 화면에 남아 있었고, 세 번째는 버튼이 넘쳐 첫 항목이 화면 밖으로 밀려나 있었습니다. 세 번 모두 사람이 직접 화면을 열고 나서야 알았습니다. 다른 날에는 서버 응답과 서비스 점검과 API가 모두 200이었는데, 화면은 자바스크립트 문법 오류 하나로 여섯 시간 동안 죽어 있었습니다.

화면이 있는 결과물은 브라우저로 열어 판정하는데, 기준은 둘입니다. 브라우저 오류가 0건인지, 그리고 기대한 요소가 실제로 보이는지입니다. 「그려졌다」와 「보인다」도 달라서, 요소가 화면 안에 들어와 있는지, 가로로 넘쳐 옆으로 밀리지 않았는지까지 봅니다.

2. 200은 그 주소가 있다는 뜻도 아니다

정적 사이트는 없는 주소를 받아도 첫 화면을 내주며 200을 돌려주는 경우가 많습니다. 확인하려는 주소와 함께 일부러 없는 주소를 하나 쳐 보고, 둘이 같은 응답을 주면 그 200은 믿지 않습니다.

갱신 배포 직후에도 옛 본문이 200으로 나옵니다. 우리가 잰 경우에는 약 36초 동안 캐시가 옛 화면을 내주었습니다. 그래서 새 본문에만 들어 있는 낱말 하나를 골라 그 낱말이 보이는지로 판정합니다. 로그인 게이트가 돌려주는 302 역시 「밖으로 새지 않는다」만 말합니다. 파일이 없어도 302가 나오므로, 파일이 실제로 있는지는 빌드 결과물을 따로 봅니다.

판정할 주소는 사용자가 실제로 여는 주소입니다. 옆 경로를 확인하고 첫 주소가 됐다고 말하지 않습니다. 링크와 QR코드는 열리는지보다 맞는 목적지로 가는지가 중요합니다. QR코드는 이미지를 풀어 안에 든 주소 문자열을 읽어 봅니다. 환경 설정이 빠지면 개발자 컴퓨터 주소가 그대로 찍혀 나가기 때문입니다. 링크를 남에게 건네기 전에는 받는 사람이 평소 상태, 예를 들어 로그인하지 않은 상태에서 무엇을 보게 될지 한 줄로 적어 봅니다.

3. 로그는 완료가 아니다

큰 파일 묶음을 내려받는 일을 로그로 판정했다가 네 번 틀린 기록이 있습니다. 작업이 여러 번 다시 시작되면 로그는 회차마다 조각나서, 무엇이 끝났는지 로그만으로는 셀 수 없습니다. 파일이 실제로 있는지와 크기가 맞는지로 다시 세자 남은 대상이 2,504개에서 13개로 줄었습니다.

또 한 번은 자료 처리 작업이 「완료」를 찍었는데, 마지막 적재 단계가 오류 없이 조용히 실패해서 만들어진 642건 가운데 12건만 데이터베이스에 들어가 있었습니다. 그 뒤로는 작업 끝에 데이터베이스 건수를 작업 전과 비교해 찍습니다.

「남은 일이 뭐냐」는 질문에도 메모가 아니라 직접 조회한 숫자로 답합니다. 메모는 적은 날의 사진일 뿐이고 지금 상태를 말해 주지 않습니다.

4. 보내는 쪽의 성공은 받는 쪽의 증거가 아니다

한 백업 작업은 성공으로 끝났는데 담긴 파일이 0개였습니다. 파일 크기 조건을 단위째 올려서 비교하는 바람에 빈 파일만 골라졌기 때문입니다. 그래서 「담았다」가 아니라 「몇 개 담겼다」를 찍습니다.

파일을 보내는 도구가 원격 쪽이 잘못 알려 준 크기만큼만 저장하고 성공으로 끝난 일도 있습니다. 파일을 옮긴 뒤에는 받는 쪽에서 크기와 해시를 원본과 맞춰 봅니다. 백업이 돌았다는 증거도 보내는 쪽 기록이 아니라 받는 쪽에 쌓인 파일의 날짜입니다.

5. 절반의 성공이 가장 쉽게 지나간다

한 이관 스크립트는 화면에 「한쪽만 옮긴다」는 줄을 찍고 정상 종료했습니다. 그대로 갔다면 다음 날 아침 직원 전원이 로그인하지 못할 뻔했는데, 착수 전에 잡았습니다. 이런 일이 실패보다 위험한 까닭은 성공 표시가 붙어 있어서 다음 사람이 의심하지 않는다는 데 있습니다.

일부만 하도록 의도한 경우라면 그 사실을 옵션으로 드러내게 하고, 말하지 않은 부분 수행은 멈추게 만듭니다. 「이 순서를 어기지 마라」 같은 경고를 사람에게만 걸어 두어서도 안 됩니다. 같은 순서를 어기는 스크립트나 예약 작업이 있을 수 있습니다. 짝으로 만든 스크립트는 서로 비교해 차이를 봅니다.

코드 안에도 같은 함정이 있습니다. 우리 기록에는 「예외가 안 났으니 성공」으로 처리한 코드 때문에 문자가 가지 않았는데 화면에는 「보냈어요」가 뜬 일이 있습니다. 함수가 결과를 분명히 돌려주게 짜야 합니다.

6. 맡긴 쪽의 「완료」 보고는 선언이다

AI에게 일을 맡기면 「검증 완료」가 붙은 보고서가 돌아옵니다. 그 보고는 증거가 아니라 선언으로 읽습니다.

다른 AI 모델에게 맡긴 화면이 「검증 확인」 보고와 달리 배선 전체가 겉모양뿐이었고, 두 번째 결과물은 문법 오류로 파일을 읽어 들이지도 못하는 상태였습니다. 보고서의 「검증」 칸에는 실제로 잰 값이 아니라 검증 절차 안내문이 적혀 있었습니다. 슬라이드 20장에서 「넘침 0건」이라는 보고를 믿었는데 PDF로 뽑으니 23쪽이었던 일도 있습니다.

일을 맡길 때 완료 조건을 숫자로 적습니다. 쪽수, 파일 크기, 반드시 들어가야 할 낱말 같은 것이고, 돌아온 숫자는 다시 잽니다. 화면을 볼 수 없는 모델에게 눈으로 하는 검증을 맡기지 말고, 가로 넘침 0이나 요소가 화면 안에 있는지처럼 코드로 재는 검사를 시킵니다. 맡겨서 다시 쓴 글은 행사 이름, 지명, 사람 이름, 날짜부터 대조합니다. AI가 다시 쓰면 가까운 소재를 섞기 쉽습니다.

7. 「되는가」만 재면 빈 화면이 통과한다

작업 기록에 남은 한 협동조합의 근태 관리 화면은 서버 검사 75칸과 화면 검사 29칸을 모두 통과했습니다. 그런데 관리자가 열면 등록된 13명이 한 명도 보이지 않았습니다. 판정 칸이 모두 「기능이 되는가」였고, 「열었을 때 알고 싶은 것이 보이는가」는 한 칸도 없었습니다.

빈 화면은 오류가 아니라서 모든 검사를 통과합니다. 단계가 있는 화면은 「단계마다, 그 단계까지 쌓인 데이터를 넣고」 확인합니다. 판정표에 「보이는가」 칸을 숫자로 넣습니다. 첫 화면에 사람이 몇 명 이상 보이는지, 넓은 화면을 실제로 쓰는지 같은 것입니다.

8. 「껐다」와 「떴다」도 한 칸이 아니다

서비스를 멈추기만 하고 자동 시작 설정을 풀지 않아서, 재부팅 뒤 12일 동안 그 서비스가 다시 돌았습니다. 그 사이 「껐다」고 적은 안내 문서가 나갔습니다. 무언가를 끄는 일에는 그 서비스를 전제로 만든 감시와 측정을 같이 옮기는 일이 포함됩니다.

「프로세스가 떠 있다」와 「응답한다」도 다릅니다. 무거운 앱 하나는 시작됐다는 표시가 뜬 뒤에도 4분 가까이 응답하지 못했습니다. 화면이 있는 프로그램은 화면이 그려졌는지로 판정하고, 화면을 찍지 못했으면 「화면은 못 봤다」고 그대로 보고합니다.

처방: 완료 판정을 사람 눈에서 종료 코드로

우리는 같은 실수가 거듭되는 영역마다 작은 판정 도구를 하나씩 두었습니다. 배포, 발송, 서비스, 백그라운드 작업, 화면입니다. 그 도구가 정상 종료 코드를 낼 때만 「끝났다」고 말합니다. 각 도구는 알려진 고장 사례를 먼저 넣어 보고, 그 고장을 실제로 FAIL로 잡는지 확인한 뒤에 썼습니다. 틀린 검사는 검사가 없는 것보다 나쁘기 때문입니다. 결과는 한두 줄로 짧게 내게 했습니다. 길면 AI도 사람도 끝까지 읽지 않습니다.

판정을 정할 때 스스로 묻는 질문은 하나입니다. 이 일을 시킨 사람이 결과물을 열었을 때 확인하고 싶은 것을 지금 내 검사가 재고 있는가?

도구 메모

  • 주소 판정: 캐시를 피하는 쿼리 문자열을 붙이고, 새 본문에만 있는 고유 낱말이 응답에 있는지 본다. 없는 주소를 하나 같이 쳐서 응답이 다른지 본다.
  • 화면 판정: 헤드리스 브라우저로 열어 페이지 오류 0건, 기대 요소가 화면 안에 보임, 가로 넘침 0.
  • 서비스 판정: 「실행 중」 표시가 아니라 실제 포트나 주소가 응답할 때까지 기다렸다가 잰다.
  • 파일 판정: 받는 쪽에서 개수, 크기, 해시를 원본과 맞춘다.

관련 노드