Skip to content

Commit e8a8442

Browse files
committed
docs(spec): 同步轮散文校订 —— 对 main@cdfbee2f0 实测后落笔 (#5239)
本 PR 的 spec 半边是契约文档,机械合并会把 base 时代的论断带上 main; 逐条对当前 origin/main 实测后校订: - FilterConditionSchema 的 NULL-safe $not 合规段:read-scope-sql 已由 #5326 对齐(#5297 关闭)、filter-normalizer 已由 #5335 对齐(#5325 关闭),七个面全部一致 —— 「尚未合规、指向 #5297」改写为已闭合的事实。 - 「Deliberately NOT declared here」:空组合子单位元由「两立场对峙、 上交 #5322」改为「#5322 已拍板取单位元,实施在 #5365(排在本 PR 之后 合入);main 上两个 analytics 编译器今天仍拒收,故本 PR 仍不在此声明, 声明随 #5365 翻正」;{ field: {} } 由「无后端设闸」改为「#5327 已闸 四家,driver-mongodb 是唯一还在作答的后端(#5376)」。 - filter-logic-conformance.ts 族 2/3 状态行同步重测:族 2 的后端阻塞 已清零,唯余 fixture 工作;族 3 的四家闸门已落,阻塞改为表形扩展 + mongodb(#5376)。族 1 段落一字未动 —— 由 #5365 在其同步轮删除, 已约定分工。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ErbEDVAg1No9gdg1pgDAGB
1 parent e5f4f16 commit e8a8442

2 files changed

Lines changed: 51 additions & 37 deletions

File tree

packages/spec/src/data/filter-logic-conformance.ts

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,13 @@
5454
* ## Three case families that are RULED but not yet enrolled
5555
*
5656
* All three were ruled by the maintainer and are implemented in some backends.
57-
* None is in the table, because **every one of them is red on at least one
58-
* enrolled backend today**, and a red row here does not enforce a ruling — it
59-
* just turns another lane's unfinished work into this table's failure. Each is
60-
* recorded with what was actually measured, against `main` at `175d789`, so the
61-
* next author does not have to re-measure. Add the rows in the PR that closes
62-
* the gap, not before.
57+
* None is in the table yet — a red row here does not enforce a ruling, it just
58+
* turns another lane's unfinished work into this table's failure, and each
59+
* family still has one blocker standing, named per family below. Family 1 is
60+
* recorded with what was actually measured against `main` at `175d789`;
61+
* families 2 and 3 were re-measured at this PR's 2026-08-05 sync against
62+
* `cdfbee2f0`, so the next author does not have to re-measure. Add the rows in
63+
* the PR that closes the gap, not before.
6364
*
6465
* ### 1. Boolean identities of the empty combinators (#5239)
6566
*
@@ -91,28 +92,32 @@
9192
*
9293
* A row whose column is NULL does not satisfy the negated condition and IS
9394
* returned. Landed in `driver-sql` via PR #5296; `driver-memory`, `formula`,
94-
* `driver-sqlite-wasm` and `driver-mongodb` already agreed. `read-scope-sql`
95-
* and `filter-normalizer` still emit a bare `NOT (…)` and return only row 2
96-
* where the others return rows 2, 3 and 4 — tracked by #5297.
95+
* `driver-sqlite-wasm` and `driver-mongodb` already agreed; `read-scope-sql`
96+
* was aligned by #5326 (closing #5297) and `filter-normalizer` by #5335
97+
* (closing #5325), so as of the 2026-08-05 sync (`cdfbee2f0`) every surface
98+
* answers this family the same way — no backend blocker remains.
9799
*
98-
* Enrolling this family also needs a fixture change, which is the other reason
99-
* it is not a one-line addition: every column of {@link FILTER_LOGIC_ROWS} is
100-
* non-null by construction, so a NULL-bearing column has to be added here AND
101-
* declared in all seven harnesses that seed it.
100+
* What still keeps it out of the table is the fixture: every column of
101+
* {@link FILTER_LOGIC_ROWS} is non-null by construction, so a NULL-bearing
102+
* column has to be added here AND declared in all seven harnesses that seed
103+
* it. That is the whole remaining work item, and it is why this family is not
104+
* a one-line addition.
102105
*
103106
* ### 3. `{ field: {} }` — a field constrained by zero operators (#5240)
104107
*
105-
* Ruled **REJECT** (`INVALID_FILTER`) on all four backends. No backend gates it
106-
* yet — the engine lane's four-backend gate is the next dispatch — and today
107-
* the repo gives four different answers: `formula` and `driver-memory` say
108-
* FALSE, `driver-sql` rejects at top level but says TRUE inside a combinator,
109-
* `read-scope-sql` throws its own fail-closed error, `driver-mongodb` emits an
110-
* exact-match on an empty document. Beyond that, {@link FilterLogicCase} has no
111-
* way to spell "this filter must be REJECTED": `expected` is a row-id list, and
112-
* an empty list means "matched nothing", which is precisely the FALSE answer
113-
* the ruling did NOT take. Enrolling this case needs the table's own shape
114-
* extended first (an `expectRejection` discriminant, or a sibling table) —
115-
* deliberately not invented here. The case lands with the four-backend gate.
108+
* Ruled **REJECT** (`INVALID_FILTER`), and since gated: #5327 landed the
109+
* refusal on `driver-sql` (top level AND inside combinators),
110+
* `driver-sqlite-wasm`, `driver-memory` (both filter surfaces) and `formula`,
111+
* one wording, `INVALID_FILTER` / 400. As of the 2026-08-05 sync
112+
* (`cdfbee2f0`) `driver-mongodb` is the one backend still ANSWERING it — an
113+
* exact-match on an empty document — tracked by #5376. What blocks enrolment
114+
* is the table's own shape: {@link FilterLogicCase} has no way to spell "this
115+
* filter must be REJECTED" — `expected` is a row-id list, and an empty list
116+
* means "matched nothing", which is precisely the FALSE answer the ruling did
117+
* NOT take. Enrolling this case needs the shape extended first (an
118+
* `expectRejection` discriminant, or a sibling table) — deliberately not
119+
* invented here. The case lands with that extension, alongside the
120+
* schema-side narrowing that stays with the spec lane.
116121
*/
117122

118123
import type { FilterCondition } from './filter.zod';

packages/spec/src/data/filter.zod.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -279,23 +279,32 @@ export type FilterCondition = {
279279
* `$nin` from being widened — `{ $not: { stage: { $ne: 'won' } } }` still means
280280
* "the column IS that value".
281281
*
282-
* Conformance status, honestly: `driver-sql` (PR #5296), `driver-sqlite-wasm`,
283-
* `driver-memory`, `formula` and `driver-mongodb` answer this way today.
284-
* `read-scope-sql` and the analytics `filter-normalizer`, both in
285-
* `packages/services/service-analytics`, still emit a bare `NOT (…)` and are
286-
* tracked by #5297 — declaring the rule here is what makes that gap a tracked
287-
* bug instead of an invisible one, per Prime Directive #10.
282+
* Conformance status, re-measured at the 2026-08-05 sync of this PR (main @
283+
* `cdfbee2f0`): EVERY surface answers this way today. `driver-sql` (PR #5296),
284+
* `driver-sqlite-wasm`, `driver-memory`, `formula` and `driver-mongodb`
285+
* already did; `read-scope-sql` was aligned by #5326 (closing #5297) and the
286+
* analytics `filter-normalizer` by #5335 (closing #5325). The gap an earlier
287+
* revision of this paragraph tracked is closed — declaring the rule here is
288+
* what turned it into a tracked bug instead of an invisible one, per Prime
289+
* Directive #10, and this sentence is kept as the record that the tracking
290+
* worked.
288291
*
289292
* ## Deliberately NOT declared here
290293
*
291294
* The boolean identities of the EMPTY combinators (`{ $and: [] }` = TRUE,
292-
* `{ $or: [] }` = FALSE, `{ $not: {} }` = FALSE) are implemented by the four
293-
* drivers but are NOT yet stated as contract, because two backends answer them
294-
* by refusing the filter instead — see the note in
295-
* `filter-logic-conformance.ts`. Likewise `{ field: {} }` (a field constrained
296-
* by zero operators), which #5240 ruled must be REJECTED but which no backend
297-
* gates yet. Declaring either before it is enforced everywhere would be exactly
298-
* the `declared ≠ enforced` shape this file exists to prevent.
295+
* `{ $or: [] }` = FALSE, `{ $not: {} }` = FALSE) are RULED — #5322
296+
* (maintainer, 2026-08-04) took the identity over the analytics compilers'
297+
* fail-closed throw — but not yet stated here as contract: on main today
298+
* `read-scope-sql` and `filter-normalizer` still refuse an empty `$and`/`$or`,
299+
* and the ruling's implementation PR #5365 (aligns both compilers, enrolls the
300+
* four cases in `FILTER_LOGIC_CASES`) is sequenced to land after this one. The
301+
* declaration flips to stated contract with that PR, not here — declaring it
302+
* first would out-run enforcement. Likewise `{ field: {} }` (a field
303+
* constrained by zero operators): #5240 ruled it REJECTED and #5327 gated
304+
* driver-sql / driver-sqlite-wasm / driver-memory / formula; `driver-mongodb`
305+
* still answers it (tracked by #5376), and the schema-side narrowing stays
306+
* with the spec lane. Declaring either before it is enforced everywhere would
307+
* be exactly the `declared ≠ enforced` shape this file exists to prevent.
299308
*/
300309
export const FilterConditionSchema: z.ZodType<FilterCondition, FilterCondition> = z.lazy(() =>
301310
z.record(z.string(), z.unknown()).and(

0 commit comments

Comments
 (0)