사후 분석: 터미널 벤치 챌린지 - WASM 렌더러
요약
Favur는 Terminal-Bench의 WebGL 렌더러를 구현하기 위해 296시간을 투자하여, 에이전트가 그래픽 드라이버 수준의 핵심 기능을 직접 구축하는 과정을 보여주었습니다. 이 과정에서 상태 계층, 셰이더 컴파일러/인터프리터, 레이트라이저 등 주요 서브시스템을 성공적으로 구현했습니다. 다만, 테스트 통과 건수는 늘었으나 실제 내부 규격 준수율은 여전히 낮은 수준에 머물렀으며, 이는 에이전트가 코드를 조작한 것이 아닌 실제 버그를 포착했음을 의미합니다.
핵심 포인트
- WebGL 렌더러 구현을 위해 상태 계층, 셰이더 컴파일러, 레이트라이저 등 핵심 서브시스템 구축.
- 에이전트들이 그래픽 드라이버의 내부 작동 원리(API state machine)를 직접 코드로 재현해야 함.
- 총 296시간의 작업 끝에 로컬 테스트 통과 건수는 크게 증가했으나, 규격 준수율은 여전히 과제임.
우리 에이전트의 테스트는 64개 통과에서 1,334개로 증가했지만, 렌더러는 계속 작동하지 않았습니다. 다섯 가지 체크가 통과되었지만, 그것은 잘못된 것을 증명했습니다.
Favur는 터미널-벤치(Terminal-Bench)의 WebGL 렌더러를 구현하기 위해 296시간을 투자했습니다. 그 결과, 로컬 테스트 통과 건수는 64개에서 1,334개로 증가했지만, 마지막 내부 규격 준수 결과는 WebGL1 케이스 672개 중 13개, 그리고 WebGL2 케이스 2,598개 중 20개에 머물렀습니다. 에이전트들이 테스트를 조작한 것이 아니었습니다. 코드 리뷰가 실제 버그를 포착했고, 수리된 부분은 여전히 재현되었으며, 소스 코드를 새로 빌드하면 자체 셰이더 컴파일러와 레이트라이저(rasterizer)를 통해 삼각형을 그릴 수 있었습니다.
문제의 핵심은 코드 주변의 체크들에서 발생했습니다. 저희는 이 실행 과정에 대한 전체 사후 분석 보고서를 작성했으며, 링크는 마지막에 첨부되어 있습니다. 본 기사에서는 이번 실행이 무엇을 구축했는지, 무엇을 그릴 수 있는지, 어떤 부분이 작동했고, 그리고 다른 것을 증명하면서 통과했던 다섯 가지 체크에 대해 다룹니다. 장시간 작업을 위해 에이전트를 돌리는 사람이라면 아마도 같은 다섯 가지를 가지고 있을 것입니다.
작업 개요
작업은 터미널-벤치(Terminal-Bench)의 WASM WebGL 렌더러 챌린지입니다. 터미널-벤치 챌린지는 에이전트에게 시간 제한 없이, 누군가의 도움 없이 처음부터 전체 코드베이스를 구축하도록 요청하는 단일 작업들입니다. 저희가 만든 것이 아닙니다. 이 챌린지는 WebGL1 및 WebGL2 프로그램을 실행하는 렌더러를 요구하며, 이는 아무것도 없는 상태에서 시작해야 합니다. GPU나 브라우저 자체의 그래픽 코드를 사용할 수 없다는 의미였습니다. 즉, 에이전트들은 일반적으로 그래픽 드라이버가 숨기고 있는 부분들, 즉 API 상태 머신(API state machine), 셰이더 프로그램용 컴파일러 및 인터프리터, 그리고 삼각형을 픽셀로 변환하는 레이트라이저를 직접 작성해야 했습니다.
Favur는 역할을 분담했습니다. 하나의 모델은 아키텍처를 매핑했습니다. GLM 5.3이 조율하고, 스프린트를 계획하며, 구현을 관리하고, 각 스프린트를 계획과 비교하여 검토했습니다. Muse Spark 1.3 Contributor가 코드를 작성하고, 이를 검토했으며, 빌드, 테스트 및 플랫폼 작업을 처리했습니다. Gemini 3.8 Flash는 의사 코드(pseudocode)를 작성하고 에이전트의 진행 상황을 관찰했습니다. Grok 4.6은 독립적인 비평가 역할을 했습니다.
기록된 시간은 9개 세션에 걸쳐 총 296 벽시계 시간(wall-clock hours)이며, 유휴 및 정지 구간을 제외한 실제 작업 시간만으로 약 119시간에 달합니다. 이 과정은 네 번째 스프린트까지 진행되었습니다.
스프린트 8이 되자 소스 코드는 세 가지 주요 서브시스템인 상태 계층(state layer), 셰이더 컴파일러 및 인터프리터(shader compiler and interpreter), 그리고 래스터라이저(rasterizer)를 모두 갖추게 되었습니다. 그 이후부터 로컬 테스트 건수는 꾸준히 증가하여, 스프린트 1의 64개 통과 기록에서 스프린트 13에는 1,334개로 늘어났습니다.


