fix: 출력이 64KB를 넘을 수 있는 나머지 git 호출도 Bun.spawn 헬퍼로 읽는다 - #78
Merged
Merged
Conversation
Bun 1.3.x의 `$`는 64KB를 넘는 stdout을 받는 호출에서 promise가 영영 settle하지 않을 수 있다(업스트림은 1.4.0에서 수정). #74·#77이 `showBytes`와 `summary.ts`를 `gitOutput.ts` 헬퍼로 옮긴 뒤에도 큰 출력을 받는 `$`가 넷 남아 있었다: - 지문의 `status --porcelain -z -uall` — watch가 2초마다 부른다 - `getDiffFiles`의 `diff --name-status` (큰 diff) - `getDiffFiles`의 `ls-files --others` (untracked 켜짐) - `refs.ts`의 `for-each-ref` (원격 브랜치가 많은 리포) 넷 다 `gitText`로 옮긴다. 이로써 서버에 남은 `$`는 `rev-parse`· `merge-base`·`gh pr view`·`worktree list`처럼 출력이 작은 호출뿐이다. 자가 치유 3부품(flight 타임아웃·503·재시도)은 원인을 가리지 않는 안전망이라 그대로 둔다. 회귀망 `git-large-output.test.ts`는 호출처마다 그 함수를 8번 동시에 불러 출력을 겹치게 만든다(동시 호출은 실제로 일어난다 — 선택이 다른 요청, prewarm, watch 폴). Bun 1.3.12에서 수정 전 코드는 4/4 실패, 수정 후 4/4 통과. 호출을 하나씩 되돌리는 뮤테이션으로 판별력을 쟀다: 지문· name-status·ls-files는 각 3/3 잡히지만 for-each-ref는 좁은 구간에서만 확률적으로 멈춰 20라운드로도 5번 중 3번만 잡힌다 — 테스트와 CLAUDE.md에 그대로 적었다. 행업 단언은 1.3.x에서만 갈리므로 CI `test-bun13` 잡에 이 파일을 더한다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XAe9zh6siLHSR4nPpqm8QK
- for-each-ref 케이스는 8-way에선 되돌린 코드를 20라운드로도 5번 중 3번만 잡았다. 그 케이스만 16-way로 올리자 첫 라운드에 11번 중 11번 잡는다 (1.3.12, macOS — 리뷰어 6/6 + 재현 5/5). 라운드는 20 → 5. - beforeAll에 60초 상한을 준다. 픽스처가 평소 1.2~1.8초인데 부하가 걸린 뮤테이션 실행에서 훅 기본 상한 5초를 넘어 무관한 이유로 실패한 것을 실측했다 — CI 러너에서도 날 수 있는 결함이다. - 테스트 상한을 라운드 수에 맞춰 케이스별로 계산한다. - refs.ts의 worktree list도 gitText로 옮긴다. 출력이 등록된 워크트리 수에 비례하고, 디렉토리가 지워져도 prunable로 등록이 남아 약 300개면 64KB를 넘는다. 다만 죽은 워크트리 400개(110KB)로 `$`를 8·16-way 10라운드씩 8번 돌려도 한 번도 안 멈춰 판별할 모양을 못 찾았으므로 회귀망은 두지 않고 그 사실을 적는다. 크기는 필요조건일 뿐이라는 것도 적는다. - 남은 `$`는 rev-parse·merge-base·gh pr view — 출력 크기가 리포 규모와 무관한 호출뿐이다. - CI 잡 주석의 "10초"(새 파일은 15초), git-output.test.ts docblock의 오해 소지 있는 문장을 고친다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XAe9zh6siLHSR4nPpqm8QK
Linux 러너에서 되돌린 코드로 test-bun13이 빨개지는 것을 확인했으므로 되돌린다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XAe9zh6siLHSR4nPpqm8QK
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.
왜
Bun 1.3.x의
$는 64KB를 넘는 stdout을 받는 호출에서 promise가 영영 settle하지 않을 수 있습니다(업스트림은 1.4.0에서 수정). #74·#77이showBytes와summary.ts를gitOutput.ts헬퍼(Bun.spawn)로 옮긴 뒤에도, 큰 출력을 받는$가 넷 남아 있었습니다.status --porcelain -z -uallgetDiffFiles의diff --name-statusgetDiffFiles의ls-files --othersrefs.ts의for-each-refrefs.ts의worktree list무엇을
gitText로 옮깁니다. 인자 배치와 동작(종료 코드 무시, stderr 버림)은 이전과 같습니다.$는rev-parse·merge-base·gh pr view— 출력 크기가 리포 규모와 무관한 호출뿐입니다.gh pr view는 네트워크를 기다립니다), 작은$가 원리적으로 안전하다는 증명은 없습니다.singleFlight.ts주석을 이 이유로 고쳤습니다.$가 남아 있다"는 서술을 현재 상태로 고쳤습니다.test-bun13잡에 새 회귀망을 더했습니다.TDD — RED를 어디에 걸었나
#77에서는
summary.ts의 멈춤이 매번 재현되지 않아 파일 자체를 지키는 테스트를 못 세웠습니다. 이번엔 "큰 출력이 겹치면 거의 확정"이라는 측정을 이용해, 호출처마다 그 함수를 8번 동시에 부르는git-large-output.test.ts를 세웠습니다. 동시 호출은 실제로 일어납니다(선택이 다른/api/diff요청, prewarm, watch 폴이 서로 다른 flight 키로 겹침).$로 되돌림):status -ualldiff --name-statusls-files케이스도 함께 죽음)ls-files --othersfor-each-reffor-each-ref케이스만 16-way입니다. 이 호출은 좁은 구간(8-way에서 참조 600800개 ≈ 180240KB)에서만 멈춰, 처음 8-way로는 20라운드를 돌려도 5번 중 3번만 잡혔습니다. 리뷰 지적대로 16-way로 겹침을 늘리자 첫 라운드에 11번 중 11번 잡혔습니다(macOS).worktree list는 옮겼지만 회귀 테스트가 없습니다. 죽은 워크트리 등록 400개로 110KB를 내게 해도$가 8·16-way로 10라운드씩 8번 동안 한 번도 멈추지 않아, 판별할 모양을 찾지 못했습니다. 멈춤은 출력 크기만으로 정해지지 않습니다(for-each-ref도 606KB에선 안 멈췄습니다). 이 사실은 테스트 docblock과 CLAUDE.md에 적었습니다.Linux에서의 RED (리뷰 Minor 1): 다섯 호출을 전부
$로 되돌린 임시 커밋e37d2e8을 올렸습니다 — run 35573797466에서test-bun13(Bun 1.3.14, ubuntu)이 4 pass / 4 fail로 빨개졌고(새 파일의 네 케이스가 전부 15초 타임아웃, 헬퍼 테스트 넷은 무관하므로 통과), 최신 Bun의test는 초록이었습니다.lint실패는 되돌린 커밋의 부산물(gitTextimport 미사용 2건)입니다. 곧바로 되돌렸습니다(9016a3e, 트리가8c61faa와 동일).리뷰: Critical 0 · Important 1 · Minor 6. 리뷰어가 RED 4/4·깨끗한 워크트리 8 pass·호출별 뮤테이션을 따로 재현했습니다. 반영 — Important 1(for-each-ref 16-way), Minor 1(Linux RED), 2(케이스별 테스트 상한), 3(docblock 문장), 4(CI 주석의 "10초"), 5(
worktree list). 반영 안 함 — Minor 6(settleWithin공용화, 선택 사항). 부수적으로beforeAll에 60초 상한을 줬습니다 — 픽스처가 평소 1.2~1.8초인데 부하가 걸린 실행에서 훅 기본 상한 5초를 넘는 것을 실측했습니다.테스트 플랜
bun test— 795 pass / 0 failbun run test:coverage— 100% 게이트 통과 (diff.ts·fingerprint.ts·refs.ts·gitOutput.ts모두 100)bun run lint·format:check·typecheck통과node_modules없는 깨끗한 워크트리에서 Bun 1.3.14로 세 파일 → 8 pass; 지문 호출을 되돌리면 그 케이스만 실패test-bun134 fail (run 35573797466)test-bun13: Bun 1.3.14, 8 pass)e2e flake 기록
최종 커밋(
9016a3e)의 e2e가 1·2차 시도에서worker-highlight.e2e.ts:30한 건으로 실패하고 3차에 통과했습니다. 원래 있던 불안정으로 판단한 근거:/api/refs200·15ms,/api/diff200,worker.js2건 200). 멈춘 곳은 브라우저 워커의 하이라이트이고, 스펙 주석도 이 폴의 원인을 "확정하지 못했다"고 적고 있습니다.다만 통과한 런에서 이 스펙은 10~12초로 한계와 거리가 멀고, 과거 빈도(약 60런 중 3번)로는 두 번 연속 실패가 드문 일이라 이 변경이 확률을 올렸을 가능성을 완전히 배제하지는 못합니다 — 서버의 git 호출 방식이 브라우저 워커를 막을 경로는 찾지 못했습니다. 이 flake 자체는 별도로 조사할 가치가 있습니다.
🤖 Generated with Claude Code
https://claude.ai/code/session_01XAe9zh6siLHSR4nPpqm8QK