实现 objectstack#5450(清理 DatasetWidget.tsx 里那个裸控制字节)时在相邻两行发现的,按 Prime Directive #10 单独开单,不在 5450 的 PR 里顺手改。
位置
packages/plugin-dashboard/src/DatasetWidget.tsx,buildPivot() 里:
const rid = rowDims.map((d) => String(row[d] ?? 'EMPTY')).join(SEP); // SEP = U+0001
const cid = String(row[colDim] ?? 'EMPTY');
cellIndex.set(`${rid} ${cid}`, index); // 注意:空格
行 id 内部用的是一个"维度值不可能包含"的字符(U+0001,objectstack#5450 已把它改成可读的转义写法,运行时值不变),但行 id 与列 id 之间用的是一个普通空格 —— 而维度值里含空格是再常见不过的事("New York"、"In Progress"、"Closed Won")。
后果
当两行满足 rid1 + 空格 + cid1 === rid2 + 空格 + cid2 时,cellIndex 的后写者覆盖先写者,透视表那一格显示的是另一行的度量值。举例(行维度 region,列维度 quarter):
| 行 |
region |
quarter |
cell key |
| A |
New |
York Q1 |
New York Q1 |
| B |
New York |
Q1 |
New York Q1 |
两行落进同一个 key,cellIndex 只保留后者;drill-through 也是按这个 index 读 drillRawRows 的,所以钻取会一并钻到错的那行。
全程无报错、无警告 —— 只是格子里的数字不对。
触发面(如实说)
要求两个维度值恰好能在边界上"接得上",不是每天都撞;但维度值是任意用户数据,而且这是静默的数据正确性问题,不是渲染瑕疵。严重度请 triage 时按贵重口径判,我只按发现原样记。
为什么没在 objectstack#5450 里一起修
- 那一单的文件面是四个控制字节 +
KNOWN_OFFENDERS 基线,越界即停;
- cell key 的字符串形态被现有测试直接钉着(
expect(p.cellIndex.get('Open High')).toBe(0)),换编码要连同测试一起重写,属于另一个改动的完整范围。
建议方向
- cell key 不再依赖"不可能出现的字符":
JSON.stringify([rid, cid])(与 objectui#3388 对 include key、objectstack#5450 对告警去重 key 的处置同形),边界对任意维度值都无歧义;
- 顺带把
buildPivot 的用例从"只有一个行维度"扩到多行维度 —— objectstack#5450 补的那条用例已经开了个头,在那之前分隔符从来没被任何用例跑到过(改成空串也照样全绿)。
发现来源:objectstack#5450 / PR objectui#3389。
实现 objectstack#5450(清理
DatasetWidget.tsx里那个裸控制字节)时在相邻两行发现的,按 Prime Directive #10 单独开单,不在 5450 的 PR 里顺手改。位置
packages/plugin-dashboard/src/DatasetWidget.tsx,buildPivot()里:行 id 内部用的是一个"维度值不可能包含"的字符(U+0001,objectstack#5450 已把它改成可读的转义写法,运行时值不变),但行 id 与列 id 之间用的是一个普通空格 —— 而维度值里含空格是再常见不过的事("New York"、"In Progress"、"Closed Won")。
后果
当两行满足
rid1 + 空格 + cid1 === rid2 + 空格 + cid2时,cellIndex的后写者覆盖先写者,透视表那一格显示的是另一行的度量值。举例(行维度region,列维度quarter):NewYork Q1New York Q1New YorkQ1New York Q1两行落进同一个 key,
cellIndex只保留后者;drill-through 也是按这个 index 读drillRawRows的,所以钻取会一并钻到错的那行。全程无报错、无警告 —— 只是格子里的数字不对。
触发面(如实说)
要求两个维度值恰好能在边界上"接得上",不是每天都撞;但维度值是任意用户数据,而且这是静默的数据正确性问题,不是渲染瑕疵。严重度请 triage 时按贵重口径判,我只按发现原样记。
为什么没在 objectstack#5450 里一起修
KNOWN_OFFENDERS基线,越界即停;expect(p.cellIndex.get('Open High')).toBe(0)),换编码要连同测试一起重写,属于另一个改动的完整范围。建议方向
JSON.stringify([rid, cid])(与 objectui#3388 对 include key、objectstack#5450 对告警去重 key 的处置同形),边界对任意维度值都无歧义;buildPivot的用例从"只有一个行维度"扩到多行维度 —— objectstack#5450 补的那条用例已经开了个头,在那之前分隔符从来没被任何用例跑到过(改成空串也照样全绿)。发现来源:objectstack#5450 / PR objectui#3389。