fix(ck-cli): don't reduce the search root past the operands' shared parent - #184
Open
ak2k wants to merge 1 commit into
Open
fix(ck-cli): don't reduce the search root past the operands' shared parent#184ak2k wants to merge 1 commit into
ak2k wants to merge 1 commit into
Conversation
ak2k
force-pushed
the
fix/search-root-filesystem-walk
branch
from
July 29, 2026 03:39
e7f5534 to
243904a
Compare
ak2k
force-pushed
the
fix/search-root-filesystem-walk
branch
2 times, most recently
from
July 29, 2026 03:59
80ac541 to
f124d01
Compare
…arent `ck <query> docs/ notes.md` walks the entire filesystem. In find_search_root(), when the candidate is an *ancestor* of the current root, a loop walked that candidate up one parent at a time looking for an ancestor contained by the root. With the root the deeper of the two, that condition never held, so the walk ran to "/" and the root adopted it. The effect depends on operand order (a directory operand first triggers it) and shows up as an apparent hang, or as "Read-only file system (os error 30)" when ck tries to create an index at /. It needs no unusual setup -- two ordinary operands where one is a directory and the other lives beside it rather than inside it. Reduce to the longest common prefix of the paths' components instead, so the root is the operands' actual shared parent. This narrows the root to the shared prefix; it does not bound how wide that prefix may legitimately be, so operands whose only shared component is "/" (`/tmp/a` and `/var/b`) still root there, correctly. When the reduction is empty -- operands sharing no component at all -- keep the current root, which covers one operand, instead of falling through to the cwd fallback, which would cover neither. Six regression tests: the reported escape (both operand orders), the prefix reduction itself (neither operand containing the other, shared prefix deeper than "/"), the ordinary sibling case, the disjoint case that legitimately shares only "/", the empty-reduction guard, and order-independence across three operands. Adds CHANGELOG and UNEXPECTED.md entries.
ak2k
force-pushed
the
fix/search-root-filesystem-walk
branch
from
July 29, 2026 10:47
f124d01 to
010026c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
ck <query> docs/ notes.md— a directory operand plus a file beside it — roots the walk at/and traverses the whole filesystem. On currentmain:Where
/isn't writable it surfaces asRead-only file system (os error 30)instead — ck trying to index/. I found it after a ck process spent 4.5h walking a mounted cloud drive, downloading files as it went.Cause
In
find_search_root(), when the candidate is an ancestor of the current root, the second loop walks the candidate up looking for an ancestor contained by the (deeper) root — a condition that never holds, so it runs to/, which the trailingif root.starts_with(&candidate)then adopts.Fix
Reduce to the operands' longest common path prefix instead of walking either path up one parent at a time. Both containment fast-paths are kept as short-circuits.
Scope
This makes the root the operands' actual shared parent; it doesn't bound how wide that parent may legitimately be.
ck <query> /tmp/a /var/bstill roots at/, because/genuinely is their shared parent — unchanged here, and pinned by a test. If you'd want disjoint operands handled differently (per-operand walks, or an error), that's a separate behavioral decision.Verification
Six unit tests, including both operand orders and order-independence for N>2. Differential-tested against the old walk over 500k random operand sets: narrower in some, broader in none.
cargo test(91),clippy,fmtclean. CHANGELOG + UNEXPECTED.md entries included.Two things worth your call
a/x+b/y, or differing Windows drives) reduce to nothing. I keep the current root so one operand is still covered, rather than the old fall-through to.which covered neither. The dropped operand is silent — happy to add a warning if you'd prefer.