Skip to content

DatasetWidget 的交叉表(pivot ≥2 维)丢弃 __compare 列:配了 compareTo 的 pivot 静默无对比 #3614

Description

@yinlianghui

来自 #3337 / PR #3612 的实现过程,有意留在该 PR 之外(见下「为什么不顺手做」)。

事实

PR #3612 让 dataset 路径的 compareTo 真的跑通:窗口下沉到 selection.timeDimensions[].dateRange,执行器返回每个度量的 __compare 列(如 revenue__compare),渲染侧三条路径把它显示出来 —— KPI 显示 delta、扁平表格多一列、图表多一条覆盖序列。

交叉表(type: 'pivot' 且 dimensions.length >= 2)不在其中。 DatasetWidget.tsx 的 matrix 分支按 桶 × 度量 铺 cellCols,__compare 列既不进表头也不进单元格,行/列小计同理。所以一个配了 compareTo 的 pivot widget:查询正确、对比数据真的返回了、界面上一个字都看不到 —— 正是 #3337 要终结的「静默无对比」,只不过换了个 widget 家族。

复现:一个 type: 'pivot'、两个及以上 dimensions、带有界日期窗口 filter、compareTo: { kind: 'previousYear' } 的 dataset widget。

为什么不顺手做

不是遗漏,是没有唯一正确答案的布局决策,不该由实现者随手定:交叉表的列已经是 桶 × 度量,加入对比就成了 桶 × 度量 × 窗口,列数翻倍。至少三种合理形态:

  1. 每个度量列后紧跟一个对比列(与扁平表格一致,但列数翻倍、表头三层);
  2. 单元格内叠加(主值 + 下方小字对比值/百分比),列数不变但单元格变高;
  3. 只显示 delta%(替代而非新增对比列)。

三者对可读性、导出 CSV 的列结构、行/列小计的对应关系影响都不同。#3337 的验收只点名「渲染出对比列」,PR #3612 按扁平表格/KPI/图表三条路径兑现,交叉表明确留白并在代码注释里写明原因。

建议

先定形态(建议 2:交叉表的宽度本来就紧张,叠加不破坏既有列结构与导出),再实现;实现时注意 exportColumns 与 rowTotalById/colTotalById/grandTotal 三处小计是否也要带上对比值。

相关:#3337、PR #3612(packages/plugin-dashboard/src/DatasetWidget.tsx matrix 分支)。


Generated by Claude Code

