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
Filed by the domain:services PM seat (session session_01UQgPSniH1GFM9ZDeGyuGUa) carrying the repair half of #12053, whose maintainer charter was measurement-only ("⛔ no fix before the answer"). The measurement is in; this card is what it scoped. Unassigned — grading is triage's, and there is a real grading question at the end of this body.
The verdict, and it is REACHABLE
#12053's probe answered its own question with a runtime reading and a positive control: an authored custom-SQL measure (AggregationMetricTypenumber / string / boolean) is not routed away — it reaches the ObjectQL engine.aggregate bridge un-refused.
I re-verified every load-bearing site on origin/main @ 22c42c9b2 rather than accepting the report:
claim
verified
ObjectQLStrategy.canHandle never inspects query.measures
✅ it reads query.cube and caps.objectqlAggregate only
resolveMeasureAggregation forwards Metric.type verbatim as the method
✅ method: direct.type === 'count_distinct' ? 'count_distinct' : direct.type, with field: direct.sql.replace(/^\$/, '') — so the whole SQL expression lands in field and 'number' lands in method
a twin refusal for this hazard class already exists in the same file
✅ the cross-object arm refuses a non-recombinable method by name
the in-memory path answers null through a switch default
✅
The two failure shapes, neither naming its cause: driver-sql throws INVALID_QUERY/400 blaming a function key the author never wrote, and the ObjectQL in-memory fallback answers null for every bucket, silently — the #4157 class in its null variant. The probe measured the contrast directly: an admitted sum measure returned 300 per bucket where the custom-SQL measure returned null.
Root cause: #4157 was fixed on one strategy of two
NativeSQLStrategy got EXPRESSION_METRIC_TYPES and its arm; its regression pin measure-expression-sql.test.tsforces objectqlAggregate: false, so the pin covers exactly one strategy. ObjectQLStrategy never got the matching partition. That is why a closed card's defect is live again on the sibling path — the pin could not see it.
The repair question — and why I think it inherits rather than needs a new ruling
The dev framed two options and recommended A:
A — refuse explicitly on the direct path, mirroring the refusal this same file already carries for the cross-object case: an INVALID_FIELD envelope naming the measure and saying the metric needs a native-SQL driver. Turns a silent null into a loud, correctly-attributed answer. Does not make the metric work on ObjectQL.
⭐ The inheritance argument, for triage to accept or reject. This looks like the same hazard class the maintainer already ruled on 2026-08-22 for the cross-object filter family (refuse at query time rather than send a member to an engine that answers wrongly), landed as #10861 and again as #11461 / PR #12022 today. The mother reasoning — the engine physically cannot evaluate this member, and a silent wrong number is worse than a loud refusal — transfers intact: here the engine physically cannot evaluate a raw SQL expression, and today it answers null under the author's own metric name.
⚠️ The dev named a candidate semantic difference honestly, and it deserves the re-check the inheritance rule requires: option A declares custom-SQL metrics native-SQL-only rather than making them portable, which sounds like a product-semantics statement about an authorable surface.
Measured against that concern: the file already makes exactly that statement for the neighbouring case — its cross-object refusal message ends "Use sum/count/min/max, or run on a native-SQL driver." So A does not create a portability posture; it applies the one already shipped, to a case that currently fails silently instead. On that reading the mother ruling's reason is not branch-specific, and A is a declared-≠-enforced restoration (it narrows the served set to match what the engine can actually do) rather than a new product decision.
⇒ Triage's call, not this seat's — domain:* and grading have one producer, and auto-adjudication is triage's alone. If triage accepts the inheritance, this is a queue Bug at the ruled shape. If triage judges the portability question genuinely open (i.e. the platform wants authored cubes to be driver-portable), then it is a decision card and B's contract question goes to the spec seat.
Scope, if it is graded as a queue Bug
The refusal arm on the direct path, mirroring the in-file twin: code/status per ADR-0112, naming the measure the author wrote and the metric type, with a pin asserting the loud refusal and the load-bearing negatives — an admitted sum measure still served and still reaching the engine carrying its own method (a "refuse every non-six method" implementation must go red), and the existing cross-object refusal keeping its exact message.
⚠️ Also worth carrying: NativeSQLStrategy's pin forces objectqlAggregate: false. Whatever lands here should be pinned in a way the other strategy's fixture cannot hide, or this defect returns the same way it returned this time.
One prediction the probe got wrong, reported rather than dropped
The dev expected the terminal fallback to make an undeclared measure answer COUNT(*) (#4157's question 1). Measured otherwise: a typo'd measure name is minted by inferMeasure as a sum over the key before the strategy is reached, so that line is defensive-only on this path. Recorded so the repair seat does not re-derive it — or mistake it for a second defect.
Refs: #12053 (the probe and its charter; verdict delivered) · #11833 (fork 2 consumes this answer) · #4157 (the closed prior instance, fixed on one strategy only) · #10861 / #11461 + PR #12022 (the mother ruling and its most recent application, same file) · #10576
Filed by the
domain:servicesPM seat (sessionsession_01UQgPSniH1GFM9ZDeGyuGUa) carrying the repair half of #12053, whose maintainer charter was measurement-only ("⛔ no fix before the answer"). The measurement is in; this card is what it scoped. Unassigned — grading is triage's, and there is a real grading question at the end of this body.The verdict, and it is REACHABLE
#12053's probe answered its own question with a runtime reading and a positive control: an authored custom-SQL measure (
AggregationMetricTypenumber/string/boolean) is not routed away — it reaches the ObjectQLengine.aggregatebridge un-refused.I re-verified every load-bearing site on
origin/main@22c42c9b2rather than accepting the report:ObjectQLStrategy.canHandlenever inspectsquery.measuresquery.cubeandcaps.objectqlAggregateonlyresolveMeasureAggregationforwardsMetric.typeverbatim as the methodmethod: direct.type === 'count_distinct' ? 'count_distinct' : direct.type, withfield: direct.sql.replace(/^\$/, '')— so the whole SQL expression lands infieldand'number'lands inmethodnullthrough aswitchdefaultThe two failure shapes, neither naming its cause:
driver-sqlthrowsINVALID_QUERY/400 blaming afunctionkey the author never wrote, and the ObjectQL in-memory fallback answersnullfor every bucket, silently — the #4157 class in its null variant. The probe measured the contrast directly: an admittedsummeasure returned300per bucket where the custom-SQL measure returnednull.Root cause: #4157 was fixed on one strategy of two
NativeSQLStrategygotEXPRESSION_METRIC_TYPESand its arm; its regression pinmeasure-expression-sql.test.tsforcesobjectqlAggregate: false, so the pin covers exactly one strategy.ObjectQLStrategynever got the matching partition. That is why a closed card's defect is live again on the sibling path — the pin could not see it.The repair question — and why I think it inherits rather than needs a new ruling
The dev framed two options and recommended A:
INVALID_FIELDenvelope naming the measure and saying the metric needs a native-SQL driver. Turns a silentnullinto a loud, correctly-attributed answer. Does not make the metric work on ObjectQL.functionmismatch behind #11833) #12053's second non-negotiable forbids widening the contract enum from the consumer side.⭐ The inheritance argument, for triage to accept or reject. This looks like the same hazard class the maintainer already ruled on 2026-08-22 for the cross-object filter family (refuse at query time rather than send a member to an engine that answers wrongly), landed as #10861 and again as #11461 / PR #12022 today. The mother reasoning — the engine physically cannot evaluate this member, and a silent wrong number is worse than a loud refusal — transfers intact: here the engine physically cannot evaluate a raw SQL expression, and today it answers
nullunder the author's own metric name.Measured against that concern: the file already makes exactly that statement for the neighbouring case — its cross-object refusal message ends "Use sum/count/min/max, or run on a native-SQL driver." So A does not create a portability posture; it applies the one already shipped, to a case that currently fails silently instead. On that reading the mother ruling's reason is not branch-specific, and A is a declared-≠-enforced restoration (it narrows the served set to match what the engine can actually do) rather than a new product decision.
⇒ Triage's call, not this seat's —
domain:*and grading have one producer, and auto-adjudication is triage's alone. If triage accepts the inheritance, this is a queue Bug at the ruled shape. If triage judges the portability question genuinely open (i.e. the platform wants authored cubes to be driver-portable), then it is a decision card and B's contract question goes to the spec seat.Scope, if it is graded as a queue Bug
The refusal arm on the direct path, mirroring the in-file twin:
code/statusper ADR-0112, naming the measure the author wrote and the metric type, with a pin asserting the loud refusal and the load-bearing negatives — an admittedsummeasure still served and still reaching the engine carrying its own method (a "refuse every non-six method" implementation must go red), and the existing cross-object refusal keeping its exact message.NativeSQLStrategy's pin forcesobjectqlAggregate: false. Whatever lands here should be pinned in a way the other strategy's fixture cannot hide, or this defect returns the same way it returned this time.One prediction the probe got wrong, reported rather than dropped
The dev expected the terminal fallback to make an undeclared measure answer
COUNT(*)(#4157's question 1). Measured otherwise: a typo'd measure name is minted byinferMeasureas asumover the key before the strategy is reached, so that line is defensive-only on this path. Recorded so the repair seat does not re-derive it — or mistake it for a second defect.Refs: #12053 (the probe and its charter; verdict delivered) · #11833 (fork 2 consumes this answer) · #4157 (the closed prior instance, fixed on one strategy only) · #10861 / #11461 + PR #12022 (the mother ruling and its most recent application, same file) · #10576