Skip to content

celEngine 的 classifyError 把「括号/方括号不配对」这类真语法错答成 kind: 'runtime',而该 kind 会原样出现在作者可见的拒写消息与 REST 响应体里 #6133

Description

@baozhoutao

范围外发现,出自 #4812 / PR #6130 的对拍测试(一条 fixture 断言 kind === 'parse' 意外翻红)。按 Prime Directive #10 记录,不指派。

事实(origin/main bc67c28e2 基线,实测)

packages/formula/src/cel-engine.tsclassifyError错误文案关键词分类:

function classifyError(err: unknown): EvalResult<never> {
  const message = err instanceof Error ? err.message : String(err);
  let kind: 'parse' | 'type' | 'runtime' | 'bounds' = 'runtime';
  if (/Exceeded max/i.test(message)) kind = 'bounds';
  else if (/parse|unexpected|syntax/i.test(message)) kind = 'parse';
  else if (/type|unknown variable|undeclared/i.test(message)) kind = 'type';
  return { ok: false, error: { kind, message } };
}

而 cel-js 8.0.0 对语法错并不只有一种措辞。实测五条:

源码 cel-js 首行错误 命中分支 得到的 kind
record.budget > Unexpected token: EOF unexpected parse
record.a $$ 1 Unexpected character: $ unexpected parse
record.a ?? 3 Unexpected token: QUESTION unexpected parse
((record.a) Expected RPAREN, got EOF runtime
[1,2 Expected RBRACKET, got EOF runtime

Expected RPAREN, got EOF 里既没有 parse / unexpected / syntax,也没有 type / unknown variable / undeclared,于是落到默认值 runtime括号、方括号、花括号不配对是最常见的手写语法错之一,恰好整类都落在这个洞里。

为什么这条是用户可见的(不是纯内部字段)

kind 不止用于内部分支,它被原样拼进作者读到的文案和 API 响应体:

  • packages/objectql/src/validation/rule-validator.ts:1262
    `Validation rule '${rule.name}' predicate failed to evaluate (${result.error.kind}: ${result.error.message}) — write rejected (#4649)`
  • 同文件 :1417,when-predicate 版本同构
  • packages/objectql/src/cel-fault.ts:75
    return `${error.kind}: ${first || 'unknown error'}`;
  • packages/rest/src/rest-server.ts:571
    ...(error?.kind ? { reason: error.kind } : {}) —— 进 HTTP 错误响应的 reason 字段

所以一条少写了一个右括号的校验规则,作者拿到的是 (runtime: Expected RPAREN, got EOF),REST 消费方拿到的是 reason: "runtime"。message 本身是对的,分类是错的 —— 而分类正是用来告诉作者"这该去哪儿修"的:runtime 指向数据/求值期,parse 指向"你的表达式写错了"。ADR-0032 D1d 要求消息面向自纠,这一格与之相悖。

影响面

classifyError 同时服务 celEngine.compilecelEngine.evaluate,所以 build 期(os build / os validate / os lint)与运行期(写入拒绝、REST)两侧都受影响

未量化 / 未主张

  • 没有统计真实 metadata 里不配对分隔符的出现频率。
  • 没有排查 cel-js 是否还有别的语法错措辞同样漏网(上表只穷举了我构造的五条);这个洞的成因是"靠文案关键词分类"这个做法本身,补关键词只是补当前已知的洞。

建议方向(供 triage,不代裁)

关键词匹配是脆的:cel-js 换一次措辞就再破一次。可考虑改读 cel-js 抛出的错误对象上的结构化信息(ErrorOptionscode,见 lib/index.d.ts:82-86),把分类建立在契约上而不是文案上;若结构化信息不足以区分,则至少把关键词表补全并加一组 fixture 钉住每一类措辞 —— 后者是止血,前者是根治。

关联

#4812 / PR #6130(发现出处;该 PR 的对拍测试里刻意没有把这条错误分类断言进去,并在注释里写明了原因 —— 断言它等于把这个 bug 钉成契约)。ADR-0032 D1d(自纠消息)。

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions