Skip to content

两处 filter-operator 平价测试从 spec 词表里减去 is_empty / is_not_empty,但没有一条断言这两个 token 仍在词表里 #3628

Description

@yinlianghui

发现于 #3601 / PR #3623(修那单时顺手排查同类结构,未在该 PR 修)。

现象

两个 spec 平价测试各自维护一个排除集,从 spec 派生的 VIEW_FILTER_OPERATORS 里减去同样两个 token:

  • packages/plugin-list/src/__tests__/filter-operator-ast-parity.test.ts:35 —— HANDLED_BEFORE_MAPPING = new Set(['is_empty', 'is_not_empty'])
  • packages/data-objectstack/src/filter-operator-ast-parity.test.ts:34 —— NOT_THIS_ADAPTERS_JOB = new Set(['is_empty', 'is_not_empty'])

两处的排除理由都成立(视图层在 mapOperator 被问到之前就把这两个改写成 [field, '=' | '!=', null],所以它们不需要 AST 拼写)。缺的是排除项本身的存活断言:没有任何一条断言 is_empty / is_not_empty 仍然是 VIEW_FILTER_OPERATORS 的成员。

一旦上游把这两个 token 从视图词表里退役或改名,排除集就变成一次空减法 —— 平价扫描依然全绿(它对剩下的 token 仍然是完整的),但排除行成了死重,注释还会继续告诉读者「视图层会先改写这两个」,而那时视图词表里已经没有它们了。

现状测量(objectui origin/main,@objectstack/spec@17.0.0-rc.5)

VIEW_FILTER_OPERATORS count: 19
is_empty       LIVE in spec
is_not_empty   LIVE in spec

今天两条都还在,排除是有效的 —— 这条是预防性的,不是已兑现的腐化。

为什么标 finding

今天没有用户会碰到:测试绿,行为无影响,排除项当前全部有效。代价是结构性的 —— 这正是 #3601 里 82 条拒绝名单烂掉 37 条的同一个形状:一份手写清单挂在 spec 派生的词表旁边,却没有一条断言清单成员仍然存在于那份词表。#3601 的 37 条恰恰是没人给它加存活断言,才一路积累到只有做审计时才被量出来。

对照组:仓里同类结构里,有两处已经把这件事做对了,可以直接抄——

  • packages/fields/src/widgets/__tests__/FilterConditionField.operators.test.ts:117 —— PR chore(deps): track the @objectstack family at 17.0.0-rc.5 and restore green #3568 给 KNOWN_UNREACHABLE 加的「每个排除 token 仍是 spec operator」断言。
  • packages/plugin-charts/src/__tests__/chart-type-spec-parity.test.tsx —— TRACKED_DIALECT 在 spec 收编条目时 console.info 提示删除,并在注释里写明它是上界而非期望。

反过来,FlowReferenceField.specDerivation.test.ts 的 EXPECTED_KINDS 是双向 pin + 显式反空断言,不属此类,无需处理。

建议处置(供参考,非结论)

每个文件加三行,与 PR #3568 同手法:

it('every excluded operator is still in the spec view vocabulary', () => {
  for (const op of HANDLED_BEFORE_MAPPING) {
    expect(
      VIEW_FILTER_OPERATORS.includes(op),
      `'${op}' is excluded from the bridge sweep but the spec no longer lists it`,
    ).toBe(true);
  }
});

严重性交 PM triage 判定,不自评。


Generated by Claude Code

Activity

  1. self-assigned this
    on Aug 7, 2026
  2. yinlianghui commented on Aug 7, 2026

    @yinlianghui
    CollaboratorAuthor

    认领(PM 派发)。


    Generated by Claude Code

  3. yinlianghui commented on Aug 7, 2026

    @yinlianghui
    CollaboratorAuthor

    验收 ACCEPT → PR #3640(session_01GTRjn8xBqp75dk7kFupVRt)。

    已核:两测试文件 +2 棘轮(42→44),既有断言零改动;CI 17 项 0 失败;逆向验证一对(塞 never_existed_op:修前 42 绿演示恒真 / 修后红且点名)与 #3623 同构落地。

    裁决记录:

    1. new Set<string> 替代 issue 示例的 .includes() 接受:spec d.ts 里该常量是 readonly 字面量元组,.includes(string) 是 TS 错误 — 类型层实测优先于正文示例,取舍已写明。
    2. 排除集两 token 实测 LIVE(19 项词表)与正文一致 — 本单纯预防,账目干净。
    3. 新发现 两处 filter-operator 平价测试的判别力已被上游词表增长抵消:VALID_AST_OPERATORS 现已逐字收录全部 19 个 view operator,断言即使 mapOperator 退化为恒等也仍绿 #3641 入池:同族反方向(词表增长 vs 退役)的判别力侵蚀 — mapOperator 恒等化照绿、?? op 兜底掏空覆盖断言、头注 8/19 失实为 0。其中 driver-sql 是否真编译 before/after 属 objectui 无法自证的上游问题,PM 后续决定是否转 objectstack 车道。

    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