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
driver-memory's reference matcher still answers $notContains / $nin the pre-ruling way on a no-value row — the #5499 freeze that excused it dissolved 2026-08-11, so the divergence is now unexcused and untracked #13166
Split out of #13089 per its triage instruction ("若测出 HAVING 分歧在解冻后仍真实存在 ⇒ 停下,把它立成 domain:engine 的独立卡"). #13089 remains open and is not addressed by this card; that card's PR delivers only its sites 1-2 (the two pm-dispatch reference files).
The measurement
Run on branch claude/issue-13089-freeze-residue at merge-base 56470d86b, by execution (not by reading), against packages/drivers/driver-memory/src/memory-matcher.tsmatch(). Fixture: rows 1 (name: 'alpha-one'), 2 (name: 'beta'), 3 (no value) — measured under BOTH readings of "no value", name: null and the key absent. The platform-settled answer (#5146 extended by #5298 option A, re-affirmed after the #5299 reversal was costed and withdrawn) is that a no-value row SATISFIES a negation-carrying operator, i.e. ['2','3']:
Operator
name: null
key absent
ruling answer
$ne: 'alpha-one'
['2','3'] OK
['2','3'] OK
['2','3']
$nin: ['alpha-one']
['2','3'] OK
['2'] DIVERGENT
['2','3']
$notContains: 'one'
['2'] DIVERGENT
['2'] DIVERGENT
['2','3']
Three of six cells diverge. This reproduces exactly the cell already recorded in the filter-logic-conformance.ts measurement table ("driver-memory reference matcher | no — DIVERGENT, frozen (#5499) | MATCH on a null value, no on a missing key"), so the divergence is real, unchanged, and now unexcused.
Mechanism
Two independent causes in memory-matcher.tscheckCondition:
The pre-switch guard if (value === undefined && op !== '$exists' && op !== '$ne' && op !== '$null') return false; — its allowlist names $ne but not $nin / $notContains, so a MISSING key short-circuits to "no match" for those two before their arms ever run.
The $notContains arm itself: if (typeof value !== 'string' || value.includes(target)) return false; — a null value is not a string, so it fails on the type test rather than on the predicate. That is the name: null half, which the guard above does not reach.
driver-mongodb is NOT part of this: translateFieldOperators maps $nin straight through and compiles $notContains to { $not: { $regex } }, both of which match a missing/null field in MongoDB. It already agrees with the ruling.
Why this is now a card rather than a comment
Two in-code annotations still spell the freeze as LIVE and use it to excuse the divergence — they are #13089's sites 3-4 and were deliberately left untouched:
Both are wrong on two counts now: the freeze dissolved on 2026-08-11 (corroborated in the head note of packages/spec/src/data/aggregation-conformance.ts), and the driver-mongodb half of the claim was never true for this operator family. Rewriting them to past tense without deciding the divergence would have converted an actionable defect into settled-looking prose, which is what the #13089 triage forbade.
$exists is a separate, still-open cell — filter-logic-conformance.ts records that driver-memory's live mingo path and driver-mongodb both still read key-presence rather than has-value, which is why no $exists row can be enrolled yet. Not necessarily this card's scope, but it is the neighbouring cell.
Enrolment, not a row: the head note of filter-logic-conformance.ts is explicit that a row added ahead of a backend is just a red gate, and that the DEBT ledger in scripts/check-driver-conformance.mjs is per (driver x case-set), with no spelling for "fails one row of thirty-six".
Split out of #13089 per its triage instruction ("若测出 HAVING 分歧在解冻后仍真实存在 ⇒ 停下,把它立成
domain:engine的独立卡"). #13089 remains open and is not addressed by this card; that card's PR delivers only its sites 1-2 (the two pm-dispatch reference files).The measurement
Run on branch
claude/issue-13089-freeze-residueat merge-base56470d86b, by execution (not by reading), againstpackages/drivers/driver-memory/src/memory-matcher.tsmatch(). Fixture: rows1(name: 'alpha-one'),2(name: 'beta'),3(no value) — measured under BOTH readings of "no value",name: nulland the key absent. The platform-settled answer (#5146 extended by #5298 option A, re-affirmed after the #5299 reversal was costed and withdrawn) is that a no-value row SATISFIES a negation-carrying operator, i.e.['2','3']:name: null$ne: 'alpha-one'['2','3']OK['2','3']OK['2','3']$nin: ['alpha-one']['2','3']OK['2']DIVERGENT['2','3']$notContains: 'one'['2']DIVERGENT['2']DIVERGENT['2','3']Three of six cells diverge. This reproduces exactly the cell already recorded in the
filter-logic-conformance.tsmeasurement table ("driver-memoryreference matcher | no — DIVERGENT, frozen (#5499) | MATCH on a null value, no on a missing key"), so the divergence is real, unchanged, and now unexcused.Mechanism
Two independent causes in
memory-matcher.tscheckCondition:if (value === undefined && op !== '$exists' && op !== '$ne' && op !== '$null') return false;— its allowlist names$nebut not$nin/$notContains, so a MISSING key short-circuits to "no match" for those two before their arms ever run.$notContainsarm itself:if (typeof value !== 'string' || value.includes(target)) return false;— anullvalue is not a string, so it fails on the type test rather than on the predicate. That is thename: nullhalf, which the guard above does not reach.driver-mongodbis NOT part of this:translateFieldOperatorsmaps$ninstraight through and compiles$notContainsto{ $not: { $regex } }, both of which match a missing/null field in MongoDB. It already agrees with the ruling.Why this is now a card rather than a comment
Two in-code annotations still spell the freeze as LIVE and use it to excuse the divergence — they are #13089's sites 3-4 and were deliberately left untouched:
packages/objectql/src/having-filter.ts:40-42— "driver-memory / driver-mongodb still answer the old way only because [裁决] driver-memory / driver-mongodb 投入冻结 —— 维护者 2026-08-05 口径(跨单锚点) #5499 freezes them; the divergence is against a frozen face, not against the ruling."packages/services/service-analytics/src/read-scope-sql.ts:179-180— "driver-memory/driver-mongodbstay pin-only under the [裁决] driver-memory / driver-mongodb 投入冻结 —— 维护者 2026-08-05 口径(跨单锚点) #5499 freeze."Both are wrong on two counts now: the freeze dissolved on 2026-08-11 (corroborated in the head note of
packages/spec/src/data/aggregation-conformance.ts), and thedriver-mongodbhalf of the claim was never true for this operator family. Rewriting them to past tense without deciding the divergence would have converted an actionable defect into settled-looking prose, which is what the #13089 triage forbade.What a fix owes
driver-memory's reference matcher to the ruling (the include direction), or record a measured, dated exemption. Note this matcher is the reference the SQL family was aligned TO for$not的语义在 driver-sql 与 driver-memory / formula 之间分叉:NULL 行的去留相反,$not: {}一个是 TRUE 一个是 FALSE #5146, so moving it is not local.$existsis a separate, still-open cell —filter-logic-conformance.tsrecords thatdriver-memory's live mingo path anddriver-mongodbboth still read key-presence rather than has-value, which is why no$existsrow can be enrolled yet. Not necessarily this card's scope, but it is the neighbouring cell.filter-logic-conformance.tsis explicit that a row added ahead of a backend is just a red gate, and that the DEBT ledger inscripts/check-driver-conformance.mjsis per (driver x case-set), with no spelling for "fails one row of thirty-six".Generated by Claude Code