이 1,334개는 에이전트들이 작성한 로컬 단언(local assertions)입니다. 이는 컨포먼스 스위트(conformance suite)와는 다른 개념이며, 이 둘 사이의 거리가 본 기사에서 다루고자 하는 핵심 내용입니다.
구현할 수 있는 것 (What it can draw)
사후 분석을 위해 포착된 소스를 새로 재구축하고 자체 제작한 작은 프로그램들로 구동해 보았습니다. 이것이 첫 번째 테스트 결과입니다.

이것은 단순한 빨간색 삼각형이며, 그 뒤에 있는 모든 단계가 실제 작동함을 보여줍니다. 에이전트의 컴파일러에 의해 버텍스 셰이더(vertex shader)와 프래그먼트 셰이더(fragment shader)가 컴파일되고 연결되었습니다. 모서리는 속성 버퍼(attribute buffer)에서 가져왔습니다. 드로우 콜(draw call)은 래스터라이저를 거쳤고, 픽셀들이 읽혀 나갔습니다. 어떤 지름길도 사용되지 않았습니다.
세 개의 프로브가 동일한 방식으로 작동하여 올바른 픽셀들을 반환했습니다.
- 행렬에 벡터를 곱하고 첫 번째 성분을 읽는 셰이더는 완전한 알파 값을 가진 예상되는 빨간색을 반환합니다.
- 음의 제로(negative zero)로 나누고 매우 작은 숫자를 처리하는 셰이더는 그래픽 오류 없이 예상되는 색상을 제공합니다.
- 압축된 텍스처 형식 목록에 대한 질의는 빈 typed array를 반환하며, 이는 호출자가 아무것도 없을 때 필요한 값입니다.
한 프로브는 작동하는 것의 경계를 보여줍니다. 첫 번째 프로브가 필드 이름으로 읽었던 동일한 행렬 곱을 인덱스로 읽어도 여전히 다른 색상 채널들이 손상됩니다. 삼각형과 프로브들은 작은 WebGL1 경로가 작동함을 보여줍니다. 이는 완성된 렌더러를 보여주기에는 아직 거리가 있습니다.
잘 작동했던 부분
의미를 확인한 리뷰. Sprint 8에서 한 코드 리뷰어가 렌더러가 배열 내 다음 행렬로 호출자들에게 크기에 관계없이 16바이트 건너뛰라고 알려주는 것을 발견했습니다. 더 큰 행렬의 경우 값들이 겹치게 됩니다. 이 리뷰어는 이를
사소한 숫자 처리. 또 다른 코드 에이전트가 나눗셈에서 0으로 나누는 값의 부호가 손실되는 것을 발견하고, 이를 수정하여 쉐이딩 언어(shading language)가 요구하는 대로 1을 음수 0으로 나누면 음의 무한대(-infinity)를 반환하도록 했습니다.
증명과 함께 이루어진 플랫폼 개선. 지난 세션에서 한 플랫폼 에이전트가 가리키는 폴더 자체는 정상임에도 불구하고 열리지 않는 두 개의 폴더 링크를 발견했습니다. 이 에이전트는 이를 상대 경로(relative links)로 재구축하고 동일한 검사를 다시 실행하여 수정 사항이 적용되었음을 보여주었습니다. 새로운 읽기 전용(read-only) 검사도 여전히 통과합니다.
누락된 작업을 포착한 리뷰. 스프린트 리뷰는 한 스프린트의 주장과 실제 존재하는 것을 비교했고, 중앙 집중식 수정 사항들이 전혀 반영되지 않았음을 발견했습니다. 이들은 다시 반환되었고, 이후 작업이 완료되었습니다.
솔직한 마지막 보고서. 워크플로우가 더 이상 유효한 이동(legal moves)을 할 수 없게 되었을 때, 오케스트레이터(orchestrator)는 미완료된 작업을 '완료'로 호출하지 않았습니다. 마지막 기록은
직접 확인해 보세요. 각 기능에 대해, 호출자(caller)가 진입하는 방식과 동일하게 진입하는 테스트를 하나 찾아보세요. 만약 모든 테스트가 내부 객체(inner object)를 수동으로 구성한다면, 연결(wiring) 부분이 테스트되지 않은 것이고 에이전트들(agents)은 내부 객체를 통과시키는 데 매우 능숙합니다.
확인 2. 빨간 숫자 주위에 초록색 포장지
WebGL2 규격 준수 검사기(conformance wrapper)는 실행이 충돌하지 않았는지, 결과가 기록되었는지, 그리고 두 번의 실행이 일치하는지를 확인했습니다. 이 검사는 규격 준수 숫자가 특정 값에 도달해야 한다는 요구 사항은 없었습니다. 2,598개 중 20개에서 초록색 포장지가 발견되었습니다.
이는 우연히 작성하기 가장 쉬운 부분입니다.
방향에 대한 동일한 요청은 한 무리의 수정 사항들이 추가 테스트를 실행하지 않았다고 말했고, 이는 목표가 희망 없어 보이게 만들었습니다. 3시간 후 스프린트 리뷰에서 그 물결의 핵심 수정 사항들 중 어느 것도 적용되지 않았다는 것을 발견했습니다. 계획서에는 존재하지 않는 커밋과 회귀 파일들이 있었습니다.
테스트 카운트는 정확했습니다. 그것들은 프로그램이 실제로 어떤 상태인지를 설명했을 뿐입니다. 수정 사항들에 대해서는 아무것도 말하지 않았는데, 왜냐하면 그 수정 사항들이 거기에 없었기 때문입니다. 계획은 아직 실행되지 않은 실험의 힘만으로 이미 변경되어 있었습니다.
직접 확인해 보세요. 누군가 '이전'과 '이후'를 읽기 전에, 보고서에 세 가지를 보여주도록 하세요. 변화는 커밋이나 파일 형태로 존재해야 합니다. 기준선(baseline)은 그 이전에 측정되었어야 하고, 두 번째 측정은 그 이후에 이루어져야 합니다.
체크 5. 점수가 아닌 제로 값
최종 외부 평가에서는 실행된 테스트가 0개이고 통과한 테스트가 0개라고 보고되었습니다. 빌드 도구가 Linux 종속성을 로드할 수 없었기 때문에, 테스트 러너는 렌더러에 도달하기 전에 중단되었습니다. 작업 공간은 Windows에서 빌드되어 그 안에 Windows 종속성을 가진 Linux 컨테이너에 마운트되었습니다.
0개 중 0개는 설정 실패이며, 코드에 대해서는 아무것도 알려주지 못합니다. 우리 자신의 실행에서도 같은 순간 정반대의 실수를 저질렀습니다. 오케스트레이터의 마지막 기록은 차단되었다고 했지만, 실행의 외부 상태는 여전히 완료되고 성공으로 표시되었습니다.
직접 확인해 보세요. '실행되지 않음(did not run)'에 자체적인 결과를 부여하고, 이를 '실행 후 실패' 및 '통과'와 분리하며, 심사할 플랫폼에서 종속성을 구축하세요.
핵심 목록
- 기능당 하나의 테스트는 공개 진입점을 통해 들어가야 합니다.
- 헤드라인 숫자에 대한 테스트는 그 숫자가 낮을 때 실패합니다.
- 결정은 누가 답변했는지 이름을 유지해야 합니다.
- 이전과 이후를 보여주는 것은 변화가 존재함을 보여줍니다.
- '실행되지 않음'은 자체적인 결과여야 합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기