Commit bd2fc8b
* fix(metadata-fs): give an external write more than one delivery attempt — content-keyed reconciliation behind the watcher poll (#9339)
The watcher gave an externally-written file exactly ONE chance to be noticed,
and losing it was permanent and silent. Under `usePolling`, chokidar re-reads a
directory only when its stat strictly advances; an external write advances the
type directory's mtime once, so every later poll compares an unchanged stat and
can never rediscover the file. At least six independent one-shot gates sit on
that single attempt, spanning three layers, and all six produce a byte-identical
observable — which is why #7282 was closed on one member of the family and
reopened as #9339.
The fix never asks which gate fired. A bounded, content-keyed reconciliation
sweep compares what is on disk against `heads` and publishes the divergence
through the same handler the watcher feeds, so it is robust across all six by
construction. `put()`'s direct registration (#7336) and every production
watcher constant are untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qYPmkKEsfbWY1yVg83p8F
* fix(metadata-fs): the reconciliation sweep discriminates its read failures instead of inventing an empty listing (#8895)
Both `readdir` seams in `resync()` swallowed every errno and answered with
"there is nothing here". ENOENT is the one truthful empty answer — a path that
does not exist holds no items — and it stays silent. Every other code means the
read could not RUN: EACCES, EIO, and above all EMFILE/ENFILE, which degrade this
read and chokidar's own `fs.watchFile` polling at the same time and for the same
reason. Silence there made the backstop absent for the life of the process
exactly under the load-dependent conditions it exists to catch.
Reported at `error` per AGENTS.md's judgement question — the system keeps looking
healthy while its index drifts from disk — naming the consequence and the fix,
and latched per path+errno so a standing fault is said once rather than every 2s.
It deliberately does not throw: this runs on a background timer.
An unreadable type directory is also excluded from the delete pass, which would
otherwise read "could not look" as "the files are gone" and retire every item of
that type.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qYPmkKEsfbWY1yVg83p8F
* docs(metadata-fs): put the sweep's rationale back above resync() rather than stacked on reportResyncFault (#9339)
Comment-only. The read-seam commit inserted the new helpers above resync()
and left its doc block attached to the first of them, so two doc comments
stacked on reportResyncFault and the sweep itself read undocumented.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017qYPmkKEsfbWY1yVg83p8F
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 440439f commit bd2fc8b
3 files changed
Lines changed: 658 additions & 16 deletions
File tree
- .changeset
- packages/metadata-fs
- src
- test
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
0 commit comments