Commit 729a43a
`NodeMetadataManager.handleFileEvent()` did two things when chokidar reported
`add` / `change` / `unlink`: re-`load()` the file and `notifyWatchers()`. It
touched neither `listCache` nor `registry` — and `load()` is a pure read (it
delegates to `loadDiagnosed`, which only walks the loaders), so both caches
kept the pre-change state.
The manager's two read surfaces then contradicted each other for up to
LIST_CACHE_TTL_MS (30s) after editing `rootDir/view/x.json`: `get()` returned
the new definition because it falls through to the FilesystemLoader, while
`list()` — REST `/api/v1/metadata/:type`, the Studio left rail, `listViews()`
— kept serving the pre-change set. The HMR/SSE consumers the event woke answer
it by re-reading through `list()`, so the wake-up handed back precisely the
stale data it was announcing.
Same defect shape as #5109 (a cluster peer's write) with a different trigger,
so this reuses that fix's helper rather than re-deriving it:
`invalidateForForeignWrite(type, name)`, widened `private` -> `protected`. A
file event is a foreign write on the definition that matters — it did not come
through this manager's write API, so nothing refreshed the caches on its
behalf, and delete-not-prefill fits exactly (falling through to the loader IS
the file's truth).
Two constraints kept in line with every other write path in the base class:
invalidate BEFORE announcing (`register` / `unregister` / `applyRepoEvent` /
the cluster subscriber all do), so a watcher can never observe the event and
the pre-event cache together; and drop the registry entry too, not just the
list cache — FS-loaded items never enter the registry, but a same-named entry
previously written by `register()` / `registerInMemory()` SHADOWS the loader in
both `get()` and `list()`, and dropping the list cache alone would leave that
stale copy answering forever.
`type === 'api'` is unchanged in behaviour: the endpoint index was already
covered on this path by #5089's `subscribe('api', ...)` seam. The fix connects
the `invalidateListCache` seam too, making the two symmetric; the overlap is
free because `EndpointMatcher.invalidate()` is two assignments to `undefined`.
Hit surface is development-time: `MetadataPlugin` defaults to `watch: true`,
forced off under `bootstrap: 'artifact-only'`, and `standalone-stack` passes
`watch: false`.
Tests drive `handleFileEvent` with synthetic events over real files, a real
tmpdir and the real default FilesystemLoader — `startWatching` polls at
`interval: 1000`, so a real watcher per case would be seconds of wait for no
added coverage. One end-to-end case uses a real chokidar watcher to pin that
its callbacks actually reach the handler. 9 of the 11 fail without the fix.
Claude-Session: https://claude.ai/code/session_01Pbu27iNUfQCHeuS551Rqo7
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 718b229 commit 729a43a
4 files changed
Lines changed: 434 additions & 14 deletions
File tree
- .changeset
- packages/metadata/src
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2036 | 2036 | | |
2037 | 2037 | | |
2038 | 2038 | | |
2039 | | - | |
2040 | | - | |
2041 | | - | |
2042 | | - | |
2043 | | - | |
2044 | | - | |
2045 | | - | |
2046 | | - | |
| 2039 | + | |
| 2040 | + | |
| 2041 | + | |
| 2042 | + | |
| 2043 | + | |
| 2044 | + | |
| 2045 | + | |
| 2046 | + | |
| 2047 | + | |
| 2048 | + | |
| 2049 | + | |
| 2050 | + | |
2047 | 2051 | | |
2048 | 2052 | | |
2049 | 2053 | | |
| |||
2052 | 2056 | | |
2053 | 2057 | | |
2054 | 2058 | | |
2055 | | - | |
| 2059 | + | |
| 2060 | + | |
| 2061 | + | |
2056 | 2062 | | |
2057 | 2063 | | |
2058 | 2064 | | |
2059 | 2065 | | |
2060 | 2066 | | |
2061 | 2067 | | |
2062 | 2068 | | |
2063 | | - | |
| 2069 | + | |
2064 | 2070 | | |
2065 | 2071 | | |
2066 | 2072 | | |
| |||
0 commit comments