Repository navigation
driver-mongodb: translateFilter passes a { $field } cross-field reference through as a literal document, so record.s != record.t matches every row (an RLS using read widens) #19949
Description
Activity
objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actions分诊首次定级:
priority:p2·security·bug·domain:engine·pm:queue—— 维护者裁定 B:#5499 冻结下的安全例外,只做最小的"拒绝"修法Path:
packages/drivers/driver-mongodb/src/mongodb-filter.ts→translateFilter/translateFieldOperatorsTriage: lands in the MongoDB driver's filter translation ⇒
domain:engine,security,bug,priority:p2,pm:queue; rationale: a{ $field }cross-field reference is passed through as a literal sub-document, so an RLSusingsuch asrecord.s != record.tmatches every row on MongoDB — a read restriction that silently widens; the driver is under the #5499 investment freeze (no MongoDB customer), and the maintainer ruled a narrow security exception: refuse the reference (fail closed), do not implement it.分诊席(
session_01Tw7jnJinGHvoGSi8aFkhPJ,座位贴 #6015),2026-09-24T04:53Z。⛔ 不认领、不派发。本席读完了卡面(本卡尚无评论)。前提复核(
origin/main2dc5889013)packages/drivers/driver-mongodb/src/mongodb-filter.ts里$field出现 0 次。对照组正常:同一文件里translateFilter在:568;driver-sql 有 [spec] SqlDriver 将$field编译为列对列比较(cross-field comparison push-down) #5222 的字段对字段一致性用例,$field在cross-field-conformance-cases.ts里能搜到。- ⇒ 卡面读数成立:
compileCelToFilter把record.s != record.t降成{ s: { $ne: { $field: 't' } } },MongoDB 驱动原样下发,$ne选中所有行,$eq一行也不选(dev 用 mingo 7.2.4 代测;真实mongod未测)。
维护者裁定(本席在对话里把两条规则的冲突报给了维护者)
- 冲突:driver-mongodb 在维护者 08-05 的投入冻结之内([裁决] driver-memory / driver-mongodb 投入冻结 —— 维护者 2026-08-05 口径(跨单锚点) #5499,「driver-mongodb 暂无客户」),这一族的卡 09-23 已按冻结关闭;但本卡是读权限被放宽,规则 1 说安全永远最高。
- 选项:A 按冻结关闭,把最小修法写进评论留给解冻时;B 作为安全例外,只做最小修法。
- 维护者答:「19949 B」。
要做的(⛔ 只做这些)
translateFilter遇到任何运算符的值是{ $field: … }时直接拒绝:抛一个清楚的错误,点名"MongoDB 驱动不支持字段对字段比较($field)",⛔ 不再当作普通值下发。- 确认这个错误在行级权限的读取路径上表现为拒绝读取(fail closed),而不是放行,也不是被吞掉之后退回到无过滤。
- 测试:用卡面的两行
{s:'a', t:'a'}、{s:'a', t:'b'},$ne和$eq配{ $field: 't' }都必须被拒绝;对照:普通字面值的$ne/$eq行为不变。
⛔ 不做的
- ⛔ 不实现
$field的真正下降(例如用$expr做列对列比较)。那是冻结明确排除的投入,等 [裁决] driver-memory / driver-mongodb 投入冻结 —— 维护者 2026-08-05 口径(跨单锚点) #5499 解冻(有客户要 MongoDB)再做。 - ⛔ 不动 driver-mongodb 其它已知问题,它们按冻结保持关闭。
为什么是 p2
读权限被放宽是安全缺陷,但只影响用 MongoDB 驱动的部署,而目前没有这样的客户(#5499)。修法很小,改动面只有一处。
Generated by Claude Code
- addedbugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3
on Sep 24, 2026 objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actionsDeferred (serial) behind PR #19947 — stays
pm:queue, not dispatched this rounddomain:engine#1,session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-24T12:59Z. Thread read through 5807932277 (triage, ruling B).Why not now. Draft PR #19947 (#19886 stage 2c,
domain:specseat 5, cross-lane declared in its claim 5806396564) adds a shape-walk refusal topackages/drivers/driver-mongodb/src/mongodb-filter.ts(+43:$newith an array comparand refused withINVALID_FILTER/ 400, at any depth,$not/$norincluded). This card's fix lands in the same walk of the same file. Same region ⇒ hard serial across rounds; ⛔ not folded into a PR another seat owns.Known pits, recorded for the taker:
- Build on PR fix(formula, driver-mongodb): refuse == / != against a list literal at the CEL lowering and $ne arrays at the mongodb face #19947's refusal once it is on
main: the same walk, the sameINVALID_FILTER/ 400 envelope and its withheld-diagnostic posture, so the driver gains one refusal vocabulary, not two. - PR fix(spec)!: refuse an array in the equality slot at the shared comparand-shape face #19882 (spec lane, draft) adds
packages/drivers/driver-mongodb/src/mongodb-equality-array-comparand-refusal.test.ts, which pinstranslateFilterpassing an equality-slot array through. That file is fenced; this card's pins go in a file of their own. - Scope stays ruling B, verbatim on this card (5807932277): 「维护者答:「19949 B」。」 Refuse
{ $field }under every operator, fail closed on the RLS read path; ⛔ no$exprlowering. - On
mainat2c1011b01b,$fieldhas 0 hits inmongodb-filter.ts(control:translateFilter5 hits in the same file); the 1 hit inpackages/drivers/driver-mongodb/src/is prose inmongodb-aggregation.ts.
Wakes when: PR #19947 merges or closes. This seat's hot-file serial queue (seat post #6367) holds the entry.
Generated by Claude Code
- Build on PR fix(formula, driver-mongodb): refuse == / != against a list literal at the CEL lowering and $ne arrays at the mongodb face #19947's refusal once it is on
objectstack-fleet commented
on Sep 27, 2026 ContributorAuthorMore actionsClaim: PM loop round 22
Session:session_01Bvd69VPa6puiNzzPUroDBx
Account:os-sales(the seat's linked user asGET /useranswers it; always the card's assignee)
Branch:claude/issue-19949-mongodb-field-ref-refused
Worktree:objectstack-issue-19949
Domain:domain:engine
Seat:domain:engine#1
File surface:packages/drivers/driver-mongodb/src/mongodb-filter.ts:translateFilter/translateFieldOperatorsonly. A{ $field: … }comparand under ANY operator is refused with the sameINVALID_FILTER/ 400 envelope, and the same withheld-diagnostic posture, as PR fix(formula, driver-mongodb): refuse == / != against a list literal at the CEL lowering and $ne arrays at the mongodb face #19947's shape-walk refusal in the same walk. This is the maintainer's ruling B (triage 5807932277): 「19949 B」;- a new test file of its own in
packages/drivers/driver-mongodb(test side only); .changeset/19949-*.md.
Stop on breach and explain in the report. ⛔ No
$fieldlowering (no$exprcolumn-to-column), which ruling B excludes. ⛔ No other driver-mongodb defect: those stay closed under #5499. ⛔ Notpackages/spec, notcompileCelToFilter, not the RLS compiler.
Container & model:S,mode:subagent,model: opus(dispatch-gates --tier: no path-derived mandate, floor sonnet · default opus · ceiling fable; security, so the default tier)
Clause-②: no (narrowing)
Thread-read: 5814595680
Serial constraints cleared: at 2026-09-27T05:44Z, the region predecessor PR #19947 (#19886 stage 2c, spec seat 5) has merged, and PR #19882 has merged. A census of the 9 open PRs finds none underpackages/drivers/driver-mongodb/src. The seat runsbatch:3(the maintainer's ruling); in flight are PR #20174's review and this card.objectstack-fleet commented
on Sep 27, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 19949,
"status": "done",
"branch": "claude/issue-19949-mongodb-field-ref-refused",
"pr": "#20182 (draft, opened by objectstack-fleet[bot] through relay run 36299771940; the body read back byte-identical, 10678 bytes; PR assignee set to the card assignee os-sales through relay run 36299812160, read back)",
"head_sha": "00612182e9",
"session": "session_01Bvd69VPa6puiNzzPUroDBx. This is the dispatching seat's session, because this run is its subagent (mode:subagent).",
"premise_still_valid": true,
"summary": "The premise holds at origin/main 3bd28e2. mongodb-filter.ts had no $field arm, and translateFilter emitted { s: { $ne: { $field: "t" } } } verbatim. Through mingo 7.2.4 that selected both card rows, and the full RLS read path (compileCelToFilter, RLSCompiler, SecurityPlugin, ObjectQL, MongoDBDriver) returned both rows from find, 2 from count, and the s == t row from findOne. One gate was added to classifyFilterKey, on the shape walk that PR #19947 extended, and placed before the other comparand gates. It refuses a { $field }-shaped object (any$field key, so a malformed reference too) in three positions: the whole constraint (the bare form, or a list holding one), any $ -operator comparand (addDays included), and any member of a list comparand. The refusal is INVALID_FILTER / 400, and its message names "field-to-field comparison" and withholds the fields, the operator and the position. At head the RLS read is refused (find, findOne and count throw 400, and the collection is asked 0 times), and every literal comparand translates to the same document as before. There is no $expr lowering, per ruling B. The pins are in a new test file of their own, and a minor BREAKING changeset declares Clause-②: no (narrowing).",
"tests": "All at HEAD 0061218 unless stated. (1) pnpm --filter @objectstack/driver-mongodb test: "Test Files 28 passed | 5 skipped (33); Tests 630 passed | 147 skipped (777)". The 5 skipped files are the opt-in live-mongod suites (OS_TEST_MONGODB_MEMORY_SERVER_ENABLED); a live mongod is NOT MEASURED because the binary cannot be fetched here. (2) vitest run src/mongodb-field-reference-refusal.test.ts: 39 passed. (3) pnpm --filter @objectstack/driver-mongodb typecheck: exit 0, "check:test-typecheck: OK ... 0 file(s) / 0 error(s)"; tsc -p tsconfig.test.json --listFiles counts 33 test files, the new one included. (4) Ablation, run after the fix was committed (a53249d), through scripts/ablation-replace.mjs in WRAP mode under the verify lock. It deleted the gate line: anchor x1 to x0, blob 7b33578be43b to 343b8c5aa323 ("ok mutation landed"). The result was "Tests 33 failed | 6 passed (39)": every refusal case red, and the 6 controls green. Restore: blob after restore 7b33578be43b equals the blob at HEAD, and git diff HEAD is empty ("ok restored"). No dist step was needed, because the suite imports ./mongodb-filter.js from src by relative path, and the ObjectQL dist was not mutated. (5) The CJS entry dist/index.js, rebuilt at HEAD, loads and refuses { s: [ref] } with INVALID_FILTER/400. (6) Narrowed eslint on the 2 changed .ts files: eslint --no-inline-config --format json reports 2 files, 0 errors, 0 warnings. Population: --print-config gives both files a rule set. Invariance: no parserOptions.project or projectService on either file, and the config itself states it never enables type-aware linting, so the diff cannot move another file's verdict. The full pnpm lint is left to CI. (7) The H1/H2 readings came from a scratch script (scratchpad measure.mjs) over the built dists, at base 3bd28e2 and at head 0061218.",
"mcp_calls": "0",
"api_writes": "3 relay writes, each one POST /repos/objectstack-ai/objectstack/dispatches executed by fleet-write.yml as objectstack-fleet[bot]: (1) pr_create, which is POST /repos/objectstack-ai/objectstack/pulls (draft), run 36299771940; (2) label-write --assign os-sales, which is POST /repos//issues/20182/assignees, run 36299812160; (3) this os-dev-report comment, which is POST /repos//issues/19949/comments. git push is not a REST write. Reads, not counted: GET issues/19949, issues/19949/comments, pulls?head=..., pulls/20182, issues/comments/5806886759.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted, not filed. An observation, recorded in the PR Acceptance notes: translateFilter lowers a non-boolean $exists comparand to { $eq: null }, because the arm tests value === true. Measured on translateFilter at head: "yes", 1, null and "false" all give $eq: null. Not measured through a public door, and not compared with the other drivers, so it is not a class a/b/c card. driver-mongodb stays under the #5499 freeze."
],
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack, taken with no paths at HEAD 0061218, derived 59 commands (changed set: 3 paths vs merge base 3bd28e2). All 59 were run with exit codes recorded. dispatch-gates --ran: "59 derived famil(ies) accounted for — 57 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3)". 57 exited 0. NOT MEASURED: pnpm check:dual-build-cjs-loads (exit 3, PREREQUISITE NOT MET, it needs the whole workspace built; narrowed to this package's CJS entry loading, see tests (5)); pnpm check:type-check-debt (exit 3, PREREQUISITE NOT MET, 12 ledgered-closure packages are unbuilt; this package has no DEBT entry and its own test-layer typecheck is green). Also run, all exit 0: node scripts/check-issue-citations.mjs --base 3bd28e2 (5 citations resolve), and the 5 roster gates that dispatch-gates flagged as sitting under this diff's directories (check:authz-resolver, check:error-code-casing, check:filter-alias-parity, check:object-def-param-keys, check:tenant-chokepoint). New against the PM list from 3bd28e2: check-adr-0087-registration (base and self-test), check-empty-changeset (base and self-test), check:engine-double-contract, check:objectql-double-limit, check:objectui-changeset, check:pm-changeset-deadline-census, check:query-options-erasure, check:type-check-coverage, check:type-check-debt, check:where-matcher, and release-rehearsal-clone --self-test. All were run. H4: check-changeset-no-major --event (a simulated pull_request payload carrying this PR's exact body) reports "LEVEL AXIS: this PR declares clause-② no (narrowing), and no package ... is graded patch", so minor is accepted. check-adr-0087-registration accepts "not-required (no-migration-prescription)". Neither should differ: there is no conversion target on this driver, so a registry entry would carry no prescription, and adding one would also edit packages/spec, which the claim excludes. CI convergence is not awaited.",
"line_budget": "n/a: no skills/** path in the diff.",
"deviations": [
"This session was given a copy of os-dev.md that is older than .claude/agents/os-dev.md at 3bd28e2. Where the two differ, I followed the repo copy: the PR assignee is set through label-write --issue PR --assign LOGIN, and findings carry a reach: field. AGENTS.md was first read from the shared checkout (at 2c1011b, which is stale). The worktree copy was then diffed against it, and its current PR-assignee clause was the one followed.",
"The gate covers more than the literal "operator value" wording. It refuses a reference as the whole constraint (the bare form and a list holding a reference, i.e. implicit equality) and as a list member ($in/$nin/$between/arrays). H1 named those positions, and the ruling says it must no longer be sent down as an ordinary value.",
"The gate runs first among the comparand gates. Four shapes that were already refused now get the cross-field wording, with the same INVALID_FILTER/400 envelope: bare { s: ref } (before: "Unsupported filter operator $field", naming the field), $icontains: ref, $null: ref, and $ne: [ref]. At base, this package's tests had 0 hits for $field, so no pin changed. The $ne array refusal from PR #19947 is unchanged for literal arrays.",
"The engine-level pin in the suite uses an ObjectQL middleware that AND-composes the compiled policy, standing in for SecurityPlugin, because plugin-security is not a dependency of driver-mongodb. The real SecurityPlugin path was measured outside the suite, in a scratch script."
],
"files_changed": [
"packages/drivers/driver-mongodb/src/mongodb-filter.ts (+87: gate in classifyFilterKey; isFieldReferenceShape, carriesFieldReference, holdsFieldReference, fieldReferenceUnsupportedError)",
"packages/drivers/driver-mongodb/src/mongodb-field-reference-refusal.test.ts (+303, new)",
".changeset/19949-mongodb-field-reference-refused.md (+36, new; driver-mongodb minor, BREAKING, Clause-②: no (narrowing), adr-0087 not-required (no-migration-prescription))"
],
"rows": {
"proxy": "mingo 7.2.4 (driver-memory's dependency) over rows r1 {s:a,t:a} and r2 {s:a,t:b}, ref = { $field: "t" }. A live mongod is NOT MEASURED.",
"base": "3bd28e2b2e",
"head": "00612182e9",
"cells": [
"s $ne ref: base selects r1,r2 | head 400",
"s $eq ref: base none | head 400",
"$gt / $gte / $lt / $lte ref: base none | head 400",
"$in [ref]: base none | head 400",
"$nin [ref]: base selects r1,r2 | head 400",
"$between [ref,z] / [a,ref]: base none | head 400",
"$and [s $ne ref]: base r1,r2 | head 400",
"$or [s $ne ref, s=zz]: base r1,r2 | head 400",
"$or [{}, s $ne ref]: base translated {} (r1,r2) | head 400 (the gate is on the walk)",
"$not {s $eq ref} (lowered to $nor): base r1,r2 | head 400",
"$not {s $ne ref}: base none | head 400",
"s $ne {$field:t, addDays:1}: base r1,r2 | head 400",
"s $eq {$field:t, addDays:{$field:n}}: base none | head 400",
"s $ne {$field:42} (malformed): base r1,r2 | head 400",
"$notContains ref: base r1,r2 | head 400",
"$contains / $startsWith / $endsWith ref: base none | head 400",
"$exists ref: base lowered to $eq null, none | head 400",
"bare {s: ref}: base 400 (unknown operator $field, names the field) | head 400 (cross-field wording)",
"$icontains ref / $null ref / $ne [ref]: base 400 (their own gates) | head 400 (cross-field wording)",
"$nor at node level: base 400 | head 400, unchanged",
"CONTROL s $ne a: none | none, same document",
"CONTROL s $eq a: r1,r2 | r1,r2, same document",
"CONTROL t $ne b: r1 | r1",
"CONTROL t $eq b: r2 | r2",
"CONTROL t $in [b] / $nin [b] / $between [a,a] / $not {t $eq b}: r2 / r1 / r1 / r1 | identical"
]
},
"rls_path": "compileCelToFilter("record.s != record.t") and ("s != t") both return { s: { $ne: { $field: "t" } } }. RLSCompiler.compileFilter with declared {id,s,t} keeps it. Full path: SecurityPlugin with a rowLevelSecurity policy (operation all), ObjectQL, and the real MongoDBDriver over a stub Db whose collection selects with mingo. The caller is a MEMBER holding the set. Base, using "s != t": find returns [r1,r2], count 2, findOne({id:r1}) returns r1, and the server received {"s":{"$ne":{"$field":"t"}}}. The read restriction was lost. Head: find, findOne and count each throw INVALID_FILTER/400, and the qa_pair collection is asked 0 times, so the read is refused: not allowed through, not swallowed, never unfiltered. Using "s == t" (base: 0 rows) is also refused at head. Controls, identical at base and head: using t == "a" gives [r1] / count 1, using t != "a" gives [r2], using s == "a" gives [r1,r2]. The engine's find path logs at warn and rethrows. Every driver door reads where through translateFilter: find, findOne, count, updateMany, deleteMany, aggregate (buildAggregationPipeline) and explain. The suite pins six doors plus the engine rethrow.",
"collateral": "Every literal comparand translates to the same document (the controls above and in the suite). The $ne array refusal from PR #19947 is unchanged for literal arrays: mongodb-ne-array-comparand-refusal.test.ts is green, and the new file carries a control. The #19757 equality-slot array pin still holds: { tags: ["a"] } and $eq ["a"] pass through. mongodb-equality-array-comparand-refusal.test.ts is green, and the gate fires only on a reference member. The whole driver-mongodb suite is green (630 passed, 147 skipped in the opt-in live-mongod files). check:driver-conformance, check:filter-alias-parity and check:where-matcher exit 0. No workspace consumer's tests use $field with this driver (grepped in runtime, service-datasource and cli). Exports and types are unchanged. Wording moved for 4 shapes that were already refused (see deviations).",
"cleanup": "After this post, the worktree node_modules is removed and git worktree remove runs without --force; the outcome is reported in the final hand-off. No dev server, background process or monitor was started."
}objectstack-fleet commented
on Sep 27, 2026 ContributorAuthorMore actionsACCEPT: PR #20182 at
00612182e9(#19949)domain:engine#1,session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-27T06:45Z. Reviewed on GitHub againstreferences/review-checklist.md, not from the dev'sos-dev-report.- Shape: the first line is
Fixes #19949. The body and changeset declareClause-②: no (narrowing): BREAKING,@objectstack/driver-mongodbminor, ADR-0087 dispositionnot-required (no-migration-prescription). - Scope: 3 files, +426/−0. Not governed.
mongodb-filter.ts: one gate on thetranslateFiltershape walk from PR fix(formula, driver-mongodb): refuse == / != against a list literal at the CEL lowering and $ne arrays at the mongodb face #19947.- A new pin file and the changeset.
- Inside the maintainer's ruling B (「19949 B」): refuse and fail closed. No
$exprlowering, andpackages/spec,compileCelToFilterand the RLS compiler are untouched.
- Contract review of record: PASS at
00612182e9(5853495299).- 34 of 34
{ $field }shapes are refusedINVALID_FILTER/ 400. That covers every operator, list members, the bare form,addDaysand malformed references. - The 21 literal controls translate to byte-identical documents.
- On the real RLS chain (
compileCelToFilter→RLSCompiler→SecurityPlugin→ObjectQL→MongoDBDriver), ausingofs != treturned every row at base. At head,find,findOne,count,aggregate, bulk update and bulk delete all refuse with 0 collection calls. - The message withholds field names.
- The ablation reproduces the dev's count: 33 of 39 red.
- A live
mongodwas NOT MEASURED; mingo 7.2.4 is the proxy.
- 34 of 34
- CI at this head: 34 runs, 31
success, 3skipped, 0 failed. All seven required contexts aresuccess.git merge-treeagainst currentmainis clean. - Acceptance notes (not cards):
- PR-body nit: "Three shapes were already refused" should say four. The rows table lists all four.
- Changeset imprecision: "Before this change it returned every row" is true for
!=-style policies only, while==returned none. The changeset's own line 26 states both directions, so it is not a contract falsity, and a new head is not worth it. - Spec lane,
carrier:none today: the generatedcontent/docs/references/data/filter.mdx$eq/$nerows, and [finding] a{ $field }reference as a$betweenendpoint is refused by the schema door and accepted by the runtime door — the #19071 shape, one endpoint spelling over, already ruled on the schema side #19377's two-bound prescription, read as if a{ $field }comparand compiles on MongoDB. It is now an explicit 400. Correcting them is apackages/specdescribe()edit.
Landing:
readyplus auto-merge through the queue now.- Shape: the first line is
objectstack-fleet commented
on Sep 27, 2026 ContributorAuthorMore actionsLanded: PR #20182, verified on
maindomain:engine#1,session_01Bvd69VPa6puiNzzPUroDBx, written 2026-09-27T07:05Z.- Verified on main:
- PR fix(driver-mongodb)!: refuse a { $field } cross-field reference instead of sending it to MongoDB as a literal (#19949) #20182 merged through the merge queue as
98f722a742. It has one parent (9e7824a445) and is an ancestor oforigin/mainafter a fresh fetch. - Its patch-id equals the reviewed diff
3bd28e2b2e..00612182e9(PASS 5853495299): 3 files, +426/−0. - The changeset
19949-mongodb-field-reference-refused.mdis present at that commit and absent at its parent.
- PR fix(driver-mongodb)!: refuse a { $field } cross-field reference instead of sending it to MongoDB as a literal (#19949) #20182 merged through the merge queue as
- This card: closed
completedviaFixes #19949, per the maintainer's ruling B (「19949 B」).pm:dispatchedis removed in the same act.driver-mongodb'stranslateFilterrefuses a{ $field }reference in every position withINVALID_FILTER/ 400, where before it sent the reference to MongoDB as a literal document.- A row-level
usingsuch asrecord.s != record.tnow refuses the read, with 0 collection calls, instead of returning every row. - There is no
$exprlowering, as ruled. - A live
mongodwas NOT MEASURED; mingo 7.2.4 is the proxy.
- Noted for the spec lane, not filed (
carrier:none): the generatedcontent/docs/references/data/filter.mdx$eq/$nerows, and [finding] a{ $field }reference as a$betweenendpoint is refused by the schema door and accepted by the runtime door — the #19071 shape, one endpoint spelling over, already ruled on the schema side #19377's two-bound prescription, read as if a{ $field }comparand compiles on MongoDB. On this driver it is now an explicit 400.
- Verified on main:
- added a commit that references this issue
on Sep 29, 2026
Filed by the
domain:specseat 5 (session_01Sfe5YjBLwB9J3y8fvm2xq1, seat post #19357) from the out-of-scope findings of the #19886 stage-2c dev (report5806886759, class a). ⛔ Filed unassigned and unlabelled: routing and grading are triage's. ⛔ Not a claim.The defect
compileCelToFilterlowers a field-to-field comparison such asrecord.s != record.tto{ s: { $ne: { $field: 't' } } }: a declared cross-field reference (FieldReferenceSchema).packages/drivers/driver-mongodb/src/mongodb-filter.tshas no$fieldhandling. The seat greppedpackages/drivers/driver-mongodb/srconorigin/mainaeaaa44292and found no$fieldarm in the filter translation, sotranslateFilteremits the reference verbatim, as a literal sub-document.Measured by the #19886 stage-2c dev at
10efa63fb1, throughtranslateFilterplus mingo 7.2.4 as the proxy (livemongodNOT MEASURED), over the rows{s:'a', t:'a'}and{s:'a', t:'b'}:$neagainst the reference selects BOTH rows, including the one wheresequalst;$eqselects none.Why it matters
A row-level
usingthat compares two fields with!=is a read restriction. On driver-mongodb it widens to every row. The SQL family compiles$fieldto a column-to-column comparison (#5222).Seam:
spec:FieldReferenceSchema{ $field }→ runtime: driver-mongodbtranslateFilter(no lowering).Dedupe words:
mongodb field reference $field not lowered·rls field-to-field ne mongodb every row·translateFilter $field