Activity

  1. claude commented on Aug 7, 2026

    @claude
    Contributor

    Triage: needs-user-decision — the layout form has to be chosen before this is dispatchable

    Verdict. Escalated, not queued, and for the reason you gave rather than in spite of it: the defect is unambiguous but the fix has no unique correct shape, and the three candidate shapes differ in user-visible output — column count, header depth, CSV export structure, and how row/column subtotals correspond. That is product semantics, not an implementation detail a lane PM can settle inside a PR.

    Contrast with objectui#3606, triaged an hour ago and queued: there the options differed only in internal mechanism and produced the same user-visible result, so the lane could pick. Here they do not. That line is where this seat splits queue from inbox.

    The defect itself is not in doubt. PR #3612 delivered compareTo on the dataset path — window pushed down to selection.timeDimensions[].dateRange, executor returning <measure>__compare — and three render paths surfaced it (KPI delta, flat-table extra column, chart overlay series). The matrix branch of DatasetWidget.tsx lays out bucket × measure and never admits __compare into headers, cells, or subtotals. So a type: 'pivot' widget with ≥2 dimensions, a bounded date filter and compareTo runs a correct query, receives correct comparison data, and shows none of it — the same silent-no-comparison failure #3337 existed to end, relocated to another widget family.

    What the decision is. Adding comparison turns the crosstab's columns into bucket × measure × window:

    1. a comparison column after each measure column — consistent with the flat table, but doubles the column count and needs a three-level header;
    2. in-cell stacking (primary value with the comparison beneath) — column structure and export shape preserved, rows get taller;
    3. delta-% only, replacing rather than adding.

    Your recommendation is 2, on the grounds that crosstab width is already the scarce resource and stacking leaves the existing column structure and CSV export intact. That reasoning is recorded here as the default to accept absent a contrary preference.

    Whatever is chosen, this rides with it (from your body, and it is the part most likely to be forgotten): exportColumns plus all three subtotal paths — rowTotalById, colTotalById, grandTotal — need an explicit answer on whether they carry comparison values. A form decision that stops at the cell grid leaves three inconsistent surfaces behind.

    No domain:* (objectui is a whole-repo seat). ⛔ Do not dispatch until the form is chosen.

    Dedup (issues + PRs, three repos): no duplicate. #3337 / PR #3612 are the lineage; the matrix branch was explicitly and knowingly left out of that PR's scope.

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


    Generated by Claude Code

  2. os-project-manager commented on Aug 7, 2026

    @os-project-manager
    Collaborator

    Maintainer ruling — 2026-08-07. The maintainer reviewed the PM's three-axis analysis of the decision inbox and accepted the recommendations (「你帮我综合评估,我接受你的建议」). Recorded by the PM session; needs-user-decision comes off with this comment.

    Decision: Form 2 — in-cell stacking. Primary value with the compare value / delta beneath in smaller type; the pivot's column structure stays bucket × metric, unchanged.

    Two consequences ruled with it:

    • Subtotals carry compare: rowTotalById / colTotalById / grandTotal all show the stacked compare value, same treatment as data cells.
    • CSV export stays data-shaped, not display-shaped: exportColumns emits explicit flat metric__compare columns (display stacks; export is data — no stacked strings in cells).

    Rationale: pivot width is already the constrained resource; stacking preserves the existing column structure, header depth, and the subtotal correspondence that forms 1 and 3 both break — and it matches the filer's own recommendation.


    Generated by Claude Code

  3. self-assigned this
    on Aug 8, 2026
  4. yinlianghui commented on Aug 8, 2026

    @yinlianghui
    CollaboratorAuthor

    认领:PM 循环批 180(objectui 整仓席位,登记表 objectstack#4604)

    依 2026-08-07 维护者裁决执行:形态 2(单元格内叠加) + 三处小计(rowTotalById/colTotalById/grandTotal)同样叠加对比值 + CSV 导出保持数据形(exportColumns 出扁平 metric__compare 列,不导出叠加字符串)。与在飞 #3739/#3717/#3742/#3613 文件面零相交(#3613 在 data-objectstack,本单在 plugin-dashboard,同族不同文件,分诊已明确分单)。

    会话:session_01GTRjn8xBqp75dk7kFupVRt
    分支:claude/issue-3614-pivot-compare-stacking
    Worktree:objectui-3614
    文件面:packages/plugin-dashboard/(DatasetWidget.tsx matrix 分支 + 该包测试)(越界即停)


    Generated by Claude Code

  5. yinlianghui commented on Aug 8, 2026

    @yinlianghui
    CollaboratorAuthor

    实现完成,已开 draft PR #3757(分支 claude/issue-3614-pivot-compare-stacking)。

    前提复核(origin/main 5a297c3):matrix 分支确实一处不读对比列 —— cellCols 只按 桶 × 度量 铺,单元格是 fmtMeasure(fr[cc.measure], cc.measure),三处小计同理,且 exportColumns 里有一行显式的 isMatrix ? values : measureColumns 例外把对比列挡在导出之外。issue 描述成立,未发现前提过期。

    按 2026-08-07 裁决实现形态 2:单元格内叠加(主值在上、对比值 + delta 在下),列结构与表头层数不变;rowTotalById / colTotalById / grandTotal 同样叠加;exportColumns 去掉 isMatrix 例外,导出仍是扁平的 度量名__compare 列 + 裸数字。对比是否存在沿用既有的 comparedValues(从数据判定),没有新增开关。

    逆向验证先预测后跑,两个方向都对上:只回退渲染 → 两条叠加测试红(缺 matrix-cell-compare)、导出测试与三条回归钉全绿;只回退导出 → 只有导出测试红。本包 vitest 26 文件 218 测试全绿,type-check 无输出,lint 0 error,check-control-bytes OK。

    未发现越界问题,无新增 finding:plugin-report 的 DatasetReportRenderer 复用了同名 testid 但整条报表路径完全不支持 compareTo(全仓 __compare 只出现在 plugin-dashboard),所以那里没有"丢弃对比"的同类缺陷可报。


    Generated by Claude Code

  6. yinlianghui commented on Aug 8, 2026

    @yinlianghui
    CollaboratorAuthor

    验收:PR #3757 ACCEPT(会话 session_01GTRjn8xBqp75dk7kFupVRt,PM 循环批 180)。

    交付内容:按维护者形态 2 裁决落地——交叉表单元格内叠加(主值 + 下方小字对比值与 delta%),桶×度量列结构与表头深度不变;三处小计同款叠加;exportColumns 删掉 isMatrix 例外,CSV 导出扁平 metric__compare 列纯数字(显示叠加、导出数据形)。对比存在性从数据(comparedValues)检测,零新配置;delta 复用 #3612 的 computeMetricDelta 与 dashboard.trend.* 词汇不分叉;窗口名以表级 caption 标注。SKILL.md compareTo 节同步。

    证据:双腿逆向验证先预测后命中(revert 渲染→恰 2 红,revert 导出→恰 1 红,回归钉全绿);包内 218 测试全绿(新增 6);自扫超出门禁面(BOM/零宽/nbsp,一处字面 U+FEFF 主动改写为 转义);CI 全部落定零失败。文件面 4 文件全在 plugin-dashboard + changeset。


    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