Skip to content

两处 filter-operator 平价测试的判别力已被上游词表增长抵消:VALID_AST_OPERATORS 现已逐字收录全部 19 个 view operator,断言即使 mapOperator 退化为恒等也仍绿 #3641

Description

@yinlianghui

发现于 #3628 / PR #3640(给这两个文件的排除集加存活棘轮时顺手核对了文件头注的一处数字,未在该 PR 修 —— 越界)。

#3628 / #3601 是同一族腐化(平价守卫被上游词表漂移悄悄抵消),但方向相反:那两单是词表退役让手写清单变空减法,这一单是词表增长让断言失去判别力。

现象

packages/plugin-list/src/__tests__/filter-operator-ast-parity.test.ts 的文件头注写着(第 19-20 行):

They do NOT overlap: 8 of the 19 canonical view operators are absent from the AST set.

@objectstack/spec@17.0.0-rc.5 上实测,这句已经不成立 —— absent 的是 0 个,不是 8 个:

VIEW_FILTER_OPERATORS count: 19
view ops absent from VALID_AST_OPERATORS: 0  []

VALID_AST_OPERATORS 现有 51 项,已逐字收录全部 19 个 canonical view operator 拼写:

["!=","<","<=","<>","=","==",">",">=","after","before","between","contains","ends_with",
 "endswith","eq","equals","greater_than","greater_than_or_equal","greaterorequal",
 "greaterthan","greaterthanorequal","gt","gte","in","is_empty","is_not_empty",
 "is_not_null","is_null","isempty","isnotempty","isnotnull","isnull","less_than",
 "less_than_or_equal","lessorequal","lessthan","lessthanorequal","like","lt","lte","ne",
 "neq","nin","not_contains","not_equals","not_in","notcontains","notequals","notin",
 "starts_with","startswith"]

注意 before / after 都在里面 —— 而这两个正是当初写这些测试要钉的那次回归(canonical view operator 在 bridge 里没有条目,filter 被静默丢弃、返回全表)。

后果:两处断言已不再判别它们声称守卫的东西

plugin-list —— '%s maps to an AST-valid operator':

expect(VALID_AST_OPERATORS.has(String(mapOperator(viewOp)).toLowerCase())).toBe(true);

既然 19 个 view 拼写本身都已是 VALID_AST_OPERATORS 成员,那么即使 mapOperator 退化成恒等函数,这条断言依然全绿。同文件第二条(isFilterAST gate)同理,isFilterAST 也是拿 VALID_AST_OPERATORS 判的。

data-objectstack —— 'covers every canonical view operator the spec defines':

const target = FILTER_OPERATOR_ALIASES[op] ?? op;
return !VALID_AST_OPERATORS.has(String(target).toLowerCase());

?? op 的兜底意味着一个没有映射条目的 operator 落回原始 view 拼写 —— 而那现在恒为 AST-valid。所以FILTER_OPERATOR_ALIASES 整张表清空,这条断言也依然绿。这恰好是该文件头注自己警告的那件事:「a missing row in this table is not a validation failure, it is an unfiltered query」。

为什么标 finding

今天没有用户会碰到:bridge 本身仍然正确、映射条目都在、两个文件全部测试绿(PR #3640 上 44/44),行为无影响。代价是结构性的 —— 这两个文件是为一次已经发生过的静默数据泄漏(before/after 全表返回)写的回归网,而这张网现在对同类回归不再有反应。下一次有人删掉 FILTER_OPERATOR_ALIASES 里的一行,或让 mapOperator 少一个分支,这里不会红。

另外这也提出一个上游问题,objectui 侧无法自证:VALID_AST_OPERATORS 收录 before / after 只说明 isFilterAST() 不再拒绝它们,不等于 driver-sql 真的会把它们编译成 < / > 的 WHERE 子句。若后者未跟上,那就不是测试判别力问题而是又一次静默全表 —— 需要在 objectstack 侧核实。

可能的处置(供参考,非结论)

  • 头注那句「8 of the 19 … are absent」至少要按实测更正,否则它在教下一位读者一个错误的心智模型。
  • 断言要恢复判别力,得换一个不被词表增长抵消的支点。可选方向:钉 mapOperator输出而不是「输出是否 AST-valid」(如逐个 operator 钉期望的目标拼写);或在 data-objectstack 侧去掉 ?? op 兜底、改为断言映射条目存在。两者都会改动既有断言语义,属设计取舍,不宜由旁路 PR 顺手决定。
  • 若上游确已把 view 词表整体收编进 AST 词表(即 bridge 在设计上已成冗余),那正确处置可能是退役这两个文件的一部分断言而不是加固 —— 这需要先确认 driver-sql 的实际编译行为。

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


Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions