Summary
PR #1421 established an invariant for the POSIX verbs: a path a routed verb returns must be a path the resolver accepts. ls, find (listing arm) and cat re-qualify the paths in their responses so a returned path can be fed straight back in.
find --meta does not. Its metadata arm returns search results, and those are not run through the re-qualification step. So:
find("second-project/notes", meta=[...])
returns rows whose file_path is project-relative. Feeding one of those back into ls or cat either refuses as unqualified, or — worse — resolves into a different project that happens to be mounted under that name.
Why it exists
#1423 (metadata predicates) was written before #1421's round-trip invariant landed. The two merged cleanly because they touch different arms of find(), so nothing failed; the metadata arm simply never learned the rule. No existing test covers it, which is why CI is green on both.
Fix
Re-qualify SearchResult.file_path for the metadata arm using the same route prefix the listing arm uses (_route_prefix / the qualify_* helpers in posix_tools.py), plus a test asserting the round trip — a routed find --meta result fed back into cat reads the same note.
Worth checking at the same time whether any other verb returns search results rather than listing nodes, since the same gap would apply there.
Note on the invariant's guard
#1421 added test_path_accepting_verbs_are_the_ones_covered_below, which derives the path-accepting verbs from the tools and asserts the set is exactly {cat, ls, find} — so a new verb cannot silently skip the rule. That guard does not catch this case, because find is in the set; it is one arm inside an already-covered verb that misses it. Worth considering whether the guard should assert per response shape rather than per verb.
Summary
PR #1421 established an invariant for the POSIX verbs: a path a routed verb returns must be a path the resolver accepts.
ls,find(listing arm) andcatre-qualify the paths in their responses so a returned path can be fed straight back in.find --metadoes not. Its metadata arm returns search results, and those are not run through the re-qualification step. So:returns rows whose
file_pathis project-relative. Feeding one of those back intolsorcateither refuses as unqualified, or — worse — resolves into a different project that happens to be mounted under that name.Why it exists
#1423 (metadata predicates) was written before #1421's round-trip invariant landed. The two merged cleanly because they touch different arms of
find(), so nothing failed; the metadata arm simply never learned the rule. No existing test covers it, which is why CI is green on both.Fix
Re-qualify
SearchResult.file_pathfor the metadata arm using the same route prefix the listing arm uses (_route_prefix/ thequalify_*helpers inposix_tools.py), plus a test asserting the round trip — a routedfind --metaresult fed back intocatreads the same note.Worth checking at the same time whether any other verb returns search results rather than listing nodes, since the same gap would apply there.
Note on the invariant's guard
#1421 added
test_path_accepting_verbs_are_the_ones_covered_below, which derives the path-accepting verbs from the tools and asserts the set is exactly{cat, ls, find}— so a new verb cannot silently skip the rule. That guard does not catch this case, becausefindis in the set; it is one arm inside an already-covered verb that misses it. Worth considering whether the guard should assert per response shape rather than per verb.