Repository navigation
analytics: 只用来限定「日期区间」的 timeDimension 被补上默认 dateGranularity,于是网格被静默按月拆分 —— 「按 Owner 统计」加个日期筛选就变成「按 Owner × 月」 #5688
Description
Activity
分诊:转
needs-user-decision,预挂domain:services。- 落点:
packages/services/service-analytics/src/dataset-executor.tsbuildQuery的resolvedTimeDims默认粒度回填。过时前提检查:origin/main(39e43c8)上该块与正文引用原样在,前提成立。 - 为什么进决策箱:两个已立案的需求在同一处相反 ——
compareTo需要「窗口条目不得抑制分桶」(代码注释自陈,Analytics query builder ignores widget dateGranularity, sortBy/sortOrder, and funnel stage order #3588/fix(service-analytics): compareTo 带上 measure 自己的 filter,__compare 列不再是另一个 measure (#4820) #4870 修复线),而窗口-only 条目被回填默认粒度会把「日期筛选」静默变成「再加一层分组」,行数与列集都变。修法判据(如「dimension ∈selection.dimensions或调用方显式写 granularity 才回填」)是改变响应形状的公共契约取舍,且要同时裁定 compareTo 在窗口-only 情形下的对齐语义;立单 dev([17.0-rc2验收] analytics: 带 measure-scoped filter / derived 度量的 dataset 查询,响应 fields 丢失维度描述符 → 表头回退成原始维度名(如 "owner" 而非 "Owner") #5537 实施者)已明确不代裁。可达性不低(HotCRM 类 dataset 普遍声明dateGranularity,dashboard 日期筛选器普遍只发dateRange)。 - 附属症状(被投影时间列在
fields里缺label)同根因,已被 [17.0-rc2验收] analytics: 带 measure-scoped filter / derived 度量的 dataset 查询,响应 fields 丢失维度描述符 → 表头回退成原始维度名(如 "owner" 而非 "Owner") #5537 的 PR 以成对控制用例钉住并指向本单,裁决后一并处理。 - 查重:org 内
timeDimensions granularity/dateRange dateGranularityopen 面均仅本单;analytics: ObjectQLStrategy 静默忽略 timeDimensions[].dateRange —— 恰好是 date-granularity 图表必走的那条路 #3650/dashboard 的日期区间上界打在datetime列上丢失当天数据 —— 默认配置即命中 #3777 已关闭且为另一件事(立单人已自查,复核一致)。
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- 落点:
- added a commit that references this issue
on Aug 6, 2026 处置(2026-08-06):退回派发队列。
复核结论:这是恢复已确立不变量(「与
find()给出相同的行集,或以 INVALID_FILTER 拒收——不允许第三种更安静的答案」),非产品分叉,不占决策箱。修法判据:timeDimensions 条目仅当 ∈
selection.dimensions、或调用方显式写了 granularity/selection.dateGranularity时才回填粒度;纯窗口条目保持纯窗口(dateRange是 filter,只减行、不改网格形状)。验收:窗口-only 条目不产生网格列/不裂行;被选中或显式粒度的条目保持分桶(钉住 #3588/#4870,compareTo 对齐不回归);compareTo 主/比较趟成对用例;顺手收掉 #5691 钉住的 label 富化盲区。量级 M。
⚠️ 派发排程:与 #5739 同落service-analytics,不同轮派发。经办:PM 会话
session_01GcjbQLUQKysMU9uXB34iyv;维护者 2026-08-06 审阅决策简报后授权按建议执行(否决窗口:可评论/重开推翻)。
Generated by Claude Code
【裁决落地】维护者 2026-08-06 批复全舰队决策箱评估报告(批复「同意」),本单裁定:
裁「回填判据收窄」——仅当该 timeDimension 同时出现在
selection.dimensions、或作者显式给了 granularity 时才回填默认 dateGranularity;纯日期窗口用途不再被静默按月拆分。同场必答项:compareTo 在窗口-only 情形的对齐语义须在同一实现中定义并测试——回填本是 #3588/#4870 的刻意修复,两个已立案需求在同一处相反,必须写成对用例钉住双向行为,防翻烧饼回归。
流转:摘
needs-user-decision→pm:queue,归 services 车道。评估与落地会话:
session_01N3uGFF8teXbpgtbEJ1aYXu
Generated by Claude Code
排程注记(services 座位,第 2 轮选批时记录 —— 延后不是搁置,已知坑先写在单上):
- 同文件串行:本单落点
dataset-executor.ts的buildQuery/resolveDimensionGranularity,与 analytics dataset 路由:另有九处「作者/调用方形状」的 dataset 拒收仍答 500 —— 它们从来没进过 #5352 的正则名单,所以 #5367 的信封化也没覆盖到 #5716(九处拒收信封化,其中四处在同一文件 :466-532)同文件。analytics dataset 路由:另有九处「作者/调用方形状」的 dataset 拒收仍答 500 —— 它们从来没进过 #5352 的正则名单,所以 #5367 的信封化也没覆盖到 #5716 已于第 2 轮派发,本单严格后轮(预计 R3),开工前基于含 analytics dataset 路由:另有九处「作者/调用方形状」的 dataset 拒收仍答 500 —— 它们从来没进过 #5352 的正则名单,所以 #5367 的信封化也没覆盖到 #5716 的合并后 main。 - 翻 pin 义务:[17.0-rc2验收] analytics: 带 measure-scoped filter / derived 度量的 dataset 查询,响应 fields 丢失维度描述符 → 表头回退成原始维度名(如 "owner" 而非 "Owner") #5537 的 PR 已把「两条路径一致的既有行为」用成对控制用例钉住并明确指向本单(
dataset-dimension-field-descriptors.test.ts)—— 本单落地时那组 pin 是要翻的靶,翻后必须承重(断言窗口型 timeDimension 不再分桶的实质),不是删断言。 - compareTo 约束:
buildQuery上方长注释记录了补默认粒度的存在理由(compareTo 需要「窗口条目不得抑制分桶」)—— 修法判据要同时保住 compareTo 对齐路径,analytics: 只用来限定「日期区间」的 timeDimension 被补上默认 dateGranularity,于是网格被静默按月拆分 —— 「按 Owner 统计」加个日期筛选就变成「按 Owner × 月」 #5688 正文已述。 - 关联提示:fix(service-analytics): 即席推断的 Cube 把
owner.region当成关系穿越,不再铸成基表列region(#5739) #5923(analytics 自动推断路径:inferCubeFromQuery的 stripPrefix 把关系穿越owner.region铸成基表列region—— 基表恰好有同名列时静默筛/分组错列(两个策略、两个请求键均如此) #5739)只改了即席 cube 铸造时 timeDimension 的键,对本单「完全无影响」(dev 必答项已核);analytics dataset 路由:另有九处「作者/调用方形状」的 dataset 拒收仍答 500 —— 它们从来没进过 #5352 的正则名单,所以 #5367 的信封化也没覆盖到 #5716 的 dev 将回答其改动对本单的影响,派发本单前以其回答重定价。
Generated by Claude Code
- 同文件串行:本单落点
认领:PM 循环第 3 轮补入席(services 车道)
会话:session_015a5qkLzpGXhLL2F5gvJ7dD
分支:claude/issue-5688-window-timedim-no-bucket
Worktree:objectstack-issue-5688
域:domain:services
文件面:packages/services/service-analytics/src/dataset-executor.ts(buildQuery/resolveDimensionGranularity)+analytics-service.ts仅限 label 富化盲区若属同根因(:915 一带,按裁决范围内判)+dataset-dimension-field-descriptors.test.ts(#5537 成对控制用例 = 翻转靶)+ 同包测试;⛔ 不触本文件今日 #5963 刚信封化的四处 throw(其测试须保持绿)
串行约束已清:前序 #5716→PR #5963 已 MERGED(其必答项答「完全无影响」—— 重定价:成本模型不变);同包无其它在飞;基于合并后 origin/main(今日 fb3d99b/#5963 均触过本文件,正文行号已过期按内容定位)执行口径:排程注记(13:0xZ 本单评论)四条照旧;裁决与前提随派发令发出。
Generated by Claude Code
验收:ACCEPT → PR #6003(CI 全绿,随后转 ready 入队,本座位跟到 MERGED)。
- 裁决「回填判据收窄」落在唯一正确的位置(
resolvedTimeDims),且把「要不要分桶」与「桶多大」两个问题显式拆开(resolveDimensionGranularity未动)—— 本单成因即两问混在一处,注释里写明了。 - 同场必答项(compareTo 对齐语义)按裁决在同一实现中定义并成对钉住,且带来超出预期的发现:窗口-only 情形的对齐是修好而非保住 ——
mergeByDimensions从不把回填桶列纳入合并键,旧行为里比较值落在最后写入行、其余行拿到自信的 0(实测 u1 compare 2→3)。KPI 单值卡同理修正。机制假设 1 未证伪,无 fork。 - fix(service-analytics): 带 measure-scoped filter / derived 度量的 dataset 查询,fields 也描述维度列 (#5537) #5691 现状先核(它是 [17.0-rc2验收] analytics: 带 measure-scoped filter / derived 度量的 dataset 查询,响应 fields 丢失维度描述符 → 表头回退成原始维度名(如 "owner" 而非 "Owner") #5537 的已合 PR,非待认领单)后正确收掉 label 盲区:扩查找不扩投影,「只富化、不造列」边界原样保留并注明为何不并
selectedDims。 - 翻 pin 承重(成对控制用例加断网格实质),拆半反向验证 8+1 红与预测逐例吻合,两半互不代偿;消费半径(rest 854 例、dogfood 18 例)与四组拒收信封测试全绿,fix(service-analytics): 十三处调用方形状的分析拒收改用自带信封的 4xx,不再答 500 (#5716) #5963 刚落的四处 throw 未触。
- 必答项 [finding]
queryDataset里还有第二个 message 嗅探器isMissingSourceError,命中即静默返回空结果 ——dataset-compiler的一条拒收措辞已经命中它,只因抛点在 try 之外才没出事 #5717:完全无影响,三条独立理由成立。 - analytics: compareTo 在「日期维度本身就是网格维度」时从不对齐 —— 比较行按自己平移后的桶键落地,于是每行一半是真值一半是自信的 0,还多出窗口外的幻影行 #6007 是本单最重要的衍生产出:compareTo 在「日期维度即网格维度」的标准趋势+同比形状下从不对齐(比较行按平移后桶键追加为新行,半真值半 0,另加窗口外行;fix(service-analytics): compareTo 带上 measure 自己的 filter,__compare 列不再是另一个 measure (#4820) #4870 的 fake 固定桶键掩盖了它)—— 改前改后逐字节相同、非本 PR 引入,已按纪律立单并在新用例里作为「未改变的长期行为」原样断言,裁定后可直接作靶。待分诊定级(建议高优先:这是 compare 功能在最常见形状下的正确性缺陷)。
经办:services 座位,会话
session_015a5qkLzpGXhLL2F5gvJ7dD(第 3 轮补入席)。
Generated by Claude Code
- 裁决「回填判据收窄」落在唯一正确的位置(
立单于 #5537 的实施过程(PR 见该单)。与 #5537 的 fields 装配无关:下面的复现跑在 #5537 从未影响的那条「无 measure filter 单查询」路径上,且在
origin/main(c36abfe98,含 #5587/#5634/#5667)与 #5537 的分支上逐字节同样复现。范围外,单独立单。现象
一个 dataset selection 只把日期维度用作窗口(
timeDimensions: [{ dimension, dateRange }],不带granularity,也不把它列进selection.dimensions)——这正是 dashboard 日期区间筛选器的产物,executor 自己的注释就把它称作 "a dashboard date-range filter is the usual source"——结果网格却额外按该日期维度分桶:多出一列没人选过的时间列,行数按月裂开。复现
dataset(关键条件:日期维度声明了显式
dateGranularity):三条数据:
u1 @2026-01、u1 @2026-02、u2 @2026-01。selection —— 只按 owner 分组,日期只当窗口:
实测响应:
期望:2 行(
u1: 2、u2: 1),fields为owner+opp_count。落点
packages/services/service-analytics/src/dataset-executor.tsbuildQuery(origin/main c36abfe L888-L909):granularityFor走resolveDimensionGranularity(selection, name, datasetDefault),datasetDefault即「dataset 显式声明过dateGranularity」时编译出的单元素cube.granularities。于是一个只有dateRange的条目被补上granularity: 'month';而一旦条目带上 granularity,它就是 GROUP BY 项、并且按 #4033 被projectedDimensions(objectql-strategy.tsL1130,native 侧同义)投影成结果列。这条补默认值本身是刻意的,
buildQuery上方的长注释写明了理由:compareTo需要的正是「窗口条目不得抑制分桶」,否则主网格按月、比较网格按原始时间戳,两边维度键对不上,每个 compare 列都空。所以两种需求在同一处打架:判据看起来应该是「这个 dimension 是否出现在
selection.dimensions(或调用方自己写了 granularity)」,但这属于会改变响应形状的契约取舍,不该由我在 #5537 里顺手猜,故立单。触发条件与影响面
必要条件(三者同时):dataset 的该日期维度声明了显式
dateGranularity;selection 的timeDimensions条目不带granularity;selection.dateGranularity未设。HotCRM 一类 dataset 普遍声明dateGranularity,dashboard 的日期区间筛选器又普遍只发dateRange,因此可达性不低。命中时是行数与列集都变(不是纯元数据问题):一个「Won by Owner」表加上日期筛选后每人一行变成每人每月一行,KPI 单值卡会拿到多行里的第一行。
附带的次要症状(同一根因,同一条路径):这样投影出来的时间列在
fields里只有type没有label——analytics-service.ts的维度 label 富化(L915 起)只遍历selection.dimensions,看不到只在timeDimensions里的列。#5537 的 PR 把这一点当作两条路径一致的既有行为钉住了(dataset-dimension-field-descriptors.test.ts里成对的控制用例),并明确指向本单。不重复
已搜:
timeDimensions dateGranularity(命中 #3650/#3777,均已关闭且是另一件事:前者是dateRange被忽略,后者是上界打在 datetime 列上)、dataset-executor buildQuery grouping、dateRange granularity bucket dashboard widget rows、date range filter extra column group by month widget—— 无 open 重复。