Skip to content

Fix watcher reconciliation regressions - #124

Open
Shengyu Fu (shengyfu) wants to merge 12 commits into
shengyfu-watcher-respect-ignore-filesfrom
shengyfu-watcher-regression-follow-up
Open

Fix watcher reconciliation regressions#124
Shengyu Fu (shengyfu) wants to merge 12 commits into
shengyfu-watcher-respect-ignore-filesfrom
shengyfu-watcher-regression-follow-up

Conversation

@shengyfu

Copy link
Copy Markdown
Member

Stacked on #105 and targets shengyfu-watcher-respect-ignore-files.

  • Preserve existing Linux/Android subscriptions when directory traversal is incomplete, while still adding proven directories and pruning after a complete pass.
  • Poll the worktree-specific Git index only for active case-insensitive tracked-file exemptions, then coalesce into the serialized matcher/index/subscription reconciliation for both git add -f and git rm --cached.
  • Avoid startup tombstones for rejected paths with no reader, overlay, or stamp evidence while retaining reader-without-stamp deletion.
  • Clarify that selective OS registration is guaranteed only for Linux/Android; Windows and macOS retain recursive root subscriptions/streams with post-delivery filtering, and kqueue/PollWatcher are not covered.

Validation:

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace
  • Mutation controls confirmed each regression test fails when only its production decision is reverted, then passes after restoration.

Shengyu Fu (shengyfu) and others added 2 commits August 29, 2026 00:08
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings August 29, 2026 05:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

Review tier: Balanced
Findings: 1 High severity · 1 Medium severity

New issues introduced by this change (2)
Severity Finding
Medium severity tgrep-core/​src/​git_index.rs — This reads only the common config, but linked worktrees can enable extensions.worktreeConfig and…
High severity tgrep-cli/​src/​serve.rs — An incomplete pass still returns true here, so sync force-re-registers every proven,…
What changed in this PR

Fixes watcher reconciliation regressions involving incomplete traversal, Git index changes, and unnecessary tombstones.

Changes:

  • Preserves subscriptions during incomplete directory traversal.
  • Polls tracked-file exemptions and reconciles forced Git additions/removals.
  • Avoids tombstones without evidence and clarifies platform behavior.
File Description
tgrep-core/​src/​reader.rs Adds efficient reader path membership checks.
tgrep-core/​src/​hybrid.rs Exposes reader membership through HybridIndex.
tgrep-core/​src/​gitignore.rs Tracks exemption membership fingerprints.
tgrep-core/​src/​git_index.rs Adds fingerprints and linked-worktree handling.
tgrep-cli/​src/​serve.rs Updates polling, reconciliation, subscriptions, and tombstones.
tgrep-cli/​tests/​watcher_watch_registration.rs Tests Git index reconciliation.
README.md Documents platform-specific watcher behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tgrep-core/src/git_index.rs Outdated
Comment thread tgrep-cli/src/serve.rs
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 29, 2026 05:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

Review tier: Balanced
Findings: 1 High severity · 1 Medium severity

Pre-existing issues (2)
Severity Finding
High severity tgrep-cli/​src/​serve.rs — An incomplete pass still returns true here, so sync force-re-registers every proven,… View comment
Medium severity tgrep-core/​src/​git_index.rs — This reads only the common config, but linked worktrees can enable extensions.worktreeConfig and… View comment
Suppressed comments (1)

