Symptom
$search is case-sensitive on textual fields, contrary to three declarations that all say case-insensitive: the cross-field-object-search checklist item title, the search-filter.ts docblock ("Matching: case-insensitive"), and the search-conformance ledger row.
POST /api/v1/data/showcase_account/query {"search":"Retail","searchFields":["name"]} returns 1 record ("Acme Retail"); the same query with "retail" returns [], total 0. Also reproduces for stark/Stark, wonka/Wonka, NORTHWIND. Reproduced on two fresh boots.
Cross-field OR scanning and multi-term AND semantics are correct; only the case-fold clause fails. Enum/select terms are unaffected because optionValuesMatching lowercases both sides in JS before emitting $in.
Root cause
packages/objectql/src/search-filter.tsfieldClausesForTerm emits {field:{$contains:term}} for textual types, and $contains is contractually case-sensitive (#4706 Q2=A). The #6518 SQLite LIKE→GLOB change removed SQLite's incidental ASCII fold, exposing this. The case-insensitive operator is $icontains: {name:{$icontains:'retail'}}does return "Acme Retail".
Confirmed still present on origin/main (76d74ecb): the docblock (line 18) still declares "Matching: case-insensitive", and fieldClausesForTerm still emits $contains (lines 91/93).
Decision dimension
The fix has a direction that is the maintainer's call:
- (A) make
$search emit $icontains for textual fields, so behaviour matches the three declarations; or - (B) change the three declarations to say case-sensitive.
Recommend (A): search is near-universally expected to be case-insensitive, and three places already declare it so. Whichever way #4706 Q2 finally lands, the three declarations (item title, search-filter.ts docblock, search-conformance ledger row) must be made consistent with the behaviour. Filed as a bug per maintainer instruction.
Reproduction
POST /api/v1/data/showcase_account/query {"search":"Retail","searchFields":["name"]}
→ 200, 1 record "Acme Retail"
POST /api/v1/data/showcase_account/query {"search":"retail","searchFields":["name"]}
→ 200, records [] total 0
{name:{$icontains:'retail'}} matches; {name:{$contains:'retail'}} does not. The dogfood pin stayed green because its only case assertion is a select label — a single lowercase-name assertion would catch this.
Source
Extracted from the QA run #7629 (framework 92f26f7, console 6314e87f).
Symptom
$searchis case-sensitive on textual fields, contrary to three declarations that all say case-insensitive: thecross-field-object-searchchecklist item title, thesearch-filter.tsdocblock ("Matching: case-insensitive"), and thesearch-conformanceledger row.POST /api/v1/data/showcase_account/query {"search":"Retail","searchFields":["name"]}returns 1 record ("Acme Retail"); the same query with"retail"returns[], total 0. Also reproduces forstark/Stark,wonka/Wonka,NORTHWIND. Reproduced on two fresh boots.Cross-field OR scanning and multi-term AND semantics are correct; only the case-fold clause fails. Enum/select terms are unaffected because
optionValuesMatchinglowercases both sides in JS before emitting$in.Root cause
packages/objectql/src/search-filter.tsfieldClausesForTermemits{field:{$contains:term}}for textual types, and$containsis contractually case-sensitive (#4706 Q2=A). The #6518 SQLiteLIKE→GLOBchange removed SQLite's incidental ASCII fold, exposing this. The case-insensitive operator is$icontains:{name:{$icontains:'retail'}}does return "Acme Retail".Confirmed still present on
origin/main(76d74ecb): the docblock (line 18) still declares "Matching: case-insensitive", andfieldClausesForTermstill emits$contains(lines 91/93).Decision dimension
The fix has a direction that is the maintainer's call:
$searchemit$icontainsfor textual fields, so behaviour matches the three declarations; orRecommend (A): search is near-universally expected to be case-insensitive, and three places already declare it so. Whichever way #4706 Q2 finally lands, the three declarations (item title,
search-filter.tsdocblock,search-conformanceledger row) must be made consistent with the behaviour. Filed as abugper maintainer instruction.Reproduction
{name:{$icontains:'retail'}}matches;{name:{$contains:'retail'}}does not. The dogfood pin stayed green because its only case assertion is a select label — a single lowercase-name assertion would catch this.Source
Extracted from the QA run #7629 (framework 92f26f7, console 6314e87f).