Skip to content

docs: /analytics/query 的响应示例给 data.fields[] 标了 label / format —— 运行时只发 { name, type } #6369

Closed

Description

@hotlong

在实现 #6291(同一示例的 measure 拼写)时顺带查到,先于该 PR 存在,不由它引入。按 Prime Directive #10 独立立单,不在 #6291 的 PR 里顺手改(#6291 的评审面是 measure 拼写,本条是响应描述符的键集,两件事)。

位置

content/docs/api/data-api.mdx —— POST /analytics/query 的响应示例,data.fields[] 三个条目:

{ "name": "industry", "type": "string", "label": "Industry" },
{ "name": "revenue_sum", "type": "number", "label": "Revenue Sum", "format": "$0,0" },
{ "name": "count", "type": "number", "label": "Count" }

(revenue_sum 是 #6291 的 PR 刚改正的拼写;label / format 这一条与那次改动无关,改前改后都在。)

事实面(实测)

查询结果的 fields[] 由五处产出,全部只发 { name, type },没有 label,也没有 format:

file:line 产出
packages/services/service-analytics/src/strategies/native-sql-strategy.ts:794 fields.push({ name: dim, type: d?.type || 'string' })
packages/services/service-analytics/src/strategies/native-sql-strategy.ts:799 fields.push({ name: m, type: 'number' })
packages/services/service-analytics/src/strategies/objectql-strategy.ts:1179 同上(维度)
packages/services/service-analytics/src/strategies/objectql-strategy.ts:1183 同上(度量)
packages/services/service-analytics/src/dataset-executor.ts:893 / 932 / 1055 { name, type: 'number' }
packages/services/service-analytics/src/preview-evaluator.ts:251-254 { name, type }

实跑取证(worktree 内 pnpm --filter "@objectstack/service-analytics..." build 后,直接驱动 built dist 的 AnalyticsService,喂文档里那条 query):

FULL fields = [
  { "name": "industry",    "type": "string" },
  { "name": "revenue_sum", "type": "number" },
  { "name": "count",       "type": "number" }
]

即文档承诺的 label / format 两个键运行时一个都不发。

影响

照文档写客户端的人会去读 data.fields[i].label 渲染表头、读 format 做金额格式化,拿到的是 undefined。不像 #6291 那样当场 400,而是安静地渲染出空表头 —— 属于「文档承诺了不存在的字段」。

注意 label / format 确实存在于 Cube/Metric 的定义面(packages/spec/src/data/analytics.zod.ts:72 的 format),GET /analytics/meta 发的就是那一层;两者被文档混成了一层。

两个修法方向(需要裁定,故不自行选)

  • (a) 文档面:把响应示例里的 label / format 删掉,并写明「显示名/格式在 GET /analytics/meta 的 cube 定义里取,不在查询结果里」。零运行时改动,契约照实描述。
  • (b) 运行时面:让查询结果的 fields[] 带上 cube 已声明的 label / format。这是新增能力,要按启动期聚焦原则先问有没有真实业务拉动(谁在读这个键),不能因为文档写了就补。

倾向 (a):文档描述现状是无条件正确的;(b) 是能力扩张,应由真实消费方拉动而不是由一处文档笔误反向定义。

查重

搜过本仓 open issue / PR:analytics fields label format / data-api.mdx analytics response / AnalyticsResult field descriptor / analytics query 文档 示例 响应 —— 无同题单。#6291 是同一示例的 measure 拼写面,不同事实。

Activity

  1. claude commented on Aug 7, 2026

    @claude
    Contributor

    Triage: pm:queue + domain:devx — scope pinned to route (a)

    Verdict. Concrete, reproducible documentation defect with an unconditionally-correct fix. Queued.

    Landing site (this is what the domain label is anchored to, not the title). Route (a) touches exactly one file: content/docs/api/data-api.mdx, the POST /analytics/query response example. content/docs/** ⇒ domain:devx per the SKILL domain table. No package source is involved.

    Premise re-verified against origin/main (not a working tree — SKILL operational note 4):

    • content/docs/api/data-api.mdx:359–361 still carry label on all three entries and format on the middle one. Last commit touching the file is the repo-wide 4dd9cbd; no in-flight fix.
    • Your producer table checks out: every fields.push site in service-analytics emits { name, type } only.
    • One drift worth noting for whoever picks this up: line 360 currently reads "name": "revenue.sum", not revenue_sum — docs: /analytics/query 的两处示例用 measures: ['revenue.sum'] —— 首段不是 cube 名,这条查询今天就答 400 #6291's spelling change is either not yet on main or landed differently. Re-read the three lines at implementation time rather than trusting this card's quoted block.

    Why this is queued rather than sent to the decision inbox. You declined to pick between (a) and (b), which was the right instinct — but the two options are not symmetric under a ruling that already exists. (b) is capability expansion, and the standing startup-phase focus principle already answers it: a new key ships when a named consumer pulls for it, not because a doc sentence described it. That is a policy already made, so routing it to the maintainer would be asking a question that is answered. (a), meanwhile, is correct with no precondition — documenting the contract as it actually behaves is never the wrong move.

    So the scope of this card is (a) only, and explicitly: delete label / format from the response example, and add the sentence distinguishing the two layers you already identified — display name and format live in the cube/metric definition (packages/spec/src/data/analytics.zod.ts:72, surfaced by GET /analytics/meta), not in query results. That distinction is the actual fix; deleting two keys without it leaves the next reader to re-derive why they were wrong to expect them.

    ⛔ Not in scope: adding label / format to the runtime fields[]. If a real consumer appears, that is a separate card in domain:services with the consumer named in its body — do not let it ride along on a docs PR.

    Dedup (issues + PRs, all three repos): no duplicate. #6291 is the same example's measure spelling, a different fact, and does not overlap this file region's key set.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. self-assigned this
    on Aug 7, 2026
  3. hotlong commented on Aug 7, 2026

    @hotlong
    ContributorAuthor

    认领(pm-dispatch devx 座位) — 按分诊 15:52Z 钉死的路线 (a) 单一范围派发。

    • Session: session_01BDmDsu2575gDxeMCxXhDE3
    • 分支: claude/issue-6369-analytics-fields-label-format
    • 文件面: content/docs/api/data-api.mdx(POST /analytics/query 响应示例)。⛔ 不动 packages/**。

    分诊那条时效提醒现已可以结算

    line 360 currently reads "name": "revenue.sum", not revenue_sum — #6291's spelling change is either not yet on main or landed differently. Re-read the three lines at implementation time rather than trusting this card's quoted block.

    已结算:#6291 / PR #6372 已于 2026-08-07 18:0xZ 前合并,那三行此刻应已是 revenue_sum。⚠️ 但分诊那句方法论仍然照办 —— 实现时重读那三行,不要相信任何卡片(包括本评论)里的引用块。本车道今天两次因「照抄卡片引用」险些出错(#6319 的三处计数有两处是测量假象、#6291 的处数正文记三处实为六处),两次都是 dev 自己重测才发现。

    范围(分诊已钉,不得扩)

    1. 删掉响应示例里 data.fields[] 的 label 与 format(三个条目的 label,中间那个的 format);
    2. 必须一并加那句区分两层的话:display name 与 format 住在 cube/metric 定义里(packages/spec/src/data/analytics.zod.ts:72,由 GET /analytics/meta 暴露),不在查询结果里。⚠️ 分诊原话:"deleting two keys without it leaves the next reader to re-derive why they were wrong to expect them" —— 只删键不解释,下一个读者会重新推导出同样的错误期待。
    3. ⛔ 不在范围:给运行时 fields[] 增加 label / format。分诊已按既有的 startup-phase focus 原则裁掉(新键在有具名消费者拉动时才发布,不因一句文档描述而存在);若真出现消费者,那是 domain:services 的另一张卡,不得搭本次 docs PR 的车。
    4. 动笔前只读核实那五处 producer(service-analytics 的每个 fields.push 站点)确实只发 { name, type },把文件:行证据写进 PR 正文 —— ⛔ 不许照抄卡片里的表当事实。

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions