점유율이 흔들린 진짜 이유는 실력이 아니라 결장이었다 — 유머 700라운드 블록 재집계
칼라톤의 AI 유머 배틀 리그는 시즌이 끝나면 모델별 총점·평균·우승 수를 얹은 리더보드 한 장으로 요약된다. 시즌 1은 GPT의 시즌, 시즌 5는 Gemini의 시즌, 이런 식이다. 그런데 시즌 하나는 짧아도 19라운드, 길게는 130라운드다. 그 긴 시간 동안 순위가 계속 그 모양이었을 리는 없다는 게 이번 집계의 출발 질문이었다. 시즌 안에서 점유율은 흔들리는가, 흔들린다면 그건 무엇의 신호인가.
방법은 단순하다. 시즌마다 라운드 표를 앞에서부터 12라운드씩 잘라 블록을 만들고, 블록별로 누가 몇 번 우승했는지 센다. 그리고 관측된 요동이 실제 변화인지 동전 던지기의 굴곡인지를 가른다. 결과를 먼저 적으면 이렇다. 눈에 보이는 요동은 거의 전부 후자였고, 전자가 확인된 네 시즌 중 하나는 실력의 변화가 아니라 한 모델이 그 라운드에 아예 없었다는 사실이었다.
방법 — 700라운드, 51개 블록, 그리고 순열검정
집계 대상은 저장소에 공개된 유머 시즌 리포트 국문 12편(시즌 1·2·3·5·7·9·11·13·15·17·19·21)이다. 리더보드의 우승 수를 모두 더하면 700라운드이고, '전체 라운드 우승 코멘트' 표에 실제로 실린 행은 697행이다(시즌 9·17·19가 한 행씩 비어 있다 — 이미 알려진 표시 계층의 결번이다). 블록은 표에 실린 행 순서대로 12개씩 잘랐고, 자투리(12라운드에 못 미치는 꼬리)는 통계에서 제외했다. 그렇게 만들어진 완전 블록이 51개다.
판정 기준은 순열검정이다. 시즌의 라운드 우승자 목록을 그대로 두고 순서만 무작위로 섞은 뒤 같은 방식으로 블록을 만들어 통계량을 다시 계산한다. 이 가상의 시즌들에서는 정의상 '시즌 내 변화'가 존재하지 않는다 — 모델별 실력이 처음부터 끝까지 고정된 세계다. 관측값이 이 가상 분포 안에 있으면 요동은 우연으로 설명되고, 바깥에 있으면 진짜 변화다.
결과 ① — 눈으로 보면 분명히 요동친다
먼저 시즌 1을 보자. 최다승 모델은 GPT(90라운드 중 44승)인데, 블록별로 갈라 놓으면 시즌이 두 개처럼 보인다.
| 시즌 1 블록 | GPT | Claude | Gemini | Grok |
|---|---|---|---|---|
| B1 (R3~14) | 6 | 2 | 2 | 2 |
| B2 | 7 | 3 | 1 | 1 |
| B3 | 8 | 1 | 2 | 1 |
| B4 | 6 | 3 | 0 | 3 |
| B5 | 5 | 4 | 1 | 2 |
| B6 | 6 | 6 | 0 | 0 |
| B7 (~R86) | 2 | 9 | 1 | 0 |
GPT의 블록 점유율은 66.7%(8/12)에서 16.7%(2/12)까지 내려앉고, Claude는 8.3%에서 75.0%까지 올라간다. 마지막 블록만 보고 시즌을 요약하면 "시즌 1은 Claude의 시즌"이 된다. 다른 시즌도 정도만 다를 뿐 비슷하다. 블록이 둘 이상인 열한 시즌의 최다승 모델을 추적하면 진폭(최고 블록 점유율 − 최저 블록 점유율)이 평균 23.5%p, 최대 50.0%p다.
실질적인 결과 하나. 51개 블록 중 12개(23.5%)에서 블록 1위가 그 시즌의 최다승 모델과 다르다. 임의의 12라운드를 잘라 그 구간의 1위를 시즌 챔피언이라고 부르면 네 번에 한 번은 틀린다는 뜻이다.
결과 ② — 그런데 그 진폭은 우연이 만드는 것보다 크지 않다
여기서 순열검정이 개입한다. 각 시즌 최다승 모델의 관측 진폭을, 순서를 섞은 가상 시즌들의 평균 진폭과 나란히 놓았다.
| 시즌 | 최다승 모델 | 시즌 점유율 | 관측 진폭 | 우연 평균 | p |
|---|---|---|---|---|---|
| 시즌 1 (7블록) | GPT | 47.6% | 50.0%p | 38.7%p | 0.264 |
| 시즌 2 (10블록) | Claude | 44.2% | 33.3%p | 43.3%p | 0.901 |
| 시즌 3 (7블록) | Gemini | 36.9% | 41.7%p | 37.3%p | 0.467 |
| 시즌 5 (4블록) | Gemini | 52.1% | 33.3%p | 30.0%p | 0.493 |
| 시즌 7 (4블록) | Gemini | 39.6% | 8.3%p | 29.0%p | 1.000 |
| 시즌 9 (4블록) | Gemini | 35.4% | 16.7%p | 28.5%p | 0.902 |
| 시즌 11 (4블록) | GPT | 56.2% | 16.7%p | 29.6%p | 0.925 |
| 시즌 13 (4블록) | GPT | 45.8% | 8.3%p | 29.7%p | 1.000 |
| 시즌 17 (2블록) | GPT | 45.8% | 8.3%p | 16.6%p | 1.000 |
| 시즌 19 (2블록) | Grok | 33.3% | 33.3%p | 15.1%p | 0.200 |
| 시즌 21 (2블록) | Gemini | 45.8% | 8.3%p | 16.9%p | 1.000 |
열한 시즌 중 여덟 시즌에서 관측 진폭이 우연 평균보다 작다. 12라운드짜리 표본에서 점유율 40% 안팎의 모델이 만들어 내는 자연스러운 요동은 30~40%p 수준이고, 우리 리그의 실제 요동은 그 안에 얌전히 들어가 있다. 시즌 1의 50.0%p조차 p=0.264 — 우연으로 넉넉히 설명된다.
열한 시즌을 합쳐 블록×모델 교차표의 카이제곱을 더한 값도 마찬가지다. 관측 161.69 대 순열 평균 148.41, p=0.18. 최다승 모델 진폭의 합만 따로 보면 관측 258.3%p 대 우연 315.4%p로 오히려 좁은 편이지만 이쪽도 유의 수준에는 못 미친다(p=0.083). 요약하면, 블록 표만 놓고 "이 시즌은 후반에 흐름이 바뀌었다"고 말할 근거는 없다. 12라운드는 그런 말을 하기에 너무 짧은 창이다.
결과 ③ — 순서를 쓰면 보인다: 11시즌 중 4시즌
블록 표의 약점은 순서를 버린다는 것이다. 카이제곱은 B1이 높고 B4가 낮은 경우와 B2만 튀는 경우를 구분하지 못한다. 그래서 같은 데이터에 방향을 가진 검정을 한 번 더 걸었다. 각 모델의 우승 여부(0/1)와 라운드 순서의 상관계수를 구하고, 시즌 안에서 여러 모델을 동시에 보는 다중비교를 순열 안에서 흡수하도록 최대 |상관|을 통계량으로 삼았다.
| 시즌 | 가장 큰 추세 | 상관 | 시즌 단위 p | 구간 대조 |
|---|---|---|---|---|
| 시즌 11 | Grok ↑ | +0.353 | 0.024 | R1~30 2승 → R31~59 8승 |
| 시즌 7 | GPT ↓ | −0.334 | 0.037 | 마지막 승리 R42, 이후 17라운드 0승 |
| 시즌 1 | Claude ↑ | +0.264 | 0.039 | 17.3%(9/52) → 52.6%(20/38) |
| 시즌 13 | Gemini ↑ | +0.338 | 0.040 | 첫 승이 R30, 그 전 29라운드 0승 |
| 시즌 2 | GPT ↓ | −0.212 | 0.053 | — |
| 나머지 6시즌 | — | — | 0.198~0.796 | — |
우연이라면 열한 시즌 중 0.55개가 p<0.05에 걸려야 하는데 넷이 걸렸다. 즉 시즌 내 변화는 실재한다 — 다만 블록 표로는 안 보이고, 라운드 순서를 쓰는 검정으로만 보인다. 시즌 7의 GPT는 특히 선명하다. 58라운드에 출전해 16승을 거뒀는데 마지막 승리가 R42이고 이후 17라운드에서 한 번도 못 이겼다. 시즌 전체 승률(27.6%)이 그대로 유지됐다면 17연패 확률은 0.41%다.
시즌 7은 이미 다른 각도에서 한 번 지목된 시즌이다. 점수 눈금이 내려앉은 지점을 추적한 칼럼에서, 85점 이하 우승작 6건이 전부 R46 이후에 몰려 있고 12라운드 블록 평균이 단조 하락한 유일한 시즌으로 나왔다. 점수가 내려앉은 구간과 GPT가 우승을 못 한 구간이 같은 자리다.
결과 ④ — 넷 중 하나는 실력이 아니라 출석이었다
시즌 13의 Gemini는 블록별로 0, 0, 4, 5승이다. 후반에 각성한 것처럼 보이는 가장 극적인 곡선인데, 이것을 실력의 변화로 읽으면 틀린다. 리포트 리더보드에는 그 이유가 이미 적혀 있다 — 다만 나눗셈을 해야 보인다.
리포트의 '평균' 열은 총점 ÷ 출전 라운드 수이고 '승률' 열은 우승 수 ÷ 출전 라운드 수다(html2pdf/src/aihumor-data-fetcher.js). 따라서 총점 ÷ 평균과 우승 수 ÷ 승률은 둘 다 그 모델이 실제로 뛴 라운드 수를 되돌려 준다. 시즌 13의 Gemini는 1,818 ÷ 62.7 = 29.0이고 10 ÷ 0.345 = 29.0이다. 56라운드 시즌에서 29라운드만 뛰었다. 첫 승이 R30인 것은 각성이 아니라 등장이다.
이 재구성은 60개 리더보드 행 전부에서 정수와 최대 0.055라운드 차이로 맞아떨어진다. 그 눈금으로 12시즌을 훑으면 결장이 무더기로 나온다.
| 시즌 · 모델 | 출전/전체 | 결장 | 우승 | 정황 |
|---|---|---|---|---|
| 시즌 1 · Kimi K2.5 | 1 / 90 | 89 | 0 | 이후 시즌에서 DeepSeek으로 교체 |
| 시즌 11 · Gemini 3.5 Flash | 2 / 59 | 57 | 0 | 리더보드 5위, 총점 105점 |
| 시즌 13 · Gemini 3.5 Flash | 29 / 56 | 27 | 10 | 첫 승 R30 |
| 시즌 21 · Grok 4.6 | 14 / 25 | 11 | 1 | 유일한 승리가 마지막 라운드 |
| 시즌 2 · Claude 4.5 Sonnet | 120 / 130 | 10 | 60 | 최다승 모델도 10라운드 결장 |
| 시즌 2 · DeepSeek V3.1 | 122 / 130 | 8 | 4 | — |
| 시즌 1 · Grok 4 | 82 / 90 | 8 | 10 | — |
| 시즌 1 · Gemini 2.5 Flash | 83 / 90 | 7 | 7 | — |
| 시즌 2 · Gemini 3.5 Flash | 123 / 130 | 7 | 44 | — |
| 시즌 2 · GPT-5.2 | 124 / 130 | 6 | 21 | — |
| 시즌 19 · Grok 4.6 | 21 / 26 | 5 | 9 | 출전 대비 승률 42.9%로 1위 |
결장이 2라운드 이상인 모델-시즌은 모두 13건이며 위 표는 그중 11건이다(나머지는 시즌 7 Claude 57/59, 시즌 13 GPT 54/56). 12시즌 전체로는 (시즌, 모델, 라운드) 슬롯 3,500개 중 248개(7.1%)가 결장이다. 그중 173개가 위 표의 상위 세 건에 몰려 있고, 나머지 75개(2.1%)는 시즌 곳곳에 흩어진 산발적 실패다.
시즌 13 Gemini의 결장이 앞쪽에 몰려 있다는 것은 통계로도 확인된다. 만약 앞 24라운드에 전부 출전하고도 0승이었다면, 시즌 승률 34.5% 기준으로 그 확률은 0.65524 ≈ 2만 6천분의 1이다. 뛰었는데 못 이긴 것이 아니라 없었던 것이다.
해석 — 결장은 리그의 사고 기록이고, 라운드 표에는 안 남는다
라운드 표는 우승자만 싣는다. 진 모델도, 아예 제출하지 않은 모델도 그 표에서는 똑같이 '이름이 없음'이다. 코드를 보면 그렇게 될 수밖에 없다. 라운드 실행부(Humor/PlayBackend/models/HumorSeason.js)는 로스터를 is_active = TRUE로 조회한 뒤 참가자별 호출을 Promise.all로 묶고, 각 호출을 개별 try/catch로 감싼다. 한 모델이 던지면 그 모델만 조용히 빠지고 라운드는 남은 모델들로 계속된다. 점수 반영 루프도 채점 행이 있는 모델에 대해서만 rounds_played = rounds_played + 1을 돌린다. 그래서 결장은 분모에만 남는다.
그 분모가 왜 줄었는지에 대한 정황은 저장소 안에 있다. Humor/PlayBackend/utils/llm.js의 Gemini 직접 호출 클라이언트 위에는 이런 주석이 박혀 있다 — "Image2Text의 Vertex 이미지 생성이 같은 컨테이너 env를 오염시키면 이 AI-Studio 키 클라이언트가 Vertex 모드로 캐시되어 전 콜이 죽는다(2026-07-27~08-04 일반 시즌 image_verify·gemini 코미디언 전멸 사고 — 96% 실패, 8일 무감지)". 시즌 11 리포트의 발행일은 2026-07-31, 시즌 13은 2026-08-07이다. 주석이 적은 8일이 시즌 11 전체와 시즌 13의 앞부분을 덮는다. 시즌 9(7/24 발행)의 Gemini는 59라운드 전부에 출전했고, 시즌 15(8/14)도 19라운드 전부다. 경계가 양쪽에서 맞는다.
같은 모양의 사고가 다른 모듈에서도 문서화돼 있다. docs/MODEL_UPGRADE_2026_09_GEMINI_3_8_PLAN.md는 매칭 모듈의 매치메이커 한 명이 시즌 9 내내 매 라운드 예외를 던졌고 매치메이커 단위 catch 때문에 산출 0건인 채로 조용히 빠져 있었다고 기록한다. 참가자 단위로 실패를 흡수하는 설계는 라운드를 살리는 대신 결석을 침묵시킨다. 우리 리그에서는 그 침묵이 '점유율 곡선'으로 위장한다.
한계 — 이 집계가 말할 수 없는 것
첫째, 결장의 위치는 추정이다. 리더보드는 시즌 합계만 준다. 출전 라운드 수는 정확히 복원되지만 "몇 번 라운드에 없었는지"는 리포트에 없다. 시즌 13 Gemini의 첫 승 R30과 출전 수 29를 함께 놓으면 R30 이후 구간이 자연스러운 해석이지만, 그것은 확정이 아니라 정황이다. 라운드별 타임스탬프도 리포트에 없어 코드 주석의 날짜와 라운드를 직접 맞댈 수 없다 — 특정 가능한 것은 시즌 경계까지다.
둘째, 블록 경계는 표에 실린 행 순서로 잘랐다. 시즌 9·17·19는 라운드 행이 하나씩 비어 있어 그 시즌의 블록 경계가 실제 라운드 번호와 한 칸씩 어긋난다. 시즌 1의 표는 R3에서 시작하고, 시즌 19의 표는 R2에서 시작한다. 12라운드 블록이라는 단위 자체도 임의 선택이며, 6이나 20으로 잘랐다면 다른 그림이 나올 수 있다(블록 크기를 바꿔도 결론이 유지되는지는 이번 집계에서 검증하지 않았다).
셋째, 추세가 확인된 세 시즌에서도 원인은 미확정이다. 시즌 11의 Grok, 시즌 1의 Claude, 시즌 7의 GPT는 출전 라운드 수가 각각 59/59, 89/90, 58/59로 결장이 거의 없어 '없어서 못 이긴' 경우가 아니다. 그러나 주제 소재의 변화, 심사 규칙의 조정, 다른 참가자의 부재 같은 요인이 전부 같은 모양의 곡선을 만든다. 실제로 시즌 11은 Gemini가 사실상 통째로 빠진 시즌이라 경쟁자 수 자체가 달랐다.
넷째, 이 글은 점수를 쓰지 않았다. 유머 리그의 채점 눈금은 2026년 7월 중순 루브릭 개정 전후로 달라져 시즌을 넘나드는 점수 비교가 성립하지 않는다. 그래서 눈금 변경에 견디는 지표인 '라운드 우승 점유율'만 썼다. 대신 이 선택 때문에 "이겼는가"보다 세밀한 것 — 얼마나 아깝게 졌는가 — 은 전부 보이지 않는다. 탈락 후보의 점수는 공개 리포트에 실리지 않는다.
다섯째, 리더보드의 순위는 우승 수가 아니라 총점 기준이다. 시즌 2는 Claude가 60승으로 최다승인데 리더보드 1위는 44승의 Gemini다. 이 글의 '최다승 모델'은 리포트의 1위와 다를 수 있다(라운드 승수와 시즌 우승의 어긋남은 별도 칼럼에서 다뤘다).
그래서, 점유율은 흔들리는가
흔들린다. 다만 눈에 보이는 요동의 대부분은 12라운드라는 짧은 창이 만드는 착시이고, 진짜 변화는 순서를 세는 검정으로만 잡히며, 그렇게 잡힌 네 시즌 중 하나는 실력의 변화가 아니라 출석부의 구멍이었다. 리그를 운영하는 입장에서 이번 집계의 실무적 소득은 마지막 항목이다. 점유율이 갑자기 0으로 내려앉은 모델을 보면 먼저 물어야 할 질문은 "왜 못 이겼나"가 아니라 "그 라운드에 있었나"다.
그리고 그 질문의 답은 이미 공개 리포트 안에 있었다. 총점을 평균으로 나누기만 하면 되는 값이 리포트를 공개해 온 석 달 내내 아무도 나눠 보지 않은 채 표에 앉아 있었다. 리포트를 공개하는 이유가 이런 데 있다고 믿는다 — 우리가 못 본 것을 표가 대신 기억해 준다. 최근 시즌 리포트의 리더보드에서도 같은 나눗셈을 해 볼 수 있다. Grok의 총점 787을 평균 56.2로 나누면 14가 나온다. 25라운드짜리 시즌에서.
집계 기준. 2026년 9월 10일(KST) 기준 저장소에 공개된 AI 유머 리그 시즌 리포트 국문 12편(Frontend/public/reports/humor/season-*.html, 시즌 1·2·3·5·7·9·11·13·15·17·19·21, 발행일 2026-06-20~2026-09-03) 전수. 라운드 수 700은 리더보드 '우승' 열의 시즌별 합계이며 표에 실린 라운드 행은 697개다(시즌 9·17·19 각 1행 결번). 블록은 표 행 순서대로 12개씩 자르고 자투리는 제외해 완전 블록 51개를 얻었다. '블록 1위'가 동점인 블록 7개는 최다승 모델이 공동 1위에 포함되면 일치로 셌다. 순열검정은 시즌별 우승자 목록의 순서를 무작위로 재배치하는 방식이며 블록 카이제곱은 20,000회, 진폭·합산 통계는 4,000~5,000회 재배치 기준이다. 출전 라운드 수는 리포트 리더보드의 총점 ÷ 평균으로 역산했고 우승 수 ÷ 승률로 교차 확인했다(html2pdf/src/aihumor-data-fetcher.js의 avg_score·win_rate 정의). 60개 리더보드 행 전부에서 역산값과 정수의 차이는 최대 0.055라운드였다. 교차 검증으로 영문 리포트 12편의 라운드 697행(회차·모델·점수)과 리더보드 60행(순위·모델·총점·평균·우승·승률)을 국문판과 대조해 불일치 0건을 확인했다. 코드 근거는 Humor/PlayBackend/models/HumorSeason.js의 라운드 실행부와 utils/llm.js의 주석이며, 배포본이 저장소 코드와 동일하다고 단정할 수 없으므로 정황으로 읽어 주시기 바란다.