实现 #5334(analytics 第五道门:where 数组下沉)时路过,不属于该单范围面,按 Prime Directive #10 单独记在这里,unassigned。
一个缺陷的两半
作者写错一条筛选(拼错算子、{field: {}}、无法下沉的数组),analytics 会响亮拒收 —— 这是 #3948/#5240/#5325/#5334 一路建立的姿态,正确。但这个拒收到不了调用方:它以 500 ANALYTICS_QUERY_FAILED 落地,而不是 ADR-0112 的 400 INVALID_FILTER。两半各自成立,单修一半都不够。
半 A —— 消费面:/analytics/dataset/query 不读 code/status,改用 message 正则
packages/rest/src/rest-server.ts(analytics dataset 路由的 catch):
} catch (error: any) {
const msg = String(error?.message ?? error ?? '');
if (/not declared in the dataset|not backed by a declared relationship|.../.test(msg)) {
return res.status(400).json({ code: 'DATASET_INVALID', message: msg.slice(0, 1000) });
}
logError('[REST] Analytics dataset query error:', error);
res.status(500).json({ code: 'ANALYTICS_QUERY_FAILED', error: msg.slice(0, 500) });
}
被抛出的错误携带的 err.code / err.status 被丢弃;是否 400 由一串写死的 message 子串决定。ADR-0112 的整个意义是错误自带机器可读的语义码,这里把它换成了字符串嗅探 —— 措辞一改,分类就变,而措辞在这一族单子里几乎每周都在改。
半 B —— 生产面:filter-normalizer.ts 的多数拒收是裸 Error
packages/services/service-analytics/src/strategies/filter-normalizer.ts 里已有的四处拒收都是 throw new Error(...),不带 code/status:
对照:driver-sql、driver-memory、driver-mongodb 的同类拒收全部走 unsupportedFilterError → INVALID_FILTER / 400(ADR-0112),#5334 新落的数组拒收也是。所以同一个作者错误,走 find() 得 400,走图表得 500。
现象
dashboard widget 的筛选里拼错一个算子 → 前端看到 500 + ANALYTICS_QUERY_FAILED,读作「平台炸了」,而不是「你的筛选写错了」。运维告警按 5xx 计。#5334 之后新增的无法下沉数组拒收同样落进这条路:service 侧带着正确的 INVALID_FILTER / 400,REST 面把它降级成 500。
建议(供分诊,不代表已定)
顺序上先 B 后 A,或一并:B 让 analytics 的 filter 拒收统一走一个 unsupportedFilterError 等价物(该文件里 #5334 已落了 invalidFilterError,四处沿用即可);A 让 REST 面先读 error.status / error.code,正则名单退化成没有信封时的兜底(或直接删掉,等 B 落地后)。
单修 A:今天只有 #5334 那一处拒收带信封,其余仍是 500。单修 B:REST 面照旧嗅探 message,信封仍被丢弃。
未验证
没有测量真实 dashboard 里作者写错筛选的频率;严重度请按 triage 定。搜过 open issues(filter-normalizer / INVALID_FILTER / ADR-0112 analytics / ANALYTICS_QUERY_FAILED),没有已存在的同题单。
关联:#5334(第五道门,本发现的来源)、#5240、#5325、#3948、ADR-0112。
实现 #5334(analytics 第五道门:
where数组下沉)时路过,不属于该单范围面,按 Prime Directive #10 单独记在这里,unassigned。一个缺陷的两半
作者写错一条筛选(拼错算子、
{field: {}}、无法下沉的数组),analytics 会响亮拒收 —— 这是 #3948/#5240/#5325/#5334 一路建立的姿态,正确。但这个拒收到不了调用方:它以500 ANALYTICS_QUERY_FAILED落地,而不是 ADR-0112 的400 INVALID_FILTER。两半各自成立,单修一半都不够。半 A —— 消费面:
/analytics/dataset/query不读code/status,改用 message 正则packages/rest/src/rest-server.ts(analytics dataset 路由的 catch):被抛出的错误携带的
err.code/err.status被丢弃;是否 400 由一串写死的 message 子串决定。ADR-0112 的整个意义是错误自带机器可读的语义码,这里把它换成了字符串嗅探 —— 措辞一改,分类就变,而措辞在这一族单子里几乎每周都在改。半 B —— 生产面:
filter-normalizer.ts的多数拒收是裸Errorpackages/services/service-analytics/src/strategies/filter-normalizer.ts里已有的四处拒收都是throw new Error(...),不带code/status:Unsupported filter operator "$foo" on "col"(算子不在词表)"col" carries a field constraint with zero operators ({})({ field: {} }(零个操作符的字段约束)在同仓有三个答案:driver-sql 组合子内 TRUE、顶层抛 INVALID_FILTER、formula/driver-memory FALSE #5240)"$between" on "col" needs a two-element [min, max] array"$and"/"$or" requires a non-empty array/ branches must be filter objects对照:
driver-sql、driver-memory、driver-mongodb的同类拒收全部走unsupportedFilterError→INVALID_FILTER/ 400(ADR-0112),#5334 新落的数组拒收也是。所以同一个作者错误,走find()得 400,走图表得 500。现象
dashboard widget 的筛选里拼错一个算子 → 前端看到 500 +
ANALYTICS_QUERY_FAILED,读作「平台炸了」,而不是「你的筛选写错了」。运维告警按 5xx 计。#5334 之后新增的无法下沉数组拒收同样落进这条路:service 侧带着正确的INVALID_FILTER/ 400,REST 面把它降级成 500。建议(供分诊,不代表已定)
顺序上先 B 后 A,或一并:B 让 analytics 的 filter 拒收统一走一个
unsupportedFilterError等价物(该文件里 #5334 已落了invalidFilterError,四处沿用即可);A 让 REST 面先读error.status/error.code,正则名单退化成没有信封时的兜底(或直接删掉,等 B 落地后)。单修 A:今天只有 #5334 那一处拒收带信封,其余仍是 500。单修 B:REST 面照旧嗅探 message,信封仍被丢弃。
未验证
没有测量真实 dashboard 里作者写错筛选的频率;严重度请按 triage 定。搜过 open issues(
filter-normalizer/INVALID_FILTER/ADR-0112 analytics/ANALYTICS_QUERY_FAILED),没有已存在的同题单。关联:#5334(第五道门,本发现的来源)、#5240、#5325、#3948、ADR-0112。