Repository navigation
Description
Bug: atlas-core topics/projects filters are unescaped SQL LIKE patterns — %/_ in a filter value act as wildcards and a " crosses JSON element boundaries
pkgs/atlas-search/crates/atlas-core/src/filters.rs builds the topics/projects
filter (the values stored in l.topics / l.projects are JSON list text such as
["nixos","backup"]) as a raw LIKE pattern with the user-supplied value
interpolated verbatim:
Filters::where_clause(filters.rs:177-182):
clauses.push(format!("{col} LIKE ?"))with paramformat!("%\"{v}\"%")
forl.topicsandl.projects.Filters::session_clauses(filters.rs:213-218): the identical construction
for the Turso vector branch's session subquery.
There is no escaping and no ESCAPE clause anywhere in atlas-core. SQL LIKE
treats % as "any run of characters" and _ as "any single character", so a
filter value is a pattern, not a literal topic/project name:
Verified (laptop, origin/main a65000a)
- Rust probe through
atlas-coreitself (temporary test in a scan worktree at
a65000a,cargo test -p atlas-core --test probe_like):Filters::new
with topics["my_topic", "100%", "a\",\"b"]and projects["%"]emits
l.topics LIKE ?/l.projects LIKE ?clauses whose params are the raw
interpolations%"my_topic"%,%"100%"%,%"a","b"%,%"%"%in both
where_clauseandsession_clauses. - SQLite probe of exactly that pattern against JSON-list rows:
- filter
my_topicmatches["my-topic","other"]and["myXtopic"]
(the_wildcard) — neither row has a topic namedmy_topic; - filter
%matches every non-empty topics list
(["my-topic","other"],["myXtopic"],["a","b"],["100 days"]) —
the filter silently becomes a no-op; - filter
a","bmatches["a","b"]— the embedded"crosses the JSON
element boundary, so two distinct topics satisfy a filter for one
(nonexistent) topic; - filter
100%matches["100 days"]; - control filter
my-topicmatches only["my-topic","other"], as intended.
- filter
Why it matters
Filter-before-rank with exact classification filters is a headline contract of
atlas-core (filters.rs module doc; step-2 PR #5352). A topic or project whose
name legitimately contains _ (common: my_topic, pm_stack) over-matches
unrelated sessions, and a % value disables the filter entirely — wrong
results are returned as if the filter had been applied, with no error or note.
Because both branch constructions share the flaw, FTS and vector results are
affected identically, so fusion cannot mask it. The step-3 CLI (#5353) will
surface these filters directly to users.
Note on parity: the construction is inherited from the production Python's
Filters (the port mirrors its SQL byte-for-byte and the parity fixtures pin
it). This is a deliberate-deviation candidate: the fix changes the recorded
SQL/params for values containing %, _, \, or ", so the parity fixtures
should gain these cases as documented deviations rather than silently
diverging — the Python side carries the same bug and should get the same fix
or an explicit waiver.
Acceptance criteria
- A topics/projects filter value matches only a JSON element exactly equal
to it:%,_, and\in the value are treated as literal characters
(e.g. escaped with an explicitESCAPEclause), and a value containing
"cannot match across element boundaries. - Both construction sites are fixed consistently:
where_clause
(filters.rs, FTS/local) andsession_clauses(filters.rs, Turso vector
branch subquery). - New tests pin at least: filter
my_topicdoes not matchmy-topicor
myXtopicrows but does match amy_topicrow; filter%matches only
a literal%element (not every list); filtera","bdoes not match
["a","b"]; ordinary values (nixos) behave exactly as before. - The parity fixtures / step-6 Gate B (Atlas step 6: golden-parity gate (Gate B) + cutover #5356) record the changed params
for wildcard-bearing values as an intentional deviation from the Python,
or the Python construction is fixed in step with a note on this issue. - Existing atlas-core unit + parity tests pass (
cargo test -p atlas-core),
excepting fixture expectations updated per the previous criterion.
Activity
dezren39 commentedon Nov 4, 2026
🤖 Agent note · filed
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
4 remaining items
dezren39 commentedon Nov 5, 2026
🤖 Agent note · triaged
dezren39 commentedon Nov 5, 2026
🤖 Agent note · triaged (correction)
repo-health-code-pilot)effort/s; existingkind/bug,task/small-fix, andpriority/lowremain.dezren39 commentedon Nov 5, 2026
Bound and launched OpenCode session
ses_e5e56110d2fffevRYx4fXqxZ1tfor queue task 9838 (issue #5375). The task was already claimed and handed off byrepo-worker-code.dezren39 commentedon Nov 5, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 5, 2026
🤖 Agent note · blocked