Skip to content

drivers(sql,turso): Unsupported aggregate function 两面都是裸 Error(code/status 皆 undefined),且三个 spec 已声明的聚合函数无任何 SQL 后端编译 #5907

Description

@os-zhuang

从 #5769 的实测中带出(该单只做条件层拒收闸;维护者在 #5769 正文点名同轮该看 remote-transport.ts:462,但实测发现它不是单面问题,单独修 remote 会制造一条 local/remote 叉,故按「明确说明不做及理由」拆出本单)。

事实一:同一条件,两处裸 Error

  • packages/drivers/driver-turso/src/remote-transport.ts:462
    throw new Error("Unsupported aggregate function: " + funcRaw)
  • packages/drivers/driver-sql/src/sql-driver.ts:6753(mapAggregateFunc,由 SqlDriver.aggregate:3103 调用)
    throw new Error("Unsupported aggregate function: " + func)

两处都不带 code / status。在 origin/main(5c94f833c)上实测 remote 面:

aggregate({ aggregations: [{ function: 'median' }] })
  → THREW code=undefined status=undefined msg="Unsupported aggregate function: median"

mapDataError 读 error.code / error.status 组装信封,两者皆无 → 落默认分支 →
只剩一个 error 字段装消息文本、没有 code,并按 500 一类记日志,而这本是 400 类
的调用方错误。这正是 #1116/#1117 给过滤器拒收补信封的同一个缺口,只是换了个入口。

只修 remote 会把事情变坏:remote 变成 INVALID_QUERY/400,local(SqlDriver,
Turso local 继承)仍是裸 Error —— 一个条件、两种线上身份、取决于 url,正是
#5769 花整单去关的那类叉,方向反过来而已。所以这单的落点是两面同改。

事实二:三个 spec 已声明的聚合函数没有任何 SQL 后端编译

packages/spec/src/data/query.zod.ts:108 AggregationFunction 声明 8 个:

'count', 'sum', 'avg', 'min', 'max', 'count_distinct', 'array_agg', 'string_agg'

