fix: summary.ts의 git 호출도 $ 대신 Bun.spawn 헬퍼로 읽는다 - #77
Merged
Merged
Conversation
#74는 showBytes만 Bun.spawn으로 옮겼다. `summary.ts`(빈 상태 카드·자동 base
전환의 요약)는 flight 밖이라 타임아웃도 503도 재시도도 닿지 않는데, 출력이
64KB를 넘을 수 있는 `$`(diff --name-only, ls-files --others)가 그대로였다.
Bun 1.3.x에서 그 경로가 실제로 걸리는 것을 확인했다(변경 10k 파일 = name-only
437KB 출력에서 순차 호출 18번째에 행업). 빈도는 낮지만 걸리면 요약이 영영
안 온다.
- server/gitOutput.ts(신규): gitBytes(args)/gitText(args). showBytes에 있던
Bun.spawn 패턴과 근거·동작 계약(종료 코드 무시, 스폰 실패는 throw, stdout을
다 비운 뒤 exited)을 한 곳으로 옮긴다. 호출처가 둘이 된 시점이다.
- showBytes는 gitBytes를, summary.ts는 여섯 호출 전부 gitText를 쓴다 —
summary.ts에서 `$`가 사라진다(작은 출력 호출까지 옮긴 건 "이 파일엔 `$`가
없다"를 눈으로 확인되는 불변식으로 만들려는 것).
- 회귀망 git-output.test.ts: summary의 행업은 결정론적으로 재현되지 않으므로
(8개 동시 호출로도 간헐) 헬퍼 자체를 확실히 걸리는 모양 — 200KB `git show`
12개를 8-way로 — 으로 찌른다. gitBytes를 `$`로 바꾸면 1.3.12에서 2/2
실패(settle 타임아웃), 원복하면 통과. UTF-8 디코딩과 종료 코드 무시도 단언.
test-bun13 잡이 이 파일도 Bun 1.3.14로 돈다(의존성 없음).
- 알려진 한계: summary.ts를 `$`로 되돌리는 것은 테스트가 못 잡는다. CLAUDE.md
규칙("64KB를 넘을 수 있으면 gitBytes/gitText")과 리뷰로 지킨다.
- CLAUDE.md: 남은 `$` 목록에서 summary.ts를 빼고 "덮지 않는 곳"에 반영한다.
#76에서 test-bun13 문단 뒤로 밀려 모순처럼 읽히던 "bun install
--frozen-lockfile." 한 마디를 "나머지 잡은 …로 설치한다"로 바로잡는다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAe9zh6siLHSR4nPpqm8QK
- gitOutput.ts·git-output.test.ts가 "64KB를 넘을 수 있는 git 호출은 전부 여기를 탄다"고 했는데 거짓이다 — diff.ts의 name-status·ls-files, 지문의 status, refs.ts의 for-each-ref가 아직 `$`다(같은 PR의 CLAUDE.md도 그렇게 말한다). "새 호출은 여기를 탄다"는 규칙으로 고치고 남은 목록을 가리킨다. - "stdout을 비우기 전에 exited를 기다리면 64KB 넘는 출력에서 교착한다"는 측정하지 않은 주장이었다. 재 보니 Bun이 파이프를 선제 버퍼링해 200KB·5MB· 50MB 모두 교착하지 않는다(1.3.12). 순서는 구현 세부에 기대지 않으려는 관례로 고쳐 쓴다. - CLAUDE.md: "getRepoSummary는 이제 `$`를 하나도 쓰지 않는다"는 틀렸다 — resolveDiffBaseRev의 merge-base가 남는다(출력이 작다). 그리고 "수백 번에 한 번꼴"을 원시 수치(한 번은 18번째, 한 번은 150회 무사)로 바꾼다. 주석·문서만 바뀐다. 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.
왜
#74는
showBytes만Bun.spawn으로 옮겼다. 남은$중 **가장 위험한 곳은summary.ts**다 — 빈 상태 카드와 자동 base 전환(워크트리에서 미커밋 0건인 흔한 상태)이 부르는 요약인데, flight 밖이라 타임아웃도 503도 재시도도 닿지 않는다. 걸리면 요약이 영영 안 온다.실제로 걸리는지 먼저 쟀다(Bun 1.3.12, 실제
getRepoSummary반복 호출):baseFiles의diff --name-only출력→ 실재하지만 드물다. 그리고 결정론적으로 재현되지 않는다(8개 동시 호출로도 5라운드 중 간헐적).
무엇을
server/gitOutput.ts(신규) —gitBytes(args)/gitText(args).showBytes에 있던Bun.spawn패턴과 그 근거·동작 계약을 한 곳으로 옮긴다: 종료 코드 무시(.nothrow()와 같음), 스폰 실패는 throw, stdout을 먼저 비운 뒤exited(지금 Bun은 반대 순서도 교착하지 않지만 — 1.3.12에서 50MB까지 실측 — 구현 세부에 기대지 않는 관례). 호출처가 둘이 된 시점이라 헬퍼로 뺐다. 출력이 64KB를 넘을 수 있는 새 git 호출은 여기를 타야 한다 — 아직$로 남은 호출(diff.ts의name-status·ls-files, 지문의status,refs.ts)은 이 PR 범위 밖이다.showBytes→gitBytes. 동작 동일.summary.ts→ 여섯 호출 전부gitText. 파일에서$가 사라진다. 작은 출력(branch --show-current,rev-parse --short,rev-list --count)까지 옮긴 건 "이 파일엔$가 없다"를 눈으로 확인되는 불변식으로 만들려는 것이다. 인자는 예전에도 보간 하나가 인자 하나였고 지금은 argv라, 전달되는 값은 같다.$목록에서summary.ts를 빼고 "덮지 않는 곳"에 반영, 새 git 호출 규칙이 헬퍼를 가리키게 했다. 그리고 #76에서 제가test-bun13문단을 끼워 넣으면서 그 뒤로 밀려 설치가 없는 잡을 설명하는 것처럼 읽히던 "bun install --frozen-lockfile." 한 마디를 "나머지 잡은 …로 설치한다"로 바로잡았다.test-bun13— 새 회귀망도 Bun 1.3.14로 돈다(의존성 없음).TDD — RED를 어디에 걸었나
summary.ts의 행업은 결정론적으로 재현되지 않으므로 그 파일에 대한 RED 테스트는 만들 수 없다. 그래서 RED는 새 헬퍼에 걸었다:git-output.test.ts는 확실히 걸리는 모양(200KBgit show12개를 8-way로, 3라운드)으로gitText를 찌르고, 내용을 바이트 단위로 대조한다.Cannot find module '../server/gitOutput.ts'Bun.spawn구현gitBytes를$로gitText 버스트가 10000ms 안에 settle하지 않았다(2/2)UTF-8 디코딩(한글 파일)과 종료 코드 무시(없는
rev:path→"")도 단언한다.리뷰: Critical 0 · Important 1 · Minor 5. 리뷰어가 RED(
$뮤테이션 3/3 실패)와 잘림 뮤테이션(Expected 200009 / Received 147456)을 따로 재현했다. 반영한 것 — Important 1(헬퍼 주석이 "64KB 넘는 호출은 전부 여기를 탄다"고 거짓 주장), Minor 2("exited를 먼저 기다리면 교착"은 측정 안 된 주장 — 재 보니 거짓이라 관례로 고쳐 씀), Minor 3·4(CLAUDE.md 서술 정확도). 반영 안 한 것 —beforeAll·TextDecoder재사용(리포 관례와 무시할 비용).summary.ts를$로 되돌리는 것은 어떤 테스트도 못 잡는다(소스를 grep하는 테스트는 쓰지 않는다). CLAUDE.md 규칙과 리뷰로 지킨다.테스트 플랜
기존
summary.test.ts11종·empty-state.test.ts가 리팩터의 동작 보존을 지킨다(관련 파일 묶음 115 pass).🤖 Generated with Claude Code
https://claude.ai/code/session_01XAe9zh6siLHSR4nPpqm8QK