tgrep-core/src/git_index.rs:159

  • Linked worktrees can enable extensions.worktreeConfig and override core.ignoreCase in $GIT_DIR/config.worktree. Reading only the common config therefore applies the shared value even when this worktree's effective value differs, activating or disabling the case-insensitive matcher and index polling incorrectly. Please apply Git's common-config-then-worktree-config precedence here.
    let Ok(config) = std::fs::read_to_string(common_git_dir(&git_dir).join("config")) else {

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 772a4aa3-4cba-4ac4-aeca-dd184614127a
Copilot AI review requested due to automatic review settings August 29, 2026 06:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

Review tier: Balanced
Findings: 1 High severity · 3 Medium severity

New issues introduced by this change (2)
Severity Finding
Medium severity tgrep-core/​src/​gitignore.rs — This eagerly reads the complete Git index and matches every tracked path whenever a…
Medium severity tgrep-core/​src/​builder.rs — Treat None as the caller's supplied snapshot here. Falling back to walk_dir reconstructs…
Pre-existing issues (2)
Severity Finding
High severity tgrep-cli/​src/​serve.rs — An incomplete pass still returns true here, so sync force-re-registers every proven,… View comment
Medium severity tgrep-core/​src/​git_index.rs — This reads only the common config, but linked worktrees can enable extensions.worktreeConfig and… View comment

Comment thread tgrep-core/src/gitignore.rs Outdated
Comment thread tgrep-core/src/builder.rs Outdated
Route RPC reloads through coordinated tracked-membership snapshots while preserving live public matcher behavior. Stage and atomically publish reload generations with rollback and cache invalidation guards.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 772a4aa3-4cba-4ac4-aeca-dd184614127a
Copilot AI review requested due to automatic review settings August 29, 2026 07:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

Review tier: Balanced
Findings: 1 High severity · 3 Medium severity

New issues introduced by this change (1)
Severity Finding
Medium severity tgrep-core/​src/​gitignore.rs — The polling cache retains the newly parsed TrackedFiles even though this path only returns its…
Pre-existing issues (3)
Severity Finding
High severity tgrep-cli/​src/​serve.rs — An incomplete pass still returns true here, so sync force-re-registers every proven,… View comment
Medium severity tgrep-core/​src/​builder.rs — Treat None as the caller's supplied snapshot here. Falling back to walk_dir reconstructs… View comment
Medium severity tgrep-core/​src/​git_index.rs — This reads only the common config, but linked worktrees can enable extensions.worktreeConfig and… View comment
Issues resolved since last review (1)
Severity Finding
Medium severity tgrep-core/​src/​gitignore.rs — This eagerly reads the complete Git index and matches every tracked path whenever a… View resolved comment

Comment thread tgrep-core/src/gitignore.rs
Validate stable owned reads before publishing stamps across full builds, stale deltas, startup recovery, reload, and watcher updates. Retry incomplete startup reconciliation and preserve public builder APIs and stamp compatibility.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 772a4aa3-4cba-4ac4-aeca-dd184614127a
Copilot AI review requested due to automatic review settings August 29, 2026 07:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

Review tier: Balanced
Findings: 4 High severity · 3 Medium severity

New issues introduced by this change (4)
Severity Finding
Medium severity tgrep-core/​src/​builder.rs--no-max-filesize allows a file larger than the 64 MiB batch budget, but this now reserves the…
High severity tgrep-cli/​src/​serve.rs — On Windows, rename cannot replace an existing destination. During rollback the target still…
High severity tgrep-core/​src/​builder.rsstamp.mtime has only whole-second precision. On Windows, created_nanos does not change for an…
High severity tgrep-cli/​src/​serve.rs — These stability checks compare only FileStamp (whole-second mtime plus size). A same-size write…
Pre-existing issues (3)
Severity Finding
High severity tgrep-cli/​src/​serve.rs — An incomplete pass still returns true here, so sync force-re-registers every proven,… View comment
Medium severity tgrep-core/​src/​gitignore.rs — The polling cache retains the newly parsed TrackedFiles even though this path only returns its… View comment
Medium severity tgrep-core/​src/​git_index.rs — This reads only the common config, but linked worktrees can enable extensions.worktreeConfig and… View comment
Issues resolved since last review (1)
Severity Finding
Medium severity tgrep-core/​src/​builder.rs — Treat None as the caller's supplied snapshot here. Falling back to walk_dir reconstructs… View resolved comment
Suppressed comments (1)

tgrep-core/src/git_index.rs:159

  • Reading only the common config does not yield the effective value for linked worktrees when extensions.worktreeConfig is enabled: <git-dir>/config.worktree can override core.ignorecase. If common config says true and this worktree overrides it to false, this function still enables case-insensitive filtering and tracked exemptions incorrectly. Apply the worktree config after the common config (or use Git-compatible config resolution).
    let Ok(config) = std::fs::read_to_string(common_git_dir(&git_dir).join("config")) else {

Comment thread tgrep-core/src/builder.rs Outdated
Comment thread tgrep-cli/src/serve.rs Outdated
Comment thread tgrep-core/src/builder.rs Outdated
Comment thread tgrep-cli/src/serve.rs Outdated
Restore the mmap-backed builder and bounded batch accounting, then repair reload and startup publication through deferred event replay, no-watch catch-up, and stable containment-safe concrete event reads.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 772a4aa3-4cba-4ac4-aeca-dd184614127a
Copilot AI review requested due to automatic review settings August 29, 2026 09:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

Review tier: Balanced
Findings: 4 High severity · 5 Medium severity

New issues introduced by this change (2)
Severity Finding
Medium severity tgrep-cli/​src/​serve.rstracked_membership_changed updates the observed baseline before this branch. If the no-watcher…
Medium severity tgrep-cli/​src/​serve.rs — For every missing deferred path, this clones every reader path into a HashSet and every overlay…
Pre-existing issues (7)
Severity Finding
High severity tgrep-cli/​src/​serve.rs — These stability checks compare only FileStamp (whole-second mtime plus size). A same-size write… View comment
High severity tgrep-core/​src/​builder.rsstamp.mtime has only whole-second precision. On Windows, created_nanos does not change for an… View comment
High severity tgrep-cli/​src/​serve.rs — On Windows, rename cannot replace an existing destination. During rollback the target still… View comment
High severity tgrep-cli/​src/​serve.rs — An incomplete pass still returns true here, so sync force-re-registers every proven,… View comment
Medium severity tgrep-core/​src/​builder.rs--no-max-filesize allows a file larger than the 64 MiB batch budget, but this now reserves the… View comment
Medium severity tgrep-core/​src/​gitignore.rs — The polling cache retains the newly parsed TrackedFiles even though this path only returns its… View comment
Medium severity tgrep-core/​src/​git_index.rs — This reads only the common config, but linked worktrees can enable extensions.worktreeConfig and… View comment
Suppressed comments (1)

tgrep-core/src/git_index.rs:159

  • Reading only the common config does not yield the effective core.ignorecase for repositories using extensions.worktreeConfig: $GIT_DIR/config.worktree can override the common value for this linked worktree. That can enable or disable the tracked-file exemption and index polling incorrectly for a worktree. Apply the worktree config after the common config (including Git's normal precedence) before deciding this value.
    let Ok(config) = std::fs::read_to_string(common_git_dir(&git_dir).join("config")) else {

Comment thread tgrep-cli/src/serve.rs
Comment thread tgrep-cli/src/serve.rs Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 29, 2026 22:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

Review tier: Balanced
Findings: 2 High severity · 2 Medium severity · 1 Low severity

New issues introduced by this change (4)
Severity Finding
High severity tgrep-core/​src/​gitignore.rs — The semantic fingerprint misses tracked paths whose final file match is a whitelist but whose…
Medium severity tgrep-cli/​src/​serve.rs — When this no-watch catch-up fails, no later retry is actually scheduled: the periodic reconcile…
Low severity tgrep-cli/​src/​serve.rs — For an incomplete traversal, desired.dirs is only the proven subset; sync deliberately…
Medium severity tgrep-core/​src/​builder.rs — This is only a per-file cap, not the claimed batch-wide owned-buffer bound. Files above…
Pre-existing issues (1)
Severity Finding
High severity tgrep-cli/​src/​serve.rs — An incomplete pass still returns true here, so sync force-re-registers every proven,… View comment
Issues resolved since last review (8)
Severity Finding
Medium severity tgrep-cli/​src/​serve.rs — For every missing deferred path, this clones every reader path into a HashSet and every overlay… View resolved comment
Medium severity tgrep-cli/​src/​serve.rstracked_membership_changed updates the observed baseline before this branch. If the no-watcher… View resolved comment
High severity tgrep-cli/​src/​serve.rs — These stability checks compare only FileStamp (whole-second mtime plus size). A same-size write… View resolved comment
High severity tgrep-core/​src/​builder.rsstamp.mtime has only whole-second precision. On Windows, created_nanos does not change for an… View resolved comment
High severity tgrep-cli/​src/​serve.rs — On Windows, rename cannot replace an existing destination. During rollback the target still… View resolved comment
Medium severity tgrep-core/​src/​builder.rs--no-max-filesize allows a file larger than the 64 MiB batch budget, but this now reserves the… View resolved comment
Medium severity tgrep-core/​src/​gitignore.rs — The polling cache retains the newly parsed TrackedFiles even though this path only returns its… View resolved comment
Medium severity tgrep-core/​src/​git_index.rs — This reads only the common config, but linked worktrees can enable extensions.worktreeConfig and… View resolved comment

Comment thread tgrep-core/src/gitignore.rs Outdated
Comment thread tgrep-cli/src/serve.rs
Comment thread tgrep-cli/src/serve.rs Outdated
Comment thread tgrep-core/src/builder.rs Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 96b9f8ae-c5ec-450c-a003-cb9ade61d9df
Copilot AI review requested due to automatic review settings August 29, 2026 23:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

Review tier: Balanced
Findings: 1 High severity

New issues introduced by this change (1)
Severity Finding
High severity tgrep-core/​src/​builder.rsBuildOptions::max_file_size documents that None indexes files of any size, but this introduces…
Issues resolved since last review (5)
Severity Finding
Medium severity tgrep-core/​src/​builder.rs — This is only a per-file cap, not the claimed batch-wide owned-buffer bound. Files above… View resolved comment
Low severity tgrep-cli/​src/​serve.rs — For an incomplete traversal, desired.dirs is only the proven subset; sync deliberately… View resolved comment
Medium severity tgrep-cli/​src/​serve.rs — When this no-watch catch-up fails, no later retry is actually scheduled: the periodic reconcile… View resolved comment
High severity tgrep-core/​src/​gitignore.rs — The semantic fingerprint misses tracked paths whose final file match is a whitelist but whose… View resolved comment
High severity tgrep-cli/​src/​serve.rs — An incomplete pass still returns true here, so sync force-re-registers every proven,… View resolved comment

Comment thread tgrep-core/src/builder.rs Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 96b9f8ae-c5ec-450c-a003-cb9ade61d9df
Copilot AI review requested due to automatic review settings August 30, 2026 00:05
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 96b9f8ae-c5ec-450c-a003-cb9ade61d9df

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

Review tier: Balanced
Findings: None

Issues resolved since last review (1)
Severity Finding
High severity tgrep-core/​src/​builder.rsBuildOptions::max_file_size documents that None indexes files of any size, but this introduces… View resolved comment
Suppressed comments (2)

tgrep-core/src/builder.rs:467

  • The configured file-size cap is checked only after the successful-mmap return. If a file was below the cap during the walk but grows past it before extraction, size reflects the larger file and a successful mmap indexes it anyway. Move the existing limit check ahead of the mmap attempt so BuildOptions::max_file_size remains authoritative during this race.
        let mapped =
            std::fs::File::open(path).and_then(|file| unsafe { memmap2::Mmap::map(&file) });

tgrep-core/src/builder.rs:475

  • The owned-buffer budget is bypassed for every file larger than 64 MiB: oversized suppresses the permit, while owned_limit defaults to size, so an mmap failure under --no-max-filesize reads the entire file into an uncharged Vec. A multi-gigabyte file can therefore exhaust memory despite this budget. Cap or reject the owned fallback at MAX_OWNED_FILE_BYTES while continuing to permit larger files when mmap succeeds.
    if size > owned_limit {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,

Copilot AI review requested due to automatic review settings August 30, 2026 00:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

Review tier: Balanced
Findings: 1 Medium severity

New issues introduced by this change (1)
Severity Finding
Medium severity tgrep-core/​src/​builder.rsconfigured_limit is consulted only after the mmap early return. If a file grows beyond…

Comment thread tgrep-core/src/builder.rs
path: &Path,
size: u64,
owned_budget: &std::sync::Arc<OwnedReadBudget>,
configured_limit: Option<u64>,
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 96b9f8ae-c5ec-450c-a003-cb9ade61d9df
Copilot AI review requested due to automatic review settings August 30, 2026 03:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants