Post

ARC-AGI-3 2편: 수학적으로 완벽한 아이디어가 죽은 자리 (KR)

ARC-AGI-3 2편: 수학적으로 완벽한 아이디어가 죽은 자리 (KR)

ARC-AGI-3 워킹노트 2: 수학적으로 완벽한 아이디어가 죽은 자리

워킹노트입니다. 1편이 이 대회의 지도를 그리는 글이었다면, 이번 글은 그 지도를 들고 실제로 걸어 본 6주의 기록입니다. 제출 네 번, 인프라 사고 두 번, 그리고 수학적으로는 흠잡을 데 없었지만 규칙 한 줄에 무효가 된 아이디어 하나. 결론을 한 문장으로 미리 적으면 이렇습니다 — 이 6주 동안 점수를 가장 많이 움직인 것은 알고리즘이 아니라, 어디서 측정하고 무엇이 허용되는지를 다시 읽은 일이었습니다. 모든 수치는 2026년 8월 4일 기준입니다.

1편: ARC-AGI-3: 아직 아무도 풀지 못한 벤치마크

0. 네 번의 제출, 이상하리만치 좁은 점수대

여섯 주 동안 네 번 제출했고, 점수는 0.86 / 0.88 / 0.89 / 0.93이었습니다.

처음에는 위안이 되는 해석을 골랐습니다. “표본이 적어서 그렇다. 몇 번 더 내면 올라간다.” 리더보드 위쪽의 1.4~1.9가 운 좋은 추첨의 결과라면 맞는 얘기입니다. 하지만 네 표본이 폭 0.07 안에 모이는 걸 보면서 그 해석은 점점 유지하기 어려워졌고, 결국 이 좁은 점수대 자체가 이번 글의 출발점이 됐습니다. 점수대가 좁다는 것은 분산이 작다는 뜻이고, 분산이 작다면 위와의 격차는 운이 아니라 실력의 격차라는 뜻이기 때문입니다. 이 판정은 3장에서 숫자로 하겠습니다.

그 전에, 부끄럽지만 기록 가치가 있는 사고 두 건부터 적습니다.

1. 사고 두 건: 조용한 페일세이프는 독이다

사고 ①. 첫 제출(0.86)은 제가 만든 에이전트가 아니었습니다. Kaggle UI에서 노트북을 만들며 데이터셋을 붙이는 과정에서, 개조 소스 번들 대신 순정 번들이 붙었습니다. 제 코드는 “의존 모듈이 없으면 조용히 순정 동작으로 강등”하는 페일세이프 사다리로 짜여 있었고, 사다리는 설계대로 작동했습니다 — 그래서 아무 에러 없이, 제 개조가 하나도 실리지 않은 순정 에이전트가 제출됐고, 저는 그 점수를 보고 제 아이디어를 평가하고 있었습니다.

교훈은 “페일세이프를 넣지 말라”가 아닙니다. 강등은 허용하되, 조용한 강등은 금지해야 한다입니다. 지금은 커밋 단계에서 번들에 개조 모듈이 없으면 즉시 크래시하고, 최종 조립된 에이전트의 클래스 이름을 로그로 검증합니다.

사고 ②. 다음 버전은 7시간을 완벽하게 돌고 마지막 저장 단계에서 죽었습니다. 실행 프레임워크는 런 종료 시 에이전트 객체를 pickle로 저장하는데, 제가 런타임에 type()으로 동적 생성한 클래스는 모듈 속성으로 존재하지 않아 pickle이 참조를 만들지 못합니다. 제가 확장한 원본 코드가 굳이 모듈 레벨 클래스로 작성된 이유가 바로 그것이었습니다. 프레임워크의 관례에는 대개 이유가 있고, 그 이유는 주석이 아니라 직렬화 경로 같은 보이지 않는 계약에 숨어 있습니다.

두 사고의 공통 교훈: 내 가설을 검증하기 전에, 검증 파이프라인 자체가 검증됐는지부터 물어야 합니다.

2. 수학적으로 완벽한 아이디어, 그리고 그것이 죽은 자리

이제 본론입니다. 제 첫 차별화 아이디어는 채점 구조에서 출발했습니다.

2.1 아이디어: 이긴 게임을 더 싸게 “다시 제출”하기

1편에서 정리했듯 레벨 점수는

\[s_\ell = \min\!\left(\left(\frac{h_\ell}{a_\ell}\right)^{2},\ 1.15\right)\]

로, 액션 수의 제곱에 반비례합니다. 액션을 절반으로 줄이면 레벨 점수는 4배가 됩니다. 그리고 대회에 동봉된 채점 엔진을 읽다가 이 코드를 발견했습니다.

1
2
# scorecard: 한 게임 카드의 점수
return max(run.score for run in self.runs)

카드 점수는 플레이들의 최대값입니다. 그렇다면 전략이 저절로 써집니다. 게임을 이긴 직후, 그 게임을 한 판 더 열어서 이번에는 낭비 없이 다시 이기면 됩니다. 그냥 승리 궤적을 재생하는 게 아니라, 플레이 중 관측한 모든 전이 $(s, a) \to s’$를 그래프로 쌓고 최단 경로를 재생합니다. 승리 루트 자체가 그래프에 들어 있으므로 최단 경로는 절대 그보다 길 수 없고, 재생 중 매 스텝을 기록된 프레임과 대조해서 하나라도 어긋나면 즉시 중단하면 됩니다. 중단해도 기존 승리가 max를 지키니 하방 위험이 정확히 0인 점수 단조 증가 장치입니다.

설계했고, 구현했고, 단위 테스트 열아홉 개를 전부 통과시켰습니다. 로컬에서는 흠잡을 데가 없었습니다.

2.2 죽은 자리: 규칙 한 줄

채점 엔진의 다른 파일에는 이 코드가 있었습니다.

1
2
3
# api: 대회 모드
if scorecard.competition_mode and scorecard.has_environment(game_id):
    return None, False

대회 모드는 같은 게임 ID의 두 번째 런을 거부합니다. max를 취할 두 번째 플레이 자체를 만들 수 없습니다. max(run.score for run in self.runs)는 참이지만, 대회에서 self.runs의 길이는 언제나 1입니다. 수학은 완벽했고, 전제 하나가 거짓이었습니다.

덧붙이면, 제가 기반으로 쓰는 공개 포크에도 같은 계열의 win-then-replay 장치가 들어 있습니다. 마찬가지로 대회 모드에서는 영원히 잠자는 코드입니다. 이 포크를 복제해 돌리는 팀이 수백인데, 이 사실을 아는 팀이 몇이나 될지 모르겠습니다. 모두가 같은 코드를 실행하지만 아무도 읽지 않는다는 것 — 나중에 이 관찰이 한 번 더 저를 도와줍니다.

2.3 부검에서 나온 두 번째 사망 원인

아이디어를 묻기 전에 부검을 했습니다. 만약 재생이 허용됐더라도, 이 장치는 절반의 게임에서 배신당했을 것입니다. 제 런 로그에서 같은 (보드, 액션) 쌍이 두 번 이상 실행된 사례 760건을 전수 대조했더니 270건(35.5%)이 서로 다른 다음 상태를 냈습니다. 게임별로 0%인 것도, 57%인 것도 있습니다. 화면에 보이지 않는 타이머와 애니메이션 위상이 있다는 뜻입니다. “같은 화면 + 같은 액션 = 같은 결과”라는 전제 위에 세운 모든 캐시는 이 지점에서 확률적으로 무너집니다.

규칙 한 줄이 못 죽였어도 측정이 죽였을 아이디어였습니다. 순서만 달랐을 뿐입니다.

3. 운인가 실력인가: 추첨으로는 못 메꾸는 격차

죽은 아이디어를 묻고 나니 원래 질문이 남았습니다. 0.9와 1.5의 격차는 무엇인가.

재제출은 통계로 보면 매번 새로 뽑는 독립 추첨입니다(서빙 온도 0.6, 시드 무작위). 리더보드는 최고 기록만 남기므로, 총점의 시행 표준편차를 $\sigma$라 하면 $N$번 제출의 기대 최고값은 근사적으로

\[\mathbb{E}\!\left[\max_{i \le N} S_i\right] \approx \mu + \sigma\, a_N, \qquad a_{10} \approx 1.5,\quad a_{24} \approx 1.9,\quad a_{60} \approx 2.2\]

입니다. 그러니 관건은 $\sigma$의 크기입니다.

여기서 제 네 표본이 증거가 됩니다. 게임 하나의 점수는 시행마다 수십 배씩 튑니다(같은 게임 세 번에 0.583 / 0.444 / 0.015를 받은 적이 있습니다). 하지만 총점은 110개 런의 평균이라 중심극한정리가 분산을 눌러 줍니다. 만약 $\sigma = 0.176$이었다면 표본 셋이 폭 0.07 안에 모일 확률은 약 4%. 관측과 맞는 값은 $\sigma \approx 0.05\sim0.10$입니다.

이걸 대입하면 결론이 나옵니다. $\mu = 0.89,\ \sigma = 0.10$일 때 24번을 내도 기대 최고값은 1.08입니다. 그런데 현재 2위는 일곱 번 제출로 1.69입니다. 위쪽은 추첨을 잘한 게 아니라 평균 $\mu$ 자체가 다릅니다. 제출 슬롯을 복권처럼 긁는 전략의 기대 이득은 $\sigma(a_N - a_4) \approx 0.05\sim0.15$점이 상한 — 파던 걸 멈추고 $\mu$를 올릴 방법을 찾아야 했습니다.

4. 측정 지점이 틀렸다: 토큰 기근의 발견

$\mu$를 올리려면 병목을 알아야 하고, 병목을 알려면 측정이 맞아야 합니다. 그런데 여기서 가장 부끄러운 발견이 나왔습니다.

대회에 동봉된 실행 프레임워크 소스에는 채점 런의 구조가 그대로 적혀 있습니다. 히든 평가는 110개의 독립 런이고(같은 원본 게임의 클론이 여럿 포함됩니다), 한 번에 28개씩 돌아가며, 런 하나의 벽시계 상한은 7,920초입니다. 계산해 보면:

\[\underbrace{\left\lceil \tfrac{110}{28} \right\rceil}_{4\ \text{waves}} \times 7{,}920\,\text{s} = 31{,}680\,\text{s} \approx 9\,\text{h}, \qquad 7{,}920 = \tfrac{32{,}400}{4} - 180.\]

게임당 상한 7,920초는 임의의 수가 아니라 9시간 예산을 정확히 4웨이브로 나눈 값입니다. 예산은 이미 꽉 차 있습니다.

진짜 함의는 그 다음입니다. GPU 한 장을 런 28개가 나눠 쓰므로, 런이 실제로 받는 자원은 시간이 아니라 토큰입니다. 대회와 같은 조건(클론 28런, 대회 모드, 기준값 숨김)을 로컬에서 재현해 실측하니:

\[\text{tokens/run} \approx \frac{204\ \text{tok/s} \times 7{,}920\ \text{s}}{28} \approx 5.8 \times 10^{4},\]

런당 5~6만 토큰, 액션으로 약 30~150개였습니다. 그런데 저는 그동안 오프라인 4게임짜리 커밋(런당 19만 토큰)으로 에이전트를 관찰하고 있었습니다. 토큰이 세 배는 넉넉한 환경에서요. 그 환경에서 보이던 병목 — 한 레벨에서 900액션씩 태우는 배회 — 은 채점 환경에서는 일어날 시간조차 없는 현상이었습니다. 채점 환경의 실측은 오히려 이랬습니다: 28런 중 13런(46%)이 레벨 1을 깨는데, 그것도 8~38액션으로 꽤 싸게 깹니다. 대신 아무도 레벨 2에 못 갑니다. 문제는 낭비가 아니라 깊이였습니다.

이 발견 이후 커밋 파이프라인을 대회 시뮬레이터로 교체했습니다. 채점되는 곳과 측정하는 곳이 일치하지 않으면, 그 위의 모든 A/B는 소음입니다.

5. v6: 규칙이 남긴 여백 하나, 아무도 안 본 버그 하나

죽은 아이디어의 잔해에서 두 가지를 건졌습니다. 이번 주에 제출한 버전(v6)의 내용입니다.

5.1 클론 간 전이 — 재생 금지 규칙의 합법적 우회로

같은 게임을 두 번 플레이할 수는 없습니다. 하지만 채점 런에는 같은 원본 게임의 클론이 여럿 있고, 클론은 서로 다른 게임 ID라 재실행 금지에 걸리지 않습니다. 그렇다면 경험을 시간축이 아니라 클론축으로 옮기면 됩니다.

  • 한 가족의 첫 클론(정찰조)이 레벨을 깰 때마다, 낭비를 걷어낸 액션 세그먼트를 프로세스 전역 저장소에 발행합니다.
  • 형제 클론은 자기의 (유일한) 런에서 그 세그먼트를 스텝 단위로 검증하며 재생합니다. 첫 발산에서 중단하고 정상 루프로 복귀하므로, 2.3의 비결정성 게임에서는 알아서 일찍 꺼집니다.
  • 스케줄러가 가족마다 정찰조를 먼저 내보냅니다.

이 장치의 뼈대는 제가 쓰는 공개 포크에 이미 있었습니다. 켜져 있지 않았을 뿐입니다. 2.2의 관찰이 여기서 되돌아옵니다 — 수백 팀이 이 코드를 복제해 돌리면서, 안에 잠든 레버를 켠 팀은 거의 없습니다. 복제가 값싼 대회일수록, 코드를 실제로 읽는 행위의 상대 가치는 올라갑니다.

5.2 한 번도 작동한 적 없는 기억 장치

하네스에는 컨텍스트 축출에서 살아남는 장기 기억이 설계되어 있습니다. 매 턴 모델에게 World model:, Plan: 같은 라벨 노트를 쓰게 하고, 응답에서 수확해 다음 턴에 “이전 턴에서 가져온 world model”로 재주입하는 구조입니다. 그런데 수확 코드는 응답의 content 필드만 읽습니다. 추론형 서빙 스택은 모델 출력을 전부 reasoning 필드에 넣고 content를 비워 보냅니다. 제 로그에서 465개 응답 중 465개가 content 0자 — 이 기억 장치는 출시 후 한 번도 작동한 적이 없습니다.

고치는 것 자체는 패치 한 곳입니다. 응답이 지나가는 단일 관문에서, content가 비어 있고 reasoning에 라벨 노트가 있으면 그 라벨 줄만 올려 줍니다. 다만 구현 후 적대적 리뷰에서 함정이 하나 잡혔습니다. 라벨 파서가 탐욕적이라 라벨 없는 후속 줄을 계속 이어 붙이는 바람에, Plan: 뒤의 사고 사슬 1,709자가 통째로 “계획”으로 수확될 뻔했습니다. 매 턴 프롬프트에 2KB 잡음을 주입하는 “버그 수정”이 될 뻔한 거죠. 키당 280자 캡으로 눌렀습니다.

이 수리가 헛수고가 아니라는 외부 근거도 마침 나왔습니다. OpenAI가 7월 29일 발표한 바로는, 공식 평가 하네스가 매 수마다 추론을 버리고 히스토리를 잘라내던 것을 “추론 유지 + 요약 압축” 설정 2개로 바꾸자 GPT-5.6 Sol의 공개셋 점수가 13.3%에서 38.3%로 뛰었습니다. 가중치는 그대로였습니다. 이 벤치마크의 병목이 모델 크기가 아니라 기억의 연속성이라는, 우리가 로그에서 본 것과 같은 이야기입니다.

6. 앞으로 어디를 파는가: 논리로 유도한 계획

