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
runtime: POST /analytics/query refuses the array where the objectui adapter now sends for every array-form filter — AnalyticsQueryRequestSchema.where is FilterConditionSchema, while lowerAnalyticsWhere (the gate ui#6302 measured) accepts filter AST #15828
Filed unassigned from the #15442 / #15449 consumer census (PM session session_01M59rPZZFzqhfMUPFqqZTkf, os-dev seat, 2026-09-05). Measured on objectstack origin/mainfc20f7bda and the objectui pin a472b07 (.objectui-sha).
Measured
AnalyticsQueryRequestSchema (packages/spec/src/api/analytics.zod.ts:50, AnalyticsQuerySchema.extend(...); where inherited from packages/spec/src/data/analytics.zod.ts:299, FilterConditionSchema) — safeParse({ cube, measures, dimensions, where }) with each shape (scratch tsx script against the spec source):
where <- record : ACCEPT
where <- ast_tuple_array : REFUSE ["invalid_type(expected record)","invalid_type(expected object)"]
where <- ast_single : REFUSE (same)
where <- rule_array : REFUSE (same)
The only HTTP entry runs exactly that parse first: packages/runtime/src/dispatcher-plugin.ts:1152 (server.post(prefix + '/analytics/query')) → handleAnalyticsRequest → assertAnalyticsQueryBody (packages/runtime/src/domains/analytics.ts:49-70, called at :102 and :125) → AnalyticsQueryRequestSchema.safeParse(body) → validationFailure(...) on failure. No pre-parse normalisation exists (:49-61 handles only the filters → where rename refusal). The SDK posts the payload verbatim (packages/client/src/index.ts:1647-1650).
Why it matters
objectui ObjectStackAdapter.aggregate() (pin a472b07, packages/data-objectstack/src/index.ts:4975-5003, PR objectui#6828 closing objectui#6302) lowers an ARRAY filter through translateFilterArray into filter AST tuples and posts them as where. That was the runtime prerequisite recorded for the element:number.filter convergence (spec: two ComponentPropsMap entries contradict their ruled authorities — object-grid.data vs ViewDataSchema, element:number.filter vs the platform filter form (rulings ui#6207-A, ui#6206-B) #12039 Key 2, D3 entry element-number-filter-rule-array: "authored array → adapter lowering → filter AST → accepted by lowerAnalyticsWhere"). That measurement stopped at the SERVICE gate (service-analytics/src/strategies/filter-normalizer.ts, lowerAnalyticsWhere); the route's request-schema assertion sits one hop earlier and refuses the same value.
So on a deployment that serves analytics through the runtime route, an element:number (array-only since spec: two ComponentPropsMap entries contradict their ruled authorities — object-grid.data vs ViewDataSchema, element:number.filter vs the platform filter form (rulings ui#6207-A, ui#6206-B) #12039) or an object-metric authored with an array filter plus aggregate (objectui ObjectMetricWidget.tsx:245-253 → ds.aggregate(... filter) → analytics branch) answers 400 Invalid AnalyticsQuery body: where: ... instead of the aggregate. Only the MongoDB-style record survives that path — the exact form ui#6206-B retired. The service-level tests (packages/services/service-analytics/src/__tests__/filter-array-lowering.test.ts:235, :332) call analyticsService.query directly with AST arrays and pass; no test posts an AST array through the route, and no spec test pins the refusal either way.
Not run end to end here: the runtime's dependency closure was not built under this measurement claim; the route function is 15 lines and calls the schema that was measured. "Read, not run" on the route hop; the schema verdict is a run.
The decision this needs (not taken here)
Contract-first: the spec says where is a FilterCondition; the service accepts a wider set than the spec declares. Either (A) AnalyticsQuerySchema.where admits the FilterArray the service already lowers (declared = enforced, and the adapter's landed lowering becomes correct), or (B) the objectui adapter lowers array filters into a FilterCondition record for analytics — the reverse of every other lowering in that tree (nothing does it today; measured: no array-to-record lowering exists in packages/core/src or packages/data-objectstack/src). Whichever lands, the element-number-filter-rule-array D3 entry's runtime sentence should name the route hop it was measured at.
Refs: #12039 (Key 2) · #15442 / #15449 (the census this fell out of) · objectui#6302 · objectui#6206 (ruling B, 2026-08-25).
Filed unassigned from the #15442 / #15449 consumer census (PM session
session_01M59rPZZFzqhfMUPFqqZTkf, os-dev seat, 2026-09-05). Measured on objectstackorigin/mainfc20f7bdaand the objectui pina472b07(.objectui-sha).Measured
AnalyticsQueryRequestSchema(packages/spec/src/api/analytics.zod.ts:50,AnalyticsQuerySchema.extend(...);whereinherited frompackages/spec/src/data/analytics.zod.ts:299,FilterConditionSchema) —safeParse({ cube, measures, dimensions, where })with each shape (scratch tsx script against the spec source):The only HTTP entry runs exactly that parse first:
packages/runtime/src/dispatcher-plugin.ts:1152(server.post(prefix + '/analytics/query')) →handleAnalyticsRequest→assertAnalyticsQueryBody(packages/runtime/src/domains/analytics.ts:49-70, called at:102and:125) →AnalyticsQueryRequestSchema.safeParse(body)→validationFailure(...)on failure. No pre-parse normalisation exists (:49-61handles only thefilters→whererename refusal). The SDK posts the payload verbatim (packages/client/src/index.ts:1647-1650).Why it matters
ObjectStackAdapter.aggregate()(pina472b07,packages/data-objectstack/src/index.ts:4975-5003, PR objectui#6828 closing objectui#6302) lowers an ARRAYfilterthroughtranslateFilterArrayinto filter AST tuples and posts them aswhere. That was the runtime prerequisite recorded for theelement:number.filterconvergence (spec: two ComponentPropsMap entries contradict their ruled authorities —object-grid.datavs ViewDataSchema,element:number.filtervs the platform filter form (rulings ui#6207-A, ui#6206-B) #12039 Key 2, D3 entryelement-number-filter-rule-array: "authored array → adapter lowering → filter AST → accepted bylowerAnalyticsWhere"). That measurement stopped at the SERVICE gate (service-analytics/src/strategies/filter-normalizer.ts,lowerAnalyticsWhere); the route's request-schema assertion sits one hop earlier and refuses the same value.element:number(array-only since spec: two ComponentPropsMap entries contradict their ruled authorities —object-grid.datavs ViewDataSchema,element:number.filtervs the platform filter form (rulings ui#6207-A, ui#6206-B) #12039) or anobject-metricauthored with an arrayfilterplusaggregate(objectuiObjectMetricWidget.tsx:245-253→ds.aggregate(... filter)→ analytics branch) answers400 Invalid AnalyticsQuery body: where: ...instead of the aggregate. Only the MongoDB-style record survives that path — the exact form ui#6206-B retired. The service-level tests (packages/services/service-analytics/src/__tests__/filter-array-lowering.test.ts:235,:332) callanalyticsService.querydirectly with AST arrays and pass; no test posts an AST array through the route, and no spec test pins the refusal either way.The decision this needs (not taken here)
Contract-first: the spec says
whereis aFilterCondition; the service accepts a wider set than the spec declares. Either (A)AnalyticsQuerySchema.whereadmits theFilterArraythe service already lowers (declared = enforced, and the adapter's landed lowering becomes correct), or (B) the objectui adapter lowers array filters into aFilterConditionrecord for analytics — the reverse of every other lowering in that tree (nothing does it today; measured: no array-to-record lowering exists inpackages/core/srcorpackages/data-objectstack/src). Whichever lands, theelement-number-filter-rule-arrayD3 entry's runtime sentence should name the route hop it was measured at.Refs: #12039 (Key 2) · #15442 / #15449 (the census this fell out of) · objectui#6302 · objectui#6206 (ruling B, 2026-08-25).
Generated by Claude Code