You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Decision] Two maintainer rulings collide on boolean aggregates — batch #59's "every other pair refused" would refuse avg(flag), which ruling #11152 pins on six backends as having no per-aggregate exception #16685
Surfaced by the at-tier contract review of PR #16684 (card #16353, the spec half of #16099) and verified independently by the domain:spec seat. ⛔ Not the dev's to resolve and ⛔ not this seat's: it is a conflict between two maintainer rulings, so it goes to the decision box rather than being settled in a PR.
The collision, measured
Ruling A — decision batch #59 (2026-09-06), which card #16353 implements. Its rows: count/countDistinct any type; sum numeric only (excluding percent); avg numeric including percent; min/max numeric plus temporal; "every other pair: refused". boolean and toggle are not numeric, so that default refusessum/avg/min/max over them. ⚠️ The ruling's text never names boolean — the refusal arrives via the sweeping default, not a considered call.
Ruling B — #11152 (2026-08-28), pinned in spec's own packages/spec/src/data/aggregation-conformance.ts and enrolled on six backends: sum(flag)=3, avg(flag)=0.5, min(flag)=0, max(flag)=1. Re-read on origin/main by this seat — :61 and :218 both say, in terms, "no per-aggregate exception".
Implementation agrees with B, not A: driver-sql emits a lowering cast for boolean aggregands on Postgres (sql-driver.ts:8497-8516, card #11635, closed).
⇒ A published compatibility table built from ruling A refuses a pair that ruling B requires every backend to answer, and that spec's own conformance suite pins.
⚠️avg(flag) is not a corner case: it is the "win rate / SLA-violation rate" shape from #11065 — the reason AGGREGATION_CASES exists.
Surfaced by the at-tier contract review of PR #16684 (card #16353, the spec half of #16099) and verified independently by the
domain:specseat. ⛔ Not the dev's to resolve and ⛔ not this seat's: it is a conflict between two maintainer rulings, so it goes to the decision box rather than being settled in a PR.The collision, measured
Ruling A — decision batch #59 (2026-09-06), which card #16353 implements. Its rows:⚠️ The ruling's text never names
count/countDistinctany type;sumnumeric only (excludingpercent);avgnumeric includingpercent;min/maxnumeric plus temporal; "every other pair: refused".booleanandtoggleare not numeric, so that default refusessum/avg/min/maxover them.boolean— the refusal arrives via the sweeping default, not a considered call.Ruling B — #11152 (2026-08-28), pinned in spec's own
packages/spec/src/data/aggregation-conformance.tsand enrolled on six backends:sum(flag)=3,avg(flag)=0.5,min(flag)=0,max(flag)=1. Re-read onorigin/mainby this seat —:61and:218both say, in terms, "no per-aggregate exception".Implementation agrees with B, not A:
driver-sqlemits a lowering cast for boolean aggregands on Postgres (sql-driver.ts:8497-8516, card #11635, closed).⇒ A published compatibility table built from ruling A refuses a pair that ruling B requires every backend to answer, and that spec's own conformance suite pins.
avg(flag)is not a corner case: it is the "win rate / SLA-violation rate" shape from #11065 — the reasonAGGREGATION_CASESexists.📋 四棱
avgover a boolean field returnsnullon driver-memory and a number on sqlite — same rows, same dataset, same executor #11065 的「胜率 / SLA 违约率」正是avg(flag),而AGGREGATION_CASES在六个后端上把四个布尔聚合答案钉死。⛔ 这不是「读起来像有用」,是已登记、已实现、已 pin 的能力。AGGREGATION_ROWShas no boolean column, so the cross-driver aggregation conformance family cannot see a boolean aggregand on any face #11152 的具名裁决(有 pin、有实现、有六后端登记)。反过来做,等于让一条一般性默认推翻一条专门裁决。四棱四条同向。⛔ 但这仍必须你裁:它是两条维护者裁决之争,置信门与代裁通道都够不到。
选项
sum/avg/min/max(批 Validation Protocol: Cross-Field, Async, and Conditional validation #59 的「其余全拒」对布尔类让位于 [finding]AGGREGATION_ROWShas no boolean column, so the cross-driver aggregation conformance family cannot see a boolean aggregand on any face #11152)。表增加boolean、toggle两个成员到那四行。AGGREGATION_CASES与driver-sql不动。AGGREGATION_ROWShas no boolean column, so the cross-driver aggregation conformance family cannot see a boolean aggregand on any face #11152 的 pin 与driver-sql的 PG cast 必须一并退役,AGGREGATION_CASES四个案例删除,avgover a boolean field returnsnullon driver-memory and a number on sqlite — same rows, same dataset, same executor #11065 的形状变成不可写 ——⛔ 无论哪一边,PR #16684 的 TSDoc 与 changeset 里那句「布尔就是发散类」都必须改 —— 它在本树上是假的,而且会进 CHANGELOG。该修正已作为补丁轮发给 dev,与本裁决无关、不等它。
影响面
avgover a datetime works on SQLite and errors on Postgres #16099(编译期拒收)与 devx lint 腿都pm:blocked在 spec: declare the aggregate × field-type compatibility matrix (AggregationFunction×FieldType) that dataset measures are refused against (spec half of #16099) #16353 上,会执行这张表 ——progress是否留在sum(裁决排除percent用的是isIncoherentAggregate的权威,而它没点名progress);count_distinct × percent(表按裁决收,isIncoherentAggregate标记不相容 —— 全叉积实测这是唯一分歧对)。维护者速读
事情。 我们在给「聚合函数 × 字段类型」建一张兼容表(哪些组合允许、哪些拒收),依据是你 9 月 6 日批 #59 的裁决。那条裁决说「列出的允许,其余全拒」。
问题是「其余」里扫进了布尔字段 —— 而你 8 月 28 日的另一条裁决(#11152)明确规定:布尔在每一个数据库后端上都按数字聚合,不设例外,而且这条已经写进 spec 的一致性测试、在六个后端上跑着,驱动层也为 Postgres 专门做了转换。
⇒ 两条裁决打架了。 新表会拒掉
avg(布尔字段)—— 也就是「胜率」「SLA 违约率」这类统计,而那正是当初 #11065 要的东西。选项。
席位意见:推荐 A。 四条评估轴罕见地全部同向。核心理由是:让一条笼统的默认推翻一条具名的、有 pin、有实现、六后端登记的裁决,方向反了。而且 B 是删除一个已经发布并且有保证的能力,不是收紧一个空声明。
风险与代价(含回滚)。 A 只改这张还没有人执行的表(加两个成员),回滚是一次 revert。B 要动三处已发布的东西,不可低成本回滚。⚠️ 有时限:执行这张表的两条消费腿正等着本卡;它们一落地,再改就是收窄一个已发布的拒收集,代价从「改一行」变成一次破坏性变更。
你要做的:选 A 还是 B?