You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding] a per-aggregation filter with $contains on a multiple lookup counts 0 on every driver while the same where finds the rows: the engine's aggregation evaluator never matches a stored array #20873
Filing gate: ① a defect with a named landing site: packages/objectql/src/having-filter.tsmatchesAggregationFilter, the engine's own evaluator for a per-aggregation filter. Finding class (a), with a (b) half. reach: measured at the public door POST /api/v1/data/:object/query on SQLite, PostgreSQL 16 and the in-memory driver. The measurement is the #20802 dev's, at origin/main688ddef3c3 with an uncommitted probe (os-dev-report 5912874377 on #20802, out_of_scope_findings[0]).
Filed by the domain:engine execution seat 1 (session_01DEvba2nBuD4tWzfq8r8NFY, os-support-ai). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.
What happens
The object has a multi-valued lookup owners. Rows d1 and d3 store an array that contains u1.
query
answer
right answer
where: { owners: { $contains: 'u1' } }
d1, d3 (2 rows) on all three drivers
2
aggregations: [{ count, alias n }, { count, alias m, filter: { owners: { $contains: 'u1' } } }]
m: 0 on all three drivers
m: 2
The per-aggregation filter runs on the engine's evaluator (matchesAggregationFilter), not on the driver.
That evaluator fails $contains on any non-string value.
It compares an $in list by whole value.
So a stored array never matches.
FILTER_OPERATORS' $contains docblock (@objectstack/spec) declares membership over a stored array, and where answers it that way. The b half: the evaluator does not do what the operator's declaration says for this storage form.
Scope for whoever takes it (⛔ not a ruling)
The per-aggregation filter answers $contains (and $in where it applies) on a stored array as where does on every driver, by the declared membership semantics.
Filing gate: ① a defect with a named landing site:
packages/objectql/src/having-filter.tsmatchesAggregationFilter, the engine's own evaluator for a per-aggregationfilter. Finding class (a), with a (b) half.reach:measured at the public doorPOST /api/v1/data/:object/queryon SQLite, PostgreSQL 16 and the in-memory driver. The measurement is the #20802 dev's, atorigin/main688ddef3c3with an uncommitted probe (os-dev-report5912874377 on #20802,out_of_scope_findings[0]).Filed by the
domain:engineexecution seat 1 (session_01DEvba2nBuD4tWzfq8r8NFY,os-support-ai). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.What happens
The object has a multi-valued lookup
owners. Rowsd1andd3store an array that containsu1.where: { owners: { $contains: 'u1' } }d1,d3(2 rows) on all three driversaggregations: [{ count, alias n }, { count, alias m, filter: { owners: { $contains: 'u1' } } }]m: 0on all three driversm: 2The per-aggregation
filterruns on the engine's evaluator (matchesAggregationFilter), not on the driver.$containson any non-string value.$inlist by whole value.So a stored array never matches.
FILTER_OPERATORS'$containsdocblock (@objectstack/spec) declares membership over a stored array, andwhereanswers it that way. The b half: the evaluator does not do what the operator's declaration says for this storage form.Scope for whoever takes it (⛔ not a ruling)
filteranswers$contains(and$inwhere it applies) on a stored array aswheredoes on every driver, by the declared membership semantics.havingshares the evaluator; measure it too.domain:engine): the engine-fed faces delete their hand-copied filter meaning (driver-sql, turso remote, memory query, mongodb, formula,having); the memory reference matcher retires (D6) #20822) deletes this face's hand-copied whole-day copies (F8). This is a different meaning, but the same file. Serial with #5930 step 4 (domain:engine): the engine-fed faces delete their hand-copied filter meaning (driver-sql, turso remote, memory query, mongodb, formula,having); the memory reference matcher retires (D6) #20822, or folded into it if triage prefers.Dedupe
mcp__github__search_issues, repo-scoped, open and closed, in the act that filed this card:groupBy/aggregationssilently dropssearch— grouped counts under a search are the unsearched counts #20358 (searchdropped undergroupBy), objectql + REST: a per-aggregationfilter(andhaving) compares a temporal comparand type-blind, not by the column's storage rule — an ISO instant on adatefield counts 1 where thewheretwin counts 3 #20176 (temporal comparand type-blind), service-analytics: object-form analyticswhereskips the shared comparand-shape face's other arms ($innull member,$gt: null, null/blank$betweenbound, scalar$in) that the FilterArray spelling refuses 400 #20010 (analyticswhereshape arms) and objectql: a per-aggregationfilterrefuses an unknown operator only when rows exist —aggregations: [{ filter: { amount: { $median: 1 } } }]answers 400 on a populated table and 200 on an empty one #20122 (unknown operator only on populated tables) are other defects of the same evaluator. None covers stored-array membership.Dedupe words:
per-aggregation filter $contains multiple lookup count 0·matchesAggregationFilter stored array membership·aggregation filter any memberGenerated by Claude Code