Uh oh!
There was an error while loading. Please reload this page.
Measure the $exists has-value cell on every driver-memory exit and on driver-mongodb - #13420
Merged
zhuangjianguo merged 1 commit intoAug 30, 2026
Merged
Conversation
…h no-value readings Executes the cell the recorded table states as reading rather than measurement, and pins what it found. Two files, no source change, no conformance enrolment. driver-memory has FOUR exits and they do not agree: the reference matcher reads has-value (the ruling, shipped by #5962), the live mingo path and the analytics face's executed rows read key-presence, and the analytics face's echoed SQL renders `IS NOT NULL` / `IS NULL` — so that face disagrees with itself. driver-mongodb passes `$exists` through under its own name. Executing widened the divergence threefold against the reading: `$exists: false` and `$not { $exists: true }` diverge too, and in the opposite, worse direction — the no-value row is dropped from the query that asks for no-value rows. Every divergent cell is on the `name: null` reading; the key-absent reading already answers the ruling everywhere, so a fixture that spells "no value" as an absent key measures none of it. The direction stays undecided here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Aug 30, 2026
zhuangjianguo
marked this pull request as ready for review
August 30, 2026 11:36
zhuangjianguo
enabled auto-merge
August 30, 2026 11:36
Uh oh!
There was an error while loading. Please reload this page.
zhuangjianguo
deleted the
claude/issue-13195-exists-has-value-measurement
branch
August 30, 2026 12:09
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #13195 — this delivers step 2 of that card only: the measurement, executed. It decides no direction and enrols nothing.
What the card asked for, and what changed by executing it
The card declares itself "Read, not re-measured" and predicts its own numbers will be optimistic. They were. Reading recorded one divergent column on two surfaces. Executing found three divergent cells on three surfaces (four exits), all on one of the two readings of "no value".
Fixture: rows
1(name: 'alpha-one'),2(name: 'beta'),3(no value) — measured under both readings,name: nulland the key absent. The platform ruling (#5298 leg 3 / #5369, landed in PR #5962) is that$existsmeans "has a value", so the ruling answers are['1','2']for$exists: trueand['3']for$exists: false.The measured table (D = divergent from the ruling)
$exists: truename: null['1','2']['1','2','3']D['1','2','3']Dname IS NOT NULL['1','2','3']D$exists: true['1','2']['1','2']['1','2']name IS NOT NULL['1','2']$exists: falsename: null['3'][]D[]Dname IS NULL[]D$exists: false['3']['3']['3']name IS NULL['3']$not { $exists: true }name: null['3'][]D[]D$not { $exists: true }['3']['3']['3']The driver-mongodb column was executed against a real mongod 8.2.6 as well as against the strict stand-in this PR ships, and both returned the ids above. The real-mongod half is not repeated in CI —
test-mongod.tsgates it behind #5517 and a 123 MB download — so what lands here is the always-run half.Three findings the reading did not carry
$exists: falsediverges too, in the opposite and worse direction. The recorded column is$exists: trueon a null value, whose divergence is surplus — a row the author can see and narrow.$exists: falseand$not { $exists: true }return nothing where the ruling wants the no-value row: the row with no value is dropped from the query that asks for no-value rows.filter-logic-conformance.tsmakes exactly that trade — "silent absence for visible surplus" — its stated reason for keeping the include direction on$ne/$nin. This cell sits on the wrong side of it and was invisible while only$exists: truewas recorded.The
name: nullreading carries the whole divergence; the key-absent reading is already correct on every exit. So the fixture axis is load-bearing in the opposite way from the neighbouring cell in 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, where$notContainsdiverged on both readings and$ninon the absent one only. A fixture that spells "no value" as an absent key measures zero of this. Both columns are kept, with the reason recorded.driver-memory is one driver with FOUR exits, not two faces. The reference matcher answers the ruling; the live mingo path and the analytics face's executed rows read key-presence; and the analytics face's echoed statement renders
name IS NOT NULL/name IS NULL, which is the ruling. So the analytics face disagrees with itself: the rows a chart is drawn from and the SQL shown beside it answer the same query differently. That inequality is asserted here so it cannot be closed in silence.What is deliberately NOT here
$existsis key-presence at the wire level, so answering has-value means emitting something other than{$exists: BOOLEAN}. Nothing settles that, and this PR does not.FILTER_LOGIC_CASESenrolment, and no edit underpackages/spec/**. The DEBT ledger inscripts/check-driver-conformance.mjsis per (driver x case-set), with no spelling for "fails one row of thirty-six", so a row added ahead of a backend is only "a gate that reports a known red" (drivers(turso): remote 模式没有继承 #5146 的$notNULL-safe —— 同一个 TursoDriver,local 返回 NULL 行、remote 不返回(实测,origin/main) #5903). Enrolment is 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's half and comes after the backends agree.One measured input to the open direction is pinned, as a measurement rather than a proposal: this same translator already emits
{$ne: null}/{$eq: null}for$null, and those documents return the ruling's answers on both readings. That narrows what the fork is about — not whether MongoDB can express has-value, but whether$existsshould become an exact synonym for the negation of$null. That question is the maintainer's.Reversibility
Every divergent expectation names the ruling's answer beside the measured one, and both file headers say it: when the direction is decided, invert these in place — do not delete them, and do not re-baseline them to whatever the new output happens to be.
Verification
All at
73a083c8, the final commit.driver-memory+driver-mongodbsuitesTest Files 33 passed (33)/Tests 929 passed (929);Test Files 22 passed | 5 skipped (27)/Tests 496 passed | 143 skipped (639)typecheck, both packagesDone, bothcheck:type-check-debt(ratchet)re-measure: OK — 29 ledger entr(ies) re-measured in 244.2s, 1547 raw tsc error(s) total, none above its recorded numbercheck:type-check-coverageOK — 66/78 workspace packages type-checkedcheck:driver-conformancecheck:dual-build-cjs-loads102 published require entry point(s) across 66 package(s) loadpnpm lint(whole repo)Also green:
check:cross-package-test-inputs,check:doc-authoring,check:logger-receiver-detach,check:objectql-double-limit,check:page-declaration-shape,check:published-files,check:slot-lookup,check:test-source-alias,check:type-source-resolution,check:where-matcher,check:query-options-erasure,check:engine-double-contract,check:nul-bytes, and the ten standalonescripts/check-*.mjs/scripts/docs-audit/*.mjsin the derived family.Two honest gaps, recorded rather than papered over:
scripts/check-test-completeness.mjsexits 3 = PREREQUISITE NOT MET locally — it grades a savedturbo run testlog that only CI produces. NOT MEASURED, not a red.driver-mongodb's owntsconfig.jsonexcludes**/*.test.ts, sopnpm typechecksays nothing about the new file there. Measured separately with a temporary config that includes tests: the new file was in--listFilesand produced 0 errors; the 10 errors that config reports are pre-existing, in eight other test files, and match the ledger's recorded 10 exactly — whichcheck:type-check-debt --re-measurethen confirmed at zero surplus.No changeset: the diff is two test files and publishes nothing, so
skip-changesetapplies.Generated by Claude Code
Generated by Claude Code