Summary
predicate_capture_and_value in crates/codemark-core/src/query/summarizer.rs detects #eq?/#match? predicates with a substring check:
if !(text.contains("eq?") || text.contains("match?")) { return None; }
"not-eq?".contains("eq?") and "not-match?".contains("match?") are both true, so a (#not-eq? @x "y") / (#not-match? @x "y") predicate is treated as a positive match. Its string literal can then populate QuerySummary.identifier / fallback_identifier / short_display(), mislabeling a bookmark row with a value the query explicitly excludes.
Impact
Latent / low today: this substring check pre-dates PR #222 (the refactor preserved it), and the query generator only ever emits #eq?. It bites only hand-edited or future-generated queries that use negative predicates.
Fix
Parse the predicate operator name and accept only exact eq? / match? (optionally any-eq?/any-match? if we want those), rejecting not--prefixed forms. Add regression tests asserting #not-eq?/#not-match? populate neither identifier nor short_display().
Raised by CodeRabbit on #222.
Summary
predicate_capture_and_valueincrates/codemark-core/src/query/summarizer.rsdetects#eq?/#match?predicates with a substring check:"not-eq?".contains("eq?")and"not-match?".contains("match?")are bothtrue, so a(#not-eq? @x "y")/(#not-match? @x "y")predicate is treated as a positive match. Its string literal can then populateQuerySummary.identifier/fallback_identifier/short_display(), mislabeling a bookmark row with a value the query explicitly excludes.Impact
Latent / low today: this substring check pre-dates PR #222 (the refactor preserved it), and the query generator only ever emits
#eq?. It bites only hand-edited or future-generated queries that use negative predicates.Fix
Parse the predicate operator name and accept only exact
eq?/match?(optionallyany-eq?/any-match?if we want those), rejectingnot--prefixed forms. Add regression tests asserting#not-eq?/#not-match?populate neitheridentifiernorshort_display().Raised by CodeRabbit on #222.