SqlDriver.mapAggregateFunc 与 RemoteTransport.aggregate 各自只编译前 5 个,
后 3 个落同一句 Unsupported aggregate function。driver-mongodb
(mongodb-aggregation.ts:139/144/147)和 driver-memory
(memory-analytics.ts:866,count_distinct)则实现了其中若干 —— 即声明 ≠ 实现,
且各后端实现的子集还不一样(Prime Directive #10)。

于是 :462 这一句今天同时承担两种性质不同的条件:

  1. 协议根本没声明的函数名(median)—— 调用方写错了,INVALID_QUERY / 400 一类;
  2. 协议声明了、这个后端编不出的函数(count_distinct / array_agg / string_agg)
    —— 不是调用方的错,是能力缺口。

driver-memory 的 filter-refusal.ts 已经为过滤器算子画过这条线(#5345:
unknownFieldOperatorError 之于「协议没有这个算子」,对比「协议有、这个面降不下去」),
把两者合并成一句会告诉一个写 count_distinct 的看板作者说他打错字了。

建议落点(需要一次裁定,故不夹带在 #5769 里)

复现

// remote
const t = new RemoteTransport(); t.setClient(client);
await t.aggregate('deal', { aggregations: [{ function: 'median' }] });
// local
await new TursoDriver({ url: ':memory:' }).aggregate('deal', { aggregations: [{ function: 'count_distinct', field: 'stage', alias: 'n' }] });

两者都抛 Unsupported aggregate function: …,code / status 均为 undefined。

Activity

  1. claude commented on Aug 6, 2026

    @claude
    Contributor

    分诊:入队 pm:queue,域 domain:drivers。

    落点锚定:origin/main @ 7adc841 双面核实,两处裸 Error 都在:

    • packages/drivers/driver-sql/src/sql-driver.ts:6753
    • packages/drivers/driver-turso/src/remote-transport.ts:462

    两处都在 packages/drivers/driver-* ⇒ domain:drivers。正文「只修 remote 会制造一条 local/remote 叉」的论证分诊侧认可,落点确为两面同改。

    冻结指令核对(#5499):维护者 2026-08-05 的投入冻结只覆盖 driver-memory / driver-mongodb 两族。本单落 driver-sql + driver-turso,不在冻结面内 ⇒ 照常入队,不挂 pm:on-hold。

    ⚠️ 串行约束(同文件在飞):PR #5921(#5769,已认领)正在改同一个 remote-transport.ts 的条件层拒收。本单是同文件的聚合层 ⇒ drivers 车道请严格排在 #5921 落地之后,并在开工前重拉 origin/main(#5769 的信封形状会成为本单的体例先例)。

    事实二的分流:

    查重:三仓搜 Unsupported aggregate function / count_distinct,命中 #5769(母单)/ PR #5921 / #5918(analytics 关系穿越,另一轴);无重复入口。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. os-zhuang commented on Aug 7, 2026

    @os-zhuang
    ContributorAuthor

    车道裁决(第三档,带否决窗口) — 依据分诊 2026-08-06 的分流认定:两类措辞之分是 #5345 既有规矩的应用(它已在 driver-memory/filter-refusal.ts 上画过同构的线),非新裁决,故由 drivers 车道自裁,不占维护者决策位。维护者可评论/重开推翻。

    裁定:

    1. 两面同改(sql-driver.ts:7071 + remote-transport.ts:726),同一信封体例、首句逐字一致({ field: {} }(零个操作符的字段约束)在同仓有三个答案:driver-sql 组合子内 TRUE、顶层抛 INVALID_FILTER、formula/driver-memory FALSE #5240),体例先例取已落地的 drivers(turso): RemoteTransport 条件层的 $-算子键被当列名编译成静默空集 —— SqlDriver 已按 #5348 拒收,remote 是唯一剩余面(cloud#1077 移交) #5769/PR fix(driver-turso): RemoteTransport 拒收条件层的 $-算子键 —— 不再编译成静默空集/全表写 (#5769) #5921;
    2. 第 1 类 —— 协议未声明的函数名(如 median):调用方错误 → INVALID_QUERY / 400,措辞指路「不是已声明的聚合函数」;
    3. 第 2 类 —— 协议已声明、本后端编不出(count_distinct / array_agg / string_agg):能力缺口,不是调用方的错 → 取 ADR-0112 目录里的能力缺口码(NOT_IMPLEMENTED 或 UNSUPPORTED,由实施者按目录既有语义与 status 映射选定并说明理由;二者措辞必须可区分、且不得把作者说成打错字);
    4. ⛔ spec 半边不夹带:那三个「声明了但无 SQL 后端实现」的函数是否按 ADR-0049 enforce-or-remove 摘除,是 packages/spec 的改动与另一次裁决 —— 已另立 [rc.4] formula 字段声明的 scale: 2 不生效:数据 API 返回未舍入 double,详情页渲染 15 位小数 #6180 转 domain:spec 座位,本单只负责让运行时说实话。

    认领:PM 循环第 11 轮(drivers 车道,rc.5 后首批)
    会话:session_01WyvqvKMG6asi9aXjKE6xtx
    分支:claude/issue-5907-aggregate-function-envelopes
    Worktree:objectstack-issue-5907
    文件面:driver-sql/src/sql-driver.ts(:7071 区)+ driver-turso/src/remote-transport.ts(:726 区)+ 两侧拒收表测试 + changeset
    串行前置已清:#5921(条件层)、#6047、#6142 均已 MERGED。并行注记:#6075 同批在飞、同文件不同区(sql-driver.ts 的 :2091-2876 签名区 vs 本单 :7071 聚合区),零重叠,后落地者 rebase。


    Generated by Claude Code

  3. os-zhuang commented on Aug 7, 2026

    @os-zhuang
    ContributorAuthor

    订正上一条评论第 4 点的单号:spec 半边转单是 #6188(不是 #6180)。其余不变。


    Generated by Claude Code

  4. self-assigned this
    on Aug 7, 2026
  5. os-zhuang commented on Aug 7, 2026

    @os-zhuang
    ContributorAuthor

    复核:ACCEPT → PR #6204(PM 实测复核):

    一处如实记录的产品限制(不阻塞本单):/data 路由的 mapDataError 状态直通只覆盖 4xx,故本单声明的 501 在线上会被压成 500 INTERNAL_ERROR(连 code 一起丢)——这是 REST 边界的既有缺口 #5582,本 PR 是它的第一个活体生产者,证据已补进该单。驱动侧「在抛出点如实声明」(ADR-0112)已完成,修边界不在本单范围。

    CI 清零后转 ready 入队。


    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