indexer: walker skip-list matches basename only, silently omitting legit source dirs (stale index) #13

Closed
opened 2026-07-07 13:19:31 +02:00 by buildagent · 1 comment
Member

Severity: High · Category: Correctness (missed change / stale index)

filter_entry in crates/indexer/src/walker.rs:101-106 matches the skip-list against the entry basename (d.file_name()), not the project-relative path. So a directory legitimately named build, dist, vendor, venv, etc. anywhere in the tree (e.g. a Rust module src/build/mod.rs, or a JS lib build/ dir) is silently dropped — its files are never indexed and no error is logged.

Notably the dispatch-time filter is_in_skip_dir (crates/daemon/src/watcher.rs:929) already documents and implements the project-relative rule (only matching top-of-tree dirs via strip_prefix(root)), so the walker is the inconsistent half. The target/bin/obj entries are marker-gated at the root, but the UNIVERSAL list (build, dist, vendor, venv, …) is not.

Fix

  • Anchor the skip to the intended depth: only skip a dir when it is a direct child of root (or matches a path-scoped rule), mirroring is_in_skip_dir's strip_prefix(root) component reasoning — or restrict UNIVERSAL_SKIP matching to the project-relative first segment where that's the intent.

Impact

  • Files in affected dirs are absent from the index with no diagnostic → silent recall gaps.

Filed from a deep multi-agent code review of the workspace (v0.5.7). Severity/category per the review; file:line refs were accurate at review time — verify against current master.

**Severity:** High · **Category:** Correctness (missed change / stale index) `filter_entry` in `crates/indexer/src/walker.rs:101-106` matches the skip-list against the entry **basename** (`d.file_name()`), not the project-relative path. So a directory legitimately named `build`, `dist`, `vendor`, `venv`, etc. **anywhere in the tree** (e.g. a Rust module `src/build/mod.rs`, or a JS lib `build/` dir) is silently dropped — its files are never indexed and **no error is logged**. Notably the dispatch-time filter `is_in_skip_dir` (`crates/daemon/src/watcher.rs:929`) already documents and implements the *project-relative* rule (only matching top-of-tree dirs via `strip_prefix(root)`), so the walker is the inconsistent half. The `target`/`bin`/`obj` entries are marker-gated at the root, but the UNIVERSAL list (`build`, `dist`, `vendor`, `venv`, …) is not. ### Fix - Anchor the skip to the intended depth: only skip a dir when it is a direct child of `root` (or matches a path-scoped rule), mirroring `is_in_skip_dir`'s `strip_prefix(root)` component reasoning — or restrict UNIVERSAL_SKIP matching to the project-relative first segment where that's the intent. ### Impact - Files in affected dirs are absent from the index with no diagnostic → silent recall gaps. --- _Filed from a deep multi-agent code review of the workspace (v0.5.7). Severity/category per the review; file:line refs were accurate at review time — verify against current `master`._
Author
Member

Closing as not-a-bug after reassessing against current master (independently verified by reading both functions).

The literal observation is true — walker.rs filter_entry matches UNIVERSAL_SKIP against the entry basename (d.file_name()) at any depth. But the premise that watcher.rs::is_in_skip_dir uses a different (top-of-tree-only) rule is false: it does abs.strip_prefix(root) then rel.components().any(|c| skip_dirs.contains(c)) — i.e. it matches a skip name at any project-relative component, exactly like the walker. So for root/src/build/mod.rs both skip it; for anything inside the tree the two produce identical drop decisions. They can only differ for directories above the root, which the walker never visits.

So there is no silent walker↔watcher inconsistency and no divergent stale-index behavior. The any-depth universal skip (node_modules, dist, build, vendor, venv, …) is deliberate, gitignore-style, and consistent across both halves.

(Separate, minor design consideration — not this bug: a project with a legitimate source dir literally named build/dist/vendor can't currently un-skip it via .code-index-ignore. If that ever matters, the enhancement would be root-anchoring the universal list or an allow-list override — happy to track that separately if wanted.)

Closing as **not-a-bug** after reassessing against current master (independently verified by reading both functions). The literal observation is true — `walker.rs` `filter_entry` matches `UNIVERSAL_SKIP` against the entry basename (`d.file_name()`) at any depth. But the premise that `watcher.rs::is_in_skip_dir` uses a *different* (top-of-tree-only) rule is **false**: it does `abs.strip_prefix(root)` then `rel.components().any(|c| skip_dirs.contains(c))` — i.e. it matches a skip name at **any** project-relative component, exactly like the walker. So for `root/src/build/mod.rs` both skip it; for anything inside the tree the two produce **identical** drop decisions. They can only differ for directories *above* the root, which the walker never visits. So there is no silent walker↔watcher inconsistency and no divergent stale-index behavior. The any-depth universal skip (`node_modules`, `dist`, `build`, `vendor`, `venv`, …) is deliberate, gitignore-style, and consistent across both halves. (Separate, minor design consideration — not this bug: a project with a *legitimate* source dir literally named `build`/`dist`/`vendor` can't currently un-skip it via `.code-index-ignore`. If that ever matters, the enhancement would be root-anchoring the universal list or an allow-list override — happy to track that separately if wanted.)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
h-dv/code-index#13
No description provided.