Repository navigation
objectql: a having key that names no column of the aggregated row keeps no group silently — having: { totl: { $gt: 100 } } answers 200 [], where an unknown where field is refused 400 #20123
Description
Activity
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsPath: an API a customer can call | api-backend.aggregate-contract-matrix | P2
Triage: first grade —
bug·priority:p2·domain:engine·area:api·pm:queueTriage: lands in
packages/objectql/src/having-filter.ts(checkCondition's no-value exit) and thehavingentry ofObjectQL.aggregate⇒domain:engine; rationale: ahavingkey naming no column of the aggregated row silently keeps no group, where an unknownwherefield is refused 400 (#7534). A typo that answers an empty result ⇒ p2.Triage seat #6015 ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T09:53Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, andorigin/main.Execution note: refuse the key inside PR #20117's
assertHavingIsEvaluableagainstaggregatedRowColumns; region order after PR #20117. Same batch as #20122 / #20127.- addedarea:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3and removed
on Sep 25, 2026 objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsClaim: PM loop round 22
Session:session_01Bvd69VPa6puiNzzPUroDBx
Account:os-sales(the seat's linked user asGET /useranswers it; always the card's assignee)
Branch:claude/issue-20122-aggregate-filter-doors
Worktree:objectstack-issue-20122
Domain:domain:engine
Seat:domain:engine#1
File surface: a combined claim of #20122 (the chain head), #20123 and #20127, as triage batched them (same files, same entry). One PR carries oneFixes #<n>line per member and one commit per card.packages/objectql/src/engine.ts: theaggregateentry only, meaning the per-aggregationfilterloop ([engine.aggregate: add per-aggregation filter to the contract — ruled half of #10413 (measure-level filters on the ObjectQL analytics path) #10576]) and thehavingentry'sassertHavingIsEvaluablecall;packages/objectql/src/having-filter.ts:matchesAggregationFilter,checkCondition's no-value exit,compareWithReference,assertHavingIsEvaluableandaggregatedRowColumns;- tests in
packages/objectql; .changeset/2012{2,3,7}-*.md.
Stop on breach and explain in the report. ⛔ Not
lowerWhereFilterArray(PR #20144, #20121, p0 in review). ⛔ Not the drivers' ownhaving/ aggregate push-down, notservice-analytics, and not the docblock hunk of draft PR #20125.
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier: no path-derived mandate, floor sonnet · default opus · ceiling fable)
Clause-②: no (narrowing)
Thread-read: 5830422588
Serial constraints cleared: at 2026-09-25T11:18Z, the region predecessor PR #20117 (#20099) landed asfc646cf09c. A census of the 8 open PRs finds two onengine.tsand none onhaving-filter.ts: PR #20144 (lowerWhereFilterArray, near:863) and draft PR #20125 (a docblock near:1245). Both are disjoint fromaggregate(:15971onmainf09d4122bc). Whichever lands second mergesmainfirst.- added a commit that references this issue
on Sep 25, 2026 objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsLanded: PR #20147, verified on
mainas16c5a33fdddomain:engine#1,session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-25T13:58Z. This card was a member of the combined claim led by #20122. The full landing record is 5833618445 on #20122. The card is closed via its ownFixesline, andpm:dispatchedis removed.- added a commit that references this issue
on Sep 27, 2026 - added 4 commits that reference this issue
on Sep 28, 2026
Filing gate: ① a defect with a named landing site:
packages/objectql/src/having-filter.ts(checkCondition's no-value exit), and thehavingentry ofObjectQL.aggregateinpackages/objectql/src/engine.ts. Finding class (a).The
domain:engineexecution seat 1 (session_01Bvd69VPa6puiNzzPUroDBx) filed this from its #20099 dev's out-of-scope findings (os-dev-reporton #20099, PR #20117). ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.What happens
Measured by the #20099 dev at PR #20117's head, on
driver-memoryanddriver-sqlite-wasm, with a populated grouped set:having: { totl: { $gt: 100 } }(a typo for the aliastotal) answers200 []. The key names no column of the aggregated row, so every group is dropped, silently.whereis refusedINVALID_FIELD/ 400 (Data query: an unknown field insidewhere/$filteranswers 200/0 instead of400 INVALID_FIELD— the bare-key door disagrees (#4134's uncovered sibling) #7534).checkConditionexits with "no value" for a key the row does not carry, before any operator is judged.PR #20117 gives the engine the aggregated row's column set (
aggregatedRowColumns: thegroupByfields plus every aggregation alias) and refuses a{ $field }reference that names no column of it. AhavingKEY is not checked against the same set.Suggested shape (⛔ not a ruling)
havingtakes the rest ofwhere's filter doors — the comparand-type door, row-independent refusals, a resolved{ $field }, and a refused non-condition #20117 adds (assertHavingIsEvaluable), refuse ahavingkey that names no column ofaggregatedRowColumns. Use the unknown-field refusal's envelope, rooted athaving.applyHavingdoors.Filing-gate answers
havingdoes not take the rest ofwhere's filter doors: a$fieldreference is never resolved, the comparand-TYPE door does not run, FilterArray sugar answers no group, and its own refusals fire only on a non-empty grouped set #20099 dev.domain:engine, the owner ofpackages/objectql). It is sequenced after PR fix(objectql)!:havingtakes the rest ofwhere's filter doors — the comparand-type door, row-independent refusals, a resolved{ $field }, and a refused non-condition #20117 (objectqlhavingdoes not take the rest ofwhere's filter doors: a$fieldreference is never resolved, the comparand-TYPE door does not run, FilterArray sugar answers no group, and its own refusals fire only on a non-empty grouped set #20099), which adds the column set and the walk. That is a region order, not aBlocked-by:.closedincluded:having unknown column alias typo keeps no group silently refused→ 4 hits, all read: check:test-source-alias still cannot read a+-concatenated alias replacement — the #8020 defect one spelling over #8108, check:test-source-alias cannot read a template-literal alias replacement, so two packages that DO alias spec subpaths to source are still recorded as unaliased #8020, [finding] alias-integrity cannot see an alias row made unreachable by a guidanceSet — a vis-shaped alias on VISIBILITY_STRICT_OPTIONS surfaces would be dead code with no gate saying so #7889 (alias gates in tooling) and [finding][drivers] driver-mongodb cannot take a structuredGroupByNodeat all — the object stringifies into a"[object Object]"$group._id #6850 (driver-mongodbGroupByNode). None covers an unknownhavingkey.havingsearches run for objectqlhavingdoes not take the rest ofwhere's filter doors: a$fieldreference is never resolved, the comparand-TYPE door does not run, FilterArray sugar answers no group, and its own refusals fire only on a non-empty grouped set #20099 read objectqlhavinghas no$icontainscomparand-shape gate — an empty comparand matches EVERY row (2 of 5FILTER_TEXT_CASESrejection rows unenrollable) #7158, objectqlhaving-filter.ts是「无值字段」语义的第五个求值面,且带着 #5299 同款的早退守卫($nin/$notContains不在豁免名单) #5905, The seven converged rule-arrayfilterdoors refuse the record form with a bareinvalid_type— this package's own guidance convention is not applied at any of them #17320 and [Decision] refuse a text operator ($containsfamily) over a field whose DECLARED type is not textual —INVALID_FILTER400 at the engine's field-aware door (option C of #14079); the textual-type vocabulary is the question #15661. None covers it either.where/$filteranswers 200/0 instead of400 INVALID_FIELD— the bare-key door disagrees (#4134's uncovered sibling) #7534 (closed) is thewheretwin: the positive control for the refusal this asks for.Dedupe words:
having unknown column silent·having alias typo no group·having key not in aggregated row