Skip to content

Open annotate source files watch their entire parent directories #1088

Description

@rNoz

Summary

When the editor keeps local source documents synchronized with disk, it subscribes to each source document's parent directory instead of the source file itself. A single open file therefore creates a recursive watcher for its whole parent tree and reacts to unrelated sibling, nested, and Git metadata changes.

Reproduction

  1. Start an annotate session and open a local source document that can be reconciled from disk.
  2. Keep that source document open in the editor.
  3. Create or modify an unrelated sibling file, a nested file, or adjacent Git metadata under the same parent directory.
  4. Observe that the file-browser event stream emits a change and the editor schedules source-document reconciliation even though the open source file did not change.

The same behavior is present in the Bun server and the Pi server implementation.

Observed behavior

The client sends one dirPath query parameter per unique parent directory to /api/reference/files/stream. Both server implementations treat those paths as recursive directory watches and also watch repository metadata. Unrelated activity beneath the parent therefore wakes the source-document reconciliation path.

Expected behavior

Source-document reconciliation should subscribe to each unique normalized source file. Writes, deletion, rename-away, recreation, and creation of a previously missing leaf should emit a change for that file's parent. Sibling files, nested files, and adjacent Git metadata should not emit for an exact-file subscription.

Folder browsing must retain its existing recursive dirPath behavior and Git status refreshes.

Root cause

packages/editor/App.tsx reduces open source documents to parent directories before creating the event stream. The watcher cache in packages/server/reference-watch.ts and apps/pi-extension/server/file-browser-watch.ts is keyed only by resolved directory path, so it cannot distinguish recursive directory subscriptions from exact-file subscriptions.

Impact

Opening one source file can recursively watch a large project tree, consume unnecessary filesystem-watcher resources, and repeatedly reconcile source documents after unrelated repository activity. The behavior is especially costly in repositories with generated output, frequent Git updates, or many nested files.

Proposed scope

  • Add a pure client helper that normalizes and deduplicates source paths, builds repeated filePath query parameters, and retains unique parent directories for reconciliation.
  • Accept exactly one of dirPath or filePath in the Bun and Pi SSE endpoints.
  • Give directory and exact-file targets distinct cache keys.
  • Preserve recursive directory watching and Git metadata events for dirPath.
  • Disable recursive ignored-path and Git metadata watching for filePath.
  • Cover exact writes, sibling isolation, deletion, rename-away, recreation, missing leaves, directory rejection, cache separation, recursive directory behavior, and Bun/Pi parity.

Prior art and overlap

GitHub searches refreshed on 2026-07-20 for annotate file watchers, source-document reconciliation, reference/files/stream, filePath, and exact-file watching found no existing issue or pull request that addresses this behavior.

Merged PR #933 concerns general file-tree refresh behavior. It does not implement exact source-file subscriptions, so it does not overlap with the proposed fix.

Upstream change 8a6288b9 fixes explicit ../ annotate paths. It does not change source-document watcher scope and does not overlap with this exact-file subscription fix.

Non-goals and compatibility

  • Do not change recursive folder-browser dirPath subscriptions or their Git status refresh behavior.
  • Do not broaden exact-file subscriptions to sibling, nested, ignored-path, or Git metadata events.
  • Keep Bun and Pi request validation and watcher semantics aligned.
  • Requests must choose exactly one target mode; mixed or missing dirPath/filePath targets should remain invalid.

Validation

Focused proof on the rebased contribution branch:

  • 25 tests passed with 75 assertions across source-path construction, source-document reconciliation, and Bun/Pi watcher integration coverage.
  • Typecheck passed.
  • Hook and Pi builds passed.
  • git diff --check passed.

Contribution

I have a tested Bun, Pi, and editor implementation ready to contribute. About to push the PR => Created and ready!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions