fix: 대형 파일 자동 접힘을 파일 길이가 아니라 변경량으로 판정한다 - #66
Merged
Conversation
뷰어는 첫 등장한 대형 파일을 접어서 마운트하는데(main.ts의 isLargeFile), 그 판정에 넘기던 changedLines가 변경량이 아니라 파일 전량이었다. FileDiffMetadata의 additionLines/deletionLines는 이름과 달리 string[]이고, 뷰어처럼 파일 전량으로 diff를 만들면(isPartial === false) 각각 새 파일과 옛 파일의 전체 내용이다(types.ts가 그렇게 문서화한다). 즉 실효 판정식이 "파일 길이 x 2 > 1500", 사실상 "파일 길이 > 750줄"이었다. 실측: 1,166줄 CLAUDE.md의 +28/-2 변경이 2,306으로 읽혔고, 같은 워킹트리에서 5개 파일이 이렇게 잘못 접혔다. 실제 변경 줄 수는 Hunk 쪽 동명 number 필드에만 있다. 파일 헤더의 +N -M 배지도 같은 값을 세므로(createFileHeaderElement), 이제 화면 배지와 접힘 판정이 일치한다. 임계값 1500과 lockfile 이름 규칙은 그대로다. 이 종류의 버그는 유닛이 원리적으로 못 잡는다 — isLargeFile 자체는 옳았고 호출부가 틀린 값을 넘겼을 뿐이라 기존 테스트 다섯 개가 전부 통과한 채로 버그가 살아 있었다. 그래서 배선까지 태우는 e2e를 회귀망으로 함께 넣는다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ArwfmcvGjKnRWMiEFBfJzF
앞 커밋은 "접히지 않는다" 한 방향만 단언하고, 반대 방향은 기존 스펙이 지킨다고 문서에 적었다. 실측해보니 그 주장이 거짓이었다. - retokenize-cache.e2e.ts와 lockfile-freeze.e2e.ts 어디에도 접힘 상태를 단언하는 코드가 없다. 전자는 헤더를 click해 펼친 뒤 하이라이트를 기다리고, 후자는 hasHeader만 보는데 헤더는 접혔든 펼쳐졌든 있다. 자동 접힘이 사라지면 그 click이 반대로 파일을 접어 뒤따르는 단언이 깨지는 부수효과로만 빨간불이 된다. - 게다가 lockfile 픽스처는 20줄마다 2줄을 바꿔 8k에서 1,596줄, 30k에서 5,996줄을 변경한다(실측). 둘 다 임계값 1,500을 넘으므로 크기 규칙만으로 이미 접힌다 — LOCKFILE_NAMES를 통째로 비워도 그 스펙은 초록이라 이름 규칙의 회귀망이 아니었다. 그래서 large-file-collapse.e2e.ts가 세 방향을 한 파일에서 지키게 한다: 1. 2,000줄 파일에 3줄 변경 -> 안 접힘 2. 800줄 전량 재작성(1,600줄 변경) -> 접힘 3. 1,000줄 lockfile(변경량 196줄로 임계값 아래) -> 이름 규칙으로만 접힘 셋 다 뮤테이션으로 판별력을 확인했다: countChangedLines를 0으로 퇴화시키면 2번만 죽고, LOCKFILE_NAMES를 비우면 3번만 죽는다. 기존 픽스처 옵션 (bigFileLines/lockfileLines)을 그대로 쓰므로 새 픽스처 배선은 없다. 함께 정정한 문서 주장 둘: - 헤더 배지 표기 순서는 `-M +N`이다. createFileHeaderElement가 삭제 span을 먼저 push하고 [data-metadata]에 order가 없어 DOM 순서가 곧 화면 순서다. - "1,166줄 CLAUDE.md" 실측의 출처가 headerlab임을 밝힌다. 이 레포의 CLAUDE.md는 147줄이라, 출처 없이 두면 수치가 틀린 것으로 오독된다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ArwfmcvGjKnRWMiEFBfJzF
코드 리뷰 지적 둘을 반영한다. 1. LARGE_FILE_LINE_THRESHOLD(1500)는 이번 수정으로 의미가 바뀌었는데 값과 주석이 그대로였다. 예전엔 "파일 길이 × 2"와 비교돼 사실상 750줄 파일을 걸렀고, 이제는 실제 변경 줄 수와 비교한다. 값은 의도적으로 유지했다는 것과, 1,600 이상으로 올리면 large-file-collapse.e2e.ts ②가 먼저 빨간불이 된다는 트립와이어 성질을 함께 적는다. 상수마다 근거를 남기는 레포에서 이 줄만 맨몸이었다. 2. 앞 커밋이 ① 주석에 "파일 전량(2,000 + 1,997)이 4,000쯤"이라고 적었는데 틀렸다. isPartial === false에서 deletionLines는 옛 파일 전량이고, 이 픽스처는 줄을 교체할 뿐이라 옛 파일도 정확히 2,000줄이다. 실측하면 2,000 + 2,000 = 정확히 4,000이라 1,997이 나올 자리가 없다. 틀린 숫자를 고치려던 커밋이 새 틀린 숫자를 들인 셈이라 짚어둘 값어치가 있다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ArwfmcvGjKnRWMiEFBfJzF
앞 커밋에 test-results/.last-run.json이 딸려 들어갔다. .gitignore가 apps/viewer/test-results/ 로 경로를 고정하고 있었는데, Playwright는 실행 cwd 기준으로 산출물을 만들어 레포 루트에서 돌리면 루트에도 생긴다. 두 규칙에서 경로 접두를 떼어 어느 위치에서 돌리든 무시되게 한다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ArwfmcvGjKnRWMiEFBfJzF
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.
뷰어가 첫 등장한 대형 파일을 접어서 마운트하는데(
main.ts의isLargeFile), 그 판정에 넘기던changedLines가 변경량이 아니라 파일 전량이었다. 정책은 "changes가 너무 길면 접는다"인데 실제로는 "파일이 길면 접는다"로 동작했다.근본 원인
FileDiffMetadata의additionLines/deletionLines는 이름과 달리string[]이고, 뷰어처럼 파일 전량으로 diff를 만들면(isPartial === false—parseDiffFromFile이 항상 그렇다) 각각 새 파일과 옛 파일의 전체 내용이다.packages/diffs/src/types.ts:235-256이 그렇게 문서화한다.즉 실효 판정식이
파일 길이 × 2 > 1500, 사실상 파일 길이 750줄 초과였다.실측(headerlab 워킹트리) — 1,166줄
CLAUDE.md의 +28/−2 = 30줄 변경이 2,306으로 읽혔다. 같은 트리에서 이렇게 잘못 접힌 파일이 5개였다:CLAUDE.mdtests/e2e/header-modification.spec.tstests/unit/ScopeRail.test.tsxcomponents/ScopeRail.tsxtests/unit/App.test.tsx수정
실제
+/-줄 수는Hunk쪽 동명number필드에만 있다. 파일 헤더의-M +N배지도 정확히 그걸 세므로(createFileHeaderElement), 이제 화면 배지와 접힘 판정이 같은 값을 본다.browser/largeFile.ts—countChangedLines(hunks)추가browser/main.ts— 호출부 교체임계값
1500과 lockfile 이름 규칙은 그대로다.Screenshots
Before —
CLAUDE.md(-2 +28)가 접혀 있다. 158줄만 바뀐tests/unit/ScopeRail.test.tsx(-103 +55)도 함께 접혔다.After — 같은 파일이 펼쳐진 채 뜬다.
회귀망
이 종류의 버그는 유닛이 원리적으로 못 잡는다.
isLargeFile자체는 옳았고 호출부가 틀린 값을 넘겼을 뿐이라, 그 함수의 기존 테스트 5개가 전부 통과한 채로 버그가 살아 있었다. 같은 이유로main.ts는 커버리지 게이트 밖이고 배선은 e2e가 맡는다.large-file-collapse.e2e.ts가 세 방향을 한 파일에서 지킨다:셋 다 뮤테이션으로 판별력을 확인했다: 원래 로직으로 되돌리면 ①이,
countChangedLines를 0으로 퇴화시키면 ②만,LOCKFILE_NAMES를 비우면 ③만 죽는다.CLAUDE.md에도 이 함정(FileDiffMetadata.additionLines가 이름과 다르다)과 위 회귀망 사실관계를 기록했다.Test plan
bun test— 621 pass / 0 fail (countChangedLines테스트 4종 추가)bun run test:e2e— 78 pass / 0 failbun run test:coverage— 100% 유지 (largeFile.ts포함)bun run typecheckbun run lint/bun run format:check— 새 경고 없음dist/cli.js를 실제로 빌드해 headerlab을 서빙한 화면이며, before는 base 커밋을 빌드해 찍었다🤖 Generated with Claude Code
https://claude.ai/code/session_01ArwfmcvGjKnRWMiEFBfJzF