Found while implementing #7000 (PR for the metadata half of #6743's dry-run property). Out of that card's scope — #7000 is about the repository creating its root at attach time — so this is filed separately and unassigned.
Duplicate search over open issues: chokidar ignored watcher, FileSystemRepository watcher metadata-fs, in:title watcher, ".objectstack/metadata" — 0 hits other than #7000 / #6743 themselves.
Observation
FileSystemRepository.startWatcher() passes ignored: [/(^|[\\/])\../] with the comment "skip dotfiles incl. .objectstack" (packages/metadata-fs/src/repository.ts). chokidar applies that matcher to the watched root path itself, not only to entries discovered underneath it. MetadataPlugin attaches the repository at REPO_SUBDIR = '.objectstack/metadata' under the project root (packages/metadata/src/plugin.ts:386-398), so the root path contains a dot segment and the whole watch is ignored.
Measured on chokidar 5.0.0, the version the package depends on, with the repository's own watch options (ignoreInitial: true, depth: 2, awaitWriteFinish, usePolling: true, interval: 1000). Two identical trees, differing only in whether the root sits under a dot-directory; in both, view/a.json is rewritten and view/b.json is added after ready:
A plain root | root= metadata
getWatched keys: [ '', 'metadata', 'metadata/view' ]
events: [["add","view/b.json"],["change","view/a.json"]]
B root under dot-dir | root= .objectstack/metadata
getWatched keys: []
events: []
Case B is the production layout.
Why it may matter
The watcher is not decoration. handleFsChange translates external edits into MetadataEvents with source: 'fs', and MetadataManager.setRepository() subscribes to repo.watch({}) and re-emits every event through notifyWatchers, invalidating the registry entry and the list() cache for the affected type (packages/metadata/src/metadata-manager.ts:2560-2640). So there is a live consumer wired to a source that, in the layout the plugin actually uses, can never fire. Hand edits, a git checkout that brings metadata JSON in, or any out-of-process writer under .objectstack/metadata/ are therefore invisible until the next start().
Whether a user hits this today depends on whether anyone edits files under .objectstack/metadata/ out of process, which I did not measure — I am recording both readings rather than grading it myself:
- read as observation-class: a shipped mechanism that has never been exercised in the production layout, with no traced user-visible failure;
- read as a concrete defect: a capability that is wired end to end and silently does nothing, which is exactly the shape that survives review because everything looks connected.
Left unlabeled for the triage round to grade.
Not caused by #7000's fix
Pre-existing on origin/main, and unchanged by that PR in both directions: before it, start() created the root and armed a watcher that was then ignored; after it, ensureRoot() arms a watcher that is still ignored. The #7000 PR's watcher-arming pin deliberately uses a root that is not under a dot-directory, precisely so it measures the arming rather than this.
Possible directions (not a ruling)
- Scope the matcher to paths relative to the root instead of absolute paths (chokidar's matcher receives absolute paths, so this needs an explicit function matcher).
- Or drop the regex and ignore only the repository's own
.objectstack/ bookkeeping subtree, which is what the comment says the intent is — parseItemPath already rejects anything under .objectstack, so the matcher may be redundant with the parse guard.
Either shape is a contract-ish decision about what the watcher promises to see; it should be ruled, not guessed.
Related
Generated by Claude Code
Found while implementing #7000 (PR for the metadata half of #6743's dry-run property). Out of that card's scope — #7000 is about the repository creating its root at attach time — so this is filed separately and unassigned.
Duplicate search over open issues:
chokidar ignored watcher,FileSystemRepository watcher metadata-fs,in:title watcher,".objectstack/metadata"— 0 hits other than #7000 / #6743 themselves.Observation
FileSystemRepository.startWatcher()passesignored: [/(^|[\\/])\../]with the comment "skip dotfiles incl. .objectstack" (packages/metadata-fs/src/repository.ts). chokidar applies that matcher to the watched root path itself, not only to entries discovered underneath it.MetadataPluginattaches the repository atREPO_SUBDIR = '.objectstack/metadata'under the project root (packages/metadata/src/plugin.ts:386-398), so the root path contains a dot segment and the whole watch is ignored.Measured on chokidar 5.0.0, the version the package depends on, with the repository's own watch options (
ignoreInitial: true,depth: 2,awaitWriteFinish,usePolling: true,interval: 1000). Two identical trees, differing only in whether the root sits under a dot-directory; in both,view/a.jsonis rewritten andview/b.jsonis added afterready:Case B is the production layout.
Why it may matter
The watcher is not decoration.
handleFsChangetranslates external edits intoMetadataEvents withsource: 'fs', andMetadataManager.setRepository()subscribes torepo.watch({})and re-emits every event throughnotifyWatchers, invalidating the registry entry and thelist()cache for the affected type (packages/metadata/src/metadata-manager.ts:2560-2640). So there is a live consumer wired to a source that, in the layout the plugin actually uses, can never fire. Hand edits, agit checkoutthat brings metadata JSON in, or any out-of-process writer under.objectstack/metadata/are therefore invisible until the nextstart().Whether a user hits this today depends on whether anyone edits files under
.objectstack/metadata/out of process, which I did not measure — I am recording both readings rather than grading it myself:Left unlabeled for the triage round to grade.
Not caused by #7000's fix
Pre-existing on
origin/main, and unchanged by that PR in both directions: before it,start()created the root and armed a watcher that was then ignored; after it,ensureRoot()arms a watcher that is still ignored. The #7000 PR's watcher-arming pin deliberately uses a root that is not under a dot-directory, precisely so it measures the arming rather than this.Possible directions (not a ruling)
.objectstack/bookkeeping subtree, which is what the comment says the intent is —parseItemPathalready rejects anything under.objectstack, so the matcher may be redundant with the parse guard.Either shape is a contract-ish decision about what the watcher promises to see; it should be ruled, not guessed.
Related
os migrate planstill creates.objectstack/metadata/on a fresh project (the residual half of #6743's dry-run write side effect) #7000 / its PR — the attach-time root creation this was found underos migrate plan自称 dry-run,却仍会在全新项目上创建空数据库文件(#6469 的残余写副作用) #6743 — the dry-run property both halves serveGenerated by Claude Code