v1.108.234 - duplicate source trees stop competing with the originals
backup, old and archive join the built-in directory skip list.
⚠ This is a behaviour change, not a pure fix. A directory with one of those three names is no longer indexed. If your project ships one, read the opt-out below before upgrading.
Why
A user indexed a project root — 1,824 files, roughly 40% actual sources, the rest docs, configs and backups — and got diluted ranking plus some queries returning empty. Re-indexing the crate alone fixed it. Their diagnosis was that jCodeMunch needed a default ignore list for non-source extensions.
⚠⚠ That remedy would not have fixed it, and finding out why is the actual content of this release.
There is no extension ignore list because the extension gate is an allow-list — 157 extensions across 77 languages, gated at index_folder.py:538 — so anything unrecognised is already dropped as wrong_extension. Verified against the tree: .md, .rst, .txt, .html, .ini, .cfg, .csv, .env and every backup suffix (.bak, .old, .orig, .backup) were already never indexed.
What actually dilutes is a duplicate source tree: a backup/, old/ or archive/ directory holding real .py / .go / .ts files, whose symbols are indexed twice and then compete with the originals in ranking. A ranking problem wearing an extension problem's clothes.
Also ruled out: 1,824 files is under the 2,000 JCODEMUNCH_MAX_FOLDER_FILES default, so it was not truncation.
The opt-out, because these are ordinary English words
A project can legitimately ship an archive/ module. exclude_skip_directories removes any entry from the built-in list, per-project:
⚠ Note the direction. JCODEMUNCH_EXTRA_IGNORE_PATTERNS only adds skips; this config key is the only one that removes a built-in. Every skip is also counted in discovery_skip_counts, so a surprised user can see which rule dropped what instead of guessing.
What is deliberately not covered
Plurals and variants. backups/, archives/, archived/, old_data/ and copy/ are still indexed. Widening to them is a separate decision with its own false-positive surface, so a test asserts their absence — extending the list later should be a decision, not a discovery.
Segment matching, verified rather than assumed
old is a substring of many legitimate directory names. Both index paths match whole segments — index_repo.should_skip_file against "/" + pattern, index_folder._build_skip_dirs_regex against an anchored ^(...)$ — so threshold/, household/, scaffold/, manifold/ and goldilocks/ are unaffected. Checked end-to-end on both paths, not read off the regex.
⚠ The negative tests are the load-bearing ones. If either matcher is ever loosened to a bare substring test, they fail — instead of a user silently losing every directory whose name ends in "old".
Documentation
TROUBLESHOOTING.md's "Ranking feels diluted after indexing a whole project directory" entry is updated in the same commit. It previously stated these names were not in the built-in skip list, which this release makes false, and it now covers both directions: which variants still slip through, and how to un-skip a directory you actually want.
Tests: tests/test_v1_108_234.py (34).
{ "exclude_skip_directories": ["archive"] }