여기서부터가 이 글을 쓴 진짜 이유입니다. 남은 8주(Milestone #2가 9월 30일입니다)를 어디에 쓸지, 감이 아니라 점수 구조에서 유도해 보겠습니다.

6.1 목표 함수부터: σ가 아니라 μ

3장의 결론을 다시 씁니다. 재제출의 기대 이득은 $\sigma(a_N-a_4) \le 0.15$점. 반면 상위권과의 격차는 0.5~0.9점입니다. σ를 수확하는 모든 활동은 이제 가치가 없고, μ를 올리는 활동만 가치가 있습니다. 제출은 가설 검증의 마지막 단계로만 씁니다.

6.2 점수를 분해하면 우선순위가 나온다

게임 하나의 점수는 레벨 가중 평균입니다. $n$레벨 게임에서 레벨 $\ell$의 가중치는 $\ell / \sum_{k=1}^{n} k$. 전형적인 $n=7$이면 분모가 28이라, 레벨 1을 사람 효율로 완벽하게 깨도 그 게임 점수는 $1/28 \approx 3.6\%$입니다. 레벨 2는 그 두 배인 7.1%를 더 얹어 줍니다.

이 산수에 4장의 실측(레벨 1 클리어율 46%, 레벨 2 도달 0%)을 넣으면 지금 리더보드가 통째로 설명됩니다. 대충 근사하면:

\[S \approx 100 \times \mathbb{E}_{\text{games}}\!\left[ \frac{p_1 \cdot s_1 \cdot 1 + p_2 \cdot s_2 \cdot 2 + \cdots}{\sum_\ell \ell} \right].\]
  • 우리 현재: $p_1 \approx 0.46$, $s_1$은 들쭉날쭉, $p_2 \approx 0$ → 총점 ~0.9. 계산과 맞습니다.
  • 모든 게임에서 L1만 사람 효율로 깨면 ($p_1 = 1, s_1 = 1$): 게임당 $1/\Sigma\ell \approx 3\sim5\%$ → 총점 ~3.5. 현재 1위(1.86)의 거의 두 배입니다.
  • L2까지 절반쯤 가면 총점 ~5~6.

즉 지금 이 대회의 프런티어는 이국적인 기술이 아니라 “레벨 1을 어디서나 싸게 깨고, 가끔 레벨 2에 간다” 수준에 있습니다. 여기서 한계 이득의 순서가 나옵니다: ① L1 클리어율(46%→그 이상), ② L1 효율, ③ L2 도달 — 그리고 ③의 가중치가 ①의 두 배라는 사실이 토큰 기근과 맞물리면서 아래 우선순위가 나옵니다.

6.3 세 갈래, 그리고 이 순서인 이유

런당 예산이 ~100액션이라는 제약 아래에서, 위 세 한계 이득을 올릴 수 있는 갈래는 셋뿐이라고 봅니다.

갈래 1: 기억의 연속성 (지금 하는 것). L1 클리어 실패의 주범은 지식 부족이 아니라 지식 휘발입니다 — 모델이 알아낸 규칙이 축출과 함께 사라지고, 남은 예산으로 같은 걸 다시 알아냅니다. 죽은 채널 복구(5.2)가 1차 수리이고, 다음 단계는 축출 자체를 요약 압축으로 바꾸는 것입니다. 근거: Sol의 3배(외부), 우리 로그의 465/465(내부). 비용: 낮음, 하네스 패치 수준. 검증: 시뮬레이터에서 “carried world model” 블록의 내용과 L1 클리어율 변화를 직접 봅니다.

갈래 2: 클론 간 전이 (지금 하는 것). L2 도달의 병목은 능력이 아니라 예산입니다 — L1을 깨는 데 예산 대부분이 나갑니다. 정찰조의 세그먼트를 형제가 재생하면, 형제의 5~6만 토큰이 통째로 L2 예산이 됩니다. 가중치 2배 구간에 예산을 이전하는 구조라, 6.2의 산수에서 한계 이득이 가장 큽니다. 근거: 오프라인 검증에서 발행 세그먼트 5개를 새 인스턴스에 재생해 5/5 성공. 리스크: 히든셋에서 클론 지문이 안 맞으면 전체가 no-op으로 강등 — 하방 위험이 0이 되도록 설계된 걸 확인했습니다. 검증: 시뮬레이터의 발행/채택 이벤트와 L2 도달 분포.

갈래 3: 토큰 처리량 (대기 중). 토큰 기근에서는 초당 토큰이 곧 “런이 할 수 있는 생각의 총량”입니다. 같은 모델의 Blackwell 네이티브 4비트(NVFP4) 가중치가 공개되면 처리량이 의미 있게 오를 수 있습니다. 다만 품질 손실과의 교환이라 실측 없이는 못 갑니다. 트리거 조건(공개 가중치 등장)을 정해 두고 감시만 합니다.

순서의 논리를 요약하면: 갈래 1·2는 지금 가진 것의 수리와 재배치라 비용이 낮고 검증이 빠르며, 서로 곱해집니다 (기억이 좋아지면 정찰조가 더 잘 깨고, 정찰조가 잘 깨면 전이할 게 많아집니다). 갈래 3은 곱셈 계수지만 트리거가 외부에 있습니다.

6.4 버리는 것들, 그리고 이유

계획에서 뺀 것도 이유와 함께 적어 둡니다.

버린 것이유
재제출 추첨$\sigma \approx 0.05\sim0.10$. 기대 이득 상한 0.15점 (6.1).
재생 은행킹 계열 전부대회 모드가 두 번째 런을 거부 (2.2). 규칙이 바뀌지 않는 한 재론 없음.
순진한 전이 캐시보이는 상태의 35.5%가 비결정 (2.3). 쓰려면 애니메이션 시그니처가 선행돼야 함.
컨텍스트 윈도 확장KV 캐시가 28런 × 32k 컨텍스트로 이미 5배 초과예약 상태. 늘리면 처리량이 죽음.
더 큰 모델같은 이유. 토큰 기근에서 파라미터와 처리량은 교환 관계.
4게임 오프라인 커밋에서의 튜닝채점 환경과 토큰이 3배 다른 조건 (4장). 측정이 아니라 소음.

6.5 일정 (M2 역산)

  • 지금~1주: v6 실측. 시뮬레이터와 제출 결과에서 전이 발행/채택률, 기억 채널의 실제 내용, L1 클리어율·L2 도달 분포를 읽습니다. 이번 커밋에서 정찰조의 세그먼트 발행 10건이 처음 관측됐습니다.
  • 2~4주: 갈래 1 심화(축출→압축), 갈래 2 변형(비결정 가족에는 액션 대신 배운 규칙을 텍스트로 넘기는 전이). 각 변형은 시뮬레이터 A/B를 통과해야 제출됩니다.
  • 5~7주: 실측이 지지하는 조합으로 수렴, NVFP4 트리거 감시, 공개 게임 궤적으로 소형 액션 프라이어 증류 실험.
  • 8주차: 동결. M2 마감 직전에는 새 아이디어를 넣지 않습니다. 1편에서 적었던 원칙 그대로입니다.

7. 교훈 세 줄

여섯 주를 세 줄로 압축하면 이렇습니다.

  1. 파이프라인부터 검증하라. 사고 두 건은 아이디어가 아니라 배관에서 났고, 조용한 페일세이프가 그것을 숨겼습니다.
  2. 수학이 완벽해도 전제는 규칙이 정한다. 채점 엔진의 한 줄이 무결한 설계를 무효로 만들었고, 다른 구조(클론)가 합법적 대체로를 열어 줬습니다. 리더보드가 아니라 시스템을 읽어야 했습니다.
  3. 측정 지점이 틀리면 그 위의 모든 것이 틀린다. 채점되는 곳(토큰 기근, 110런, 클론)과 측정하는 곳을 일치시키고 나서야, 무엇이 병목인지(낭비가 아니라 깊이) 처음 보였습니다.

다음 글은 아마 전이와 기억 채널의 실측 결과가 될 겁니다. 숫자가 어느 쪽으로 나오든 기록하겠습니다.


Resources

This post is licensed under CC BY 4.0 by the author.