Repository navigation
테스트 자식의 console 을 stderr 로 돌려 러너 역직렬화 실패를 없앤다 - #57
Merged
Merged
Conversation
npm test 가 간헐적으로 assertion 이 아니라 러너 자체 오류로 실패했다
("Unable to deserialize cloned data due to invalid or unsupported version",
failureType=uncaughtException). 그 파일의 남은 테스트는 보고조차 되지 않는다.
원인은 Node 22 러너(internal/test_runner/runner.js #processRawBuffer)다. 자식의 stdout 은
직렬화된 이벤트 프레임과 console.log 출력이 섞여 흐르는데, 러너는 프레임 하나를 읽은 뒤 같은
청크의 나머지가 다음 프레임 헤더라고 가정하고 3~6번째 바이트를 길이로 읽는다. 로그가 한글이면
UTF-8 바이트(≥ 0x80)의 `<< 24` 가 음수가 되어 길이 검사를 통과하고 쓰레기를 역직렬화한다.
ASCII 로그는 길이가 수백 MB 로 읽혀 기다리다 다음 청크에서 복구되므로 안 터진다 — 이 레포는
로그가 거의 다 한글이라 runRound 를 도는 테스트에서 났다. 프레임과 로그가 한 청크로 합쳐질
때만(부모가 읽기 전에 두 write 가 쌓일 때) 나므로 간헐적이다.
- 실패 로그 직전 줄은 테스트 통과 프레임 바로 뒤의 " 대화 기록: ..." 이었다 (3번째 바이트
0xEB). 프레임 + 한글을 한 번에 write 하는 테스트로 결정적으로 재현되고, 같은 프레임 +
ASCII 는 통과한다.
- upstream 은 nodejs/node#64706(`>>> 0`, v24.x 반영)·#66273 으로 고쳤지만 v22.x 에는 없다.
테스트마다 console 을 mock 하지 않는다 — 자식 stdout 에서 프레임을 걷어내 보면 프레임 사이에
로그를 흘리는 파일이 7개(8,982B, review-boundaries 6,243B)였고, 한글 로그를 남기는 새 테스트가
생길 때마다 재발한다.
npm test 가 tests/stdout-guard.ts 를 --import 로 싣고, 테스트 자식(NODE_TEST_CONTEXT=child-v8)
에서 console 을 stderr 로 보내는 Console 로 바꾼다. stderr 는 러너가 줄 단위로만 읽고 파싱하지
않는다. 출력은 그대로 남고 assertion 은 손대지 않았다. 가드 없이 실행하면
stdout-guard.test.ts 가 실행 방법을 알리며 결정적으로 실패한다.
lpaiu-cs
commented
Oct 3, 2026
lpaiu-cs
left a comment
Owner
Author
There was a problem hiding this comment.
gpt-chat-pr-reviewer 1차 리뷰
이 리뷰는 자동화 봇에 의한 gpt 리뷰이며, 사용자 의견이나 판단을 담지 않습니다.
추론 모델: Latest · Pro (5/5)
판정: ✅ approve — 지적 사항 없음
지정된 head와 merge-base를 확인하고 고정 diff의 4개 파일 전체를 검토했습니다. 이번 변경으로 새로 발생하거나 악화되는 구체적인 버그·보안·성능 문제는 발견하지 못했습니다. Node.js 22.16.0에서 추가된 회귀 테스트를 --experimental-strip-types로 별도 실행하여 가드 적용 시 통과하고 미적용 시 의도한 assertion으로 실패함을 확인했습니다. 일반 프로세스에서는 기존 console이 유지되는 것도 확인했습니다. 실제 tsx 기반 npm test 전체와 다른 실행 환경은 검증하지 않았습니다.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
문제
npm test가 간헐적으로 assertion 이 아니라 러너 자체 오류로 실패했다.그 파일의 남은 테스트는 보고조차 되지 않는다 (137개 → 126·130개). 같은 파일만 다시 돌리면 통과한다.
원인 — Node 22 러너의 stdout 프레임 파서
node --test의 자식 프로세스는 stdout 으로 v8 직렬화 프레임([FF 0F][u32 길이][본문])을 보내고, 테스트 대상 코드의console.log도 같은 stdout 으로 섞여 나간다. 부모의#processRawBuffer는 프레임 하나를 읽은 뒤 같은 청크의 나머지가 다음 프레임 헤더라고 가정하고 3~6번째 바이트를 길이로 읽는다 (헤더 재탐색 없음).<< 24가 int32 음수가 되어rawBufferSize < fullMessageSize검사를 통과하고, 쓰레기를 역직렬화하다readHeader()에서 던진다.근거
대화 기록: https://chatgpt.com/c/fixture였다. 3번째 바이트가대의 선두 바이트0xEB다.process.stdout.write로 내보내는 테스트 파일은 매번 같은 오류로 실패하고, 같은 프레임 + ASCII 는 통과한다.NODE_TEST_CONTEXT=child-v8)로 돌려 stdout 에서 프레임을 걷어내면, 프레임 사이에 로그를 흘리는 파일이 7개 · 8,982B 였다 (review-boundaries 6,243B · chatgpt-send 852B · response-progress 743B · account-switch 614B · project-entry 365B · concurrency 105B · duplicate 60B). review-boundaries 만의 문제가 아니다.>>> 0)으로 고쳐졌고 v24.x 에는 들어갔지만 v22.x 브랜치에는 없다 (main 은 test_runner: do not crash on stdout that mimics a v8 frame nodejs/node#66273 으로 헤더 재탐색까지 넣었다).engines가>=20이라 Node 업그레이드로 풀 수 없다.변경
테스트마다
t.mock.method(console, 'log', ...)를 붙이지 않았다 — 위험한 파일이 7개였고, 한글 로그를 남기는 테스트가 새로 생길 때마다 재발한다. 모든 테스트 자식이 지나는 한 곳에서 막는다.tests/stdout-guard.ts— 테스트 자식(NODE_TEST_CONTEXT === 'child-v8')에서만 전역console을 stderr 로 쓰는Console로 바꾼다. 러너는 stderr 를readline으로 줄 단위로만 읽고 파싱하지 않으므로 안전하다. stdout 은 프레임 전용이 된다. 부모 러너 프로세스는 건드리지 않는다.package.json—npm test가 이 파일을--import로 싣는다 (러너가--test*외의 execArgv 를 자식에 그대로 넘긴다).tests/stdout-guard.test.ts— 자식의console.log가 stdout 에 닿지 않는지 확인한다. 가드 없이tsx --test를 직접 부르면 간헐적 실패 대신 이 테스트가 실행 방법을 알리며 결정적으로 실패한다.AGENTS.md빌드 명령 목록에npm test를 적었다.로그는 없애지 않고 stderr 로 그대로 나온다. 기존 테스트·assertion 은 손대지 않았다.
검증
npx tsx --test(전체)npm test(전체, 연속)stdout-guard.test.ts실패 / 가드와 함께 통과를 둘 다 확인했다.tsc --noEmit통과 ·npm run smoke339 passed ·npm test138 passed ·git diff --check통과.테스트 인프라만 바뀌므로 데몬 재시작은 필요 없다.