Stop the file watcher from silently truncating its change list - #67
Merged
Conversation
`if (touched.size < MAX_TOUCHED) touched.add(...)` 한 줄이었다. 상한(2000)을 넘으면 경로를 조용히 버렸다. 앱 자신은 멀쩡하다 — 새로고침 때 트리를 통째로 다시 읽으니까. 손해는 확장의 파일 감시자가 본다. 잘려 나간 파일은 확장에게 "아무 일 없었다" 가 되고, 확장은 자기가 전부 안다고 여긴다. touchSet.cjs 로 자루를 옮긴다. 상한을 20000 으로 올리고, 그래도 넘치면 overflow 를 알림에 실어 보낸다. 렌더러는 그 신호를 받으면 이름 목록으로 좁히지 않고 앞뒤 트리 전체를 비교해 판정한다 — 잘려 나간 파일이 조용히 누락되지 않게. 트리까지 잘린 경우에만 정말 모르는 채 넘어가고 그때는 남긴다. 전제가 반쯤 틀렸다는 것도 적어 둔다. 파일 2500개를 한 번에 만들어 확인해 보니 워처 알림에 이름이 180개 남짓만 왔다. 우리 상한에 닿기 한참 전에 fs.watch 자체가 이벤트를 흘린다(윈도우 recursive 워처의 커널 버퍼). 실제 손실의 대부분은 거기서 일어난다. 그래서 이 수정이 보장하는 것은 "우리가 조용히 자르지 않는다" 까지고, "이름이 다 온다" 는 OS 가 정한다. 다행히 앱은 이미 견딘다. syncFromDisk 가 트리를 다시 읽고 classify 가 전체 비교로 만들어짐·지워짐을 잡는다. 놓치는 것은 changed 뿐이고, 그걸 메우려면 내용 해시나 폴링 대체 경로가 필요하다 — 별건으로 남긴다. 단위 9개 추가(981개 통과). 실제 앱 검증 3/3.
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.
The bug
The file watcher collected changed paths with one line:
Past the cap it dropped paths silently. The app itself is fine —
syncFromDiskre-reads the whole tree anyway. The victim is the extension file watcher: a dropped path becomes "nothing happened" for that extension, which then believes its index is complete.The fix
electron/touchSet.cjsowns the bag now. The cap is 20000, and when it is exceeded the notification carriesoverflow: true. On overflow the renderer stops narrowing by the reported names and diffs the full before/after tree instead, so a dropped name cannot silently vanish. Only when the tree is also truncated do we genuinely not know, and that case is logged rather than passed off as complete.What the probe disproved
This was built on the assumption that a branch switch overruns the 2000 cap. It does not. Creating 2500 files at once in the real app produced watcher notifications carrying ~180 names, not 2500 —
fs.watchitself drops events long before our cap is reached (the Windows recursive watcher's kernel buffer overflows).So the honest scope of this change is narrower than the framing suggests: it guarantees the app never truncates the list itself. Whether every name arrives is decided by the OS.
The app already survives that.
syncFromDiskre-reads the tree andclassifyrecovers created/deleted from the full diff — the probe confirms all 2500 files land in the tree. What is lost ischangedevents, and closing that properly needs content hashing or a polling fallback. Left as separate work.Verification
droppedcount, duplicates not consuming the cap, backslash normalization, flag cleared on drain. 981 passing (was 972).overflow=false), every reported path is a real path, all 2500 files present in the tree.npm run typecheckclean. Line endings unchanged —main.cjs1905 CRLF / 0 LF,preload.cjs253 LF / 0 CRLF.