实现 #5334 时路过,记录一条**观察类**发现(今天没有用户能撞到的行为差异),unassigned、不进队列。 ## 位置 `packages/services/service-analytics/src/analytics-service.ts`,`inferCube`(为没有注册 Cube 的自由查询即席合成一个 Cube): ``` if (query.where && typeof query.where === 'object' && !Array.isArray(query.where)) { // Canonical FilterCondition: top-level keys ... are field names. for (const key of Object.keys(query.where as Record< string, unknown >)) { ... } } ``` `!Array.isArray(query.where)` 这个守卫写于「数组 `where` 不是筛选」的年代。#5334 之后数组 `where` 是**真筛选**(`isFilterAST` → `parseFilterAST` 下沉),于是:数组写法的筛选所涉字段不会被种进即席 Cube 的 `dimensions`,对象写法的会。同一份筛选,两种写法,合成出两个不同的 Cube。 ## 为什么今天没有可观察后果(所以是 observation 类) `NativeSQLStrategy.resolveFieldSql` 在 cube 里找不到该 member 时**回落到裸列名**,所以 WHERE 子句照样编译、照样绑值、取到的行一致(#5334 的等价性用例覆盖的正是这条)。差异只落在即席 Cube 的 `dimensions` 清单上,而该清单在这条路上仅用于字段元数据与列歧义限定 —— 即席 Cube 是单表、无 join,没有歧义可限定。 会变成真缺陷的条件:即席路径将来长出 join,或者字段元数据/歧义限定开始依赖这份 `dimensions`。 ## 建议 守卫改成「先下沉再取键」(复用 #5334 落在 `filter-normalizer.ts` 的那次下沉,或直接 `parseFilterAST`),而不是把数组当非筛选跳过。规模很小,但**不该顺手塞进 #5334 的 PR** —— 那单的裁定范围就是 `normalizeAnalyticsFilterTree` 一处。 搜过 open issues(`inferCube` / analytics where dimensions),无同题单。 关联:#5334、#5158(拍板 C)、#5329。
Activity
os-zhuang commentedon Aug 5, 2026
发现分诊轮判级:晋级 —— 摘
finding换pm:queue,补domain:services。理由:过时前提检查通过(origin/mainanalytics-service.ts:1200的!Array.isArray(query.where)守卫仍在,#5334 的下沉工具已落地可复用),修法小而明确(守卫改「先下沉再取键」),且它是「即席路径长出 join 前」拆雷的窗口期修复——留到有可观察后果时再修,成本只会更高。本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-zhuang commentedon Aug 6, 2026
认领(services 车道 PM 派发,
session_01BWS4heBoAitLmzCLhcYdbK)claude/issue-5353-infercube-array-where../objectstack-issue-5353(dev 子代理按 worktree-first 自建)packages/services/service-analytics/src/analytics-service.ts(inferCubeFromQuery的!Array.isArray守卫改「先下沉再取键」)、同包测试、.changeset/*.md。where里点名不存在的字段仍然一路到驱动 —— #4437(measure)/ #5520(dimension)之后,filter 面是同一个缺陷剩下的第三个 param #5669(PR fix(service-analytics):where源字段闸门 —— 点名不存在字段的筛选答 400 INVALID_FIELD 而非驱动 500 (#5669) #5740)刚 merged。派发要点(来自 analytics:where里点名不存在的字段仍然一路到驱动 —— #4437(measure)/ #5520(dimension)之后,filter 面是同一个缺陷剩下的第三个 param #5669 报告):下沉直接复用normalizeAnalyticsFilterTree(该 PR 已在本文件 import 并验证),无需自接parseFilterAST;落地后即席 cube 的 dimensions 会多出数组 where 的键,resolveMemberSource对这些 member 从「未声明裸列」走到「已声明 dimension」分支 —— 两分支同源同判定,fix(service-analytics):where源字段闸门 —— 点名不存在字段的筛选答 400 INVALID_FIELD 而非驱动 500 (#5669) #5740 的闸门 doc 已写明,回归以此为准。analytics 自动推断路径:inferCubeFromQuery的 stripPrefix 把关系穿越owner.region铸成基表列region—— 基表恰好有同名列时静默筛/分组错列(两个策略、两个请求键均如此) #5739(stripPrefix 遮蔽关系穿越)是同函数邻居缺陷、产品裁定级,本单不碰。Generated by Claude Code
claude commentedon Aug 6, 2026
分诊备忘(同文件串行提示,未派发、不构成认领):
本单与新立的 #5739 同落
packages/services/service-analytics/src/analytics-service.ts的inferCubeFromQuery(origin/main889ae47:stripPrefix在 1152/1559,数组where守卫与其相邻)。按 SKILL step 3 的同文件串行纪律,两单不得同轮派发。更要紧的是成本耦合:#5739 请求的裁决是「
stripPrefix要不要区分<cube>.限定符与关系路径」,一旦裁「区分」,该函数的铸造判定本就要重写 —— 届时把本单的!Array.isArray(query.where)过时守卫在同一次改动里一并下沉,成本远低于分两次改同一个函数。#5739 正文亦如此建议。本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
fix(service-analytics): gate `where` source fields — a filter over a …
fix(service-analytics): lower the `where` before seeding an ad-hoc cu…
fix(service-analytics): an inferred cube lives only in its request — …