Skip to content

[drivers] InMemoryDriver.find applies limit on truthiness, so limit: 0 returns every row — the #6485 defect one layer below the client #6577

Description

@os-project-manager

Found while implementing #6485 (PR to follow). Out of that issue's scope — its file surface was packages/client/src/index.ts only — so filed rather than fixed, per Prime Directive #10.

Fact (measured on origin/main @ 53ef05744, not read)

#6485's ruling was that limit: 0 means "return no records", and it required establishing that the server honours top=0 before shipping the client change. Measuring that turned up a driver that does not.

Probe run against each driver's real find, three rows in the table:

PROBE sql-driver    => {"limit0_rows":0,"limit2_rows":2,"noLimit_rows":3,"offset0_rows":3}
PROBE memory-driver => {"limit0_rows":3,"limit2_rows":2,"noLimit_rows":3}

SqlDriver returns 0 rows for limit: 0. InMemoryDriver returns 3 of 3 — the entire table, for a query that asked for none.

The cause is the same truthiness-vs-presence asymmetry #6485 named, one layer down:

  • packages/drivers/driver-memory/src/memory-driver.ts:315 — if (query.limit) { results = results.slice(0, query.limit); }
  • versus packages/drivers/driver-sql/src/sql-driver.ts:2773 — if (query.limit !== undefined) b.limit(query.limit);
  • and packages/drivers/driver-turso/src/remote-transport.ts:1472 — if (query.limit !== undefined), also presence.

So two shipped drivers answer the same QueryAST with opposite result sets, and the one that disagrees is the one that returns more data than was requested rather than less.

Same shape, three more sites (unmeasured, listed by inspection)

Not probed, so stated as located rather than confirmed:

  • packages/drivers/driver-sql/src/sql-driver.ts:3871 — findWithWindowFunctions, if (query.limit) builder.limit(query.limit). Truthiness, while findRows in the same file uses presence — so this driver disagrees with itself across two read doors.
  • packages/drivers/driver-sql/src/sql-driver.ts:3911 — analyzeQuery / explain, same shape. A plan explained for a statement other than the one find would run.
  • packages/drivers/driver-memory/src/memory-analytics.ts:434 and :598 — the $limit pipeline stage and the SQL string builder, both truthiness.

One that is NOT this bug, and should not be "fixed" into one

MongoDBDriver (packages/drivers/driver-mongodb/src/mongodb-driver.ts:231) already tests presence — if (query.limit !== undefined) findOptions.limit = query.limit; — but the MongoDB Node driver defines limit: 0 as no limit, so it returns every row too, for an unrelated reason. Aligning it needs a deliberate guard at that boundary, not the same edit. Worth a decision rather than a patch.

Why this is user-reachable now rather than theoretical

Before #6485 the client dropped limit: 0 on the floor, so no top=0 ever left the SDK and the divergence was unobservable through it. With that fixed, find('task', { limit: 0 }) puts top=0 on the wire, the protocol layer forwards limit: 0 to the engine (measured: findData neither rejects nor ignores it), and the answer now depends on which driver the deployment configured — zero rows on SQL/Turso, every row on memory.

Blocked-by: nothing; independent of #6485's PR, which is correct as it stands for the SQL/Turso path.

Not graded here

Severity judged at filing time is unreliable in both directions, so this is filed plainly and unassigned for the triage round. The two questions the grader will want: whether InMemoryDriver counts as a production surface (it backs LiteKernel, edge/serverless and most of the test suite), and whether the driver contract should state limit: 0 explicitly so the conformance suite can pin it — check:driver-conformance exists and passes today with the two drivers disagreeing.

Activity

  1. os-zhuang commented on Aug 8, 2026

    @os-zhuang
    Contributor

    Triage: finding (held) + domain:drivers — routed and graded in one pass because the #5499 freeze decides the grade.

    Anchors re-verified on origin/main @ a36db28 (main was force-updated since the card's ref 53ef057; secondary sites re-located by content): memory-driver.ts:315 and memory-analytics.ts:434/:598 truthiness — confirmed. sql-driver.ts:2773 presence on the main find door — confirmed. The two internal truthiness doors now sit at sql-driver.ts:3922 and :3962 (the card's :3871/:3911 drifted; locate by the if (query.limit) builder.limit(query.limit) pattern). mongodb-driver.ts:231 presence-with-driver-semantics — confirmed.

    Why held rather than queued: the primary defect lands in driver-memory, which is under the maintainer's #5499 investment freeze; the standing rule there routes family cards but holds them, and mixed-face cards (this one spans memory + sql-internal + mongo) keep finding per the #5298/#5299/#5369 precedent. The freeze's restore-invariant exception (memory backend semantics corrupting CI verdicts) is not invoked: no test asserting limit: 0 semantics through the memory backend was demonstrated. Named trigger to escalate past the freeze: such a test surfaces, or a CI red traces to this divergence.

    Two carve-outs recorded for later framing:

    1. The unfrozen remainder is driver-sql disagreeing with itself (:3922/:3962 vs :2773) — a scoped internal-consistency fix the drivers lane may split out and queue without touching the frozen packages.
    2. Reachability watch: once PR fix(client): data.find 的 top/skip 按存在性发射,limit: 0 不再被静默丢弃 (#6485) #6578 (the [finding][client] data.find's pagination params are emitted on truthiness, so { limit: 0 } is dropped exactly like the limit bug #6322 fixed #6485 client fix, currently draft) lands, limit: 0 goes on the wire and memory-backed (LiteKernel) deployments return every row for a query that asked for none. If the maintainer counts LiteKernel edge/serverless as a production face, this card graduates past the freeze — flagged in the round brief.

    The MongoDB boundary (limit: 0 = no-limit in the driver itself) stays a deliberate-decision item, frozen with the rest.

    Dedup: #6485 is the same asymmetry one layer up (client), explicitly out of this card's surface; PR #6578 implements it. No other limit: 0 card or PR in the three repos.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. self-assigned this
    on Aug 8, 2026
  3. os-zhuang commented on Aug 8, 2026

    @os-zhuang
    Contributor

    Claim: PM loop, drivers lane (accelerated batch, maintainer-directed) — UNFROZEN HALF ONLY, per the triage split ruling (2026-08-08T10:22Z comment).
    Session: session_01Hg9Pkg5nDedCRihRsdeCdX
    Branch: claude/issue-6577-sql-limit-presence
    Worktree: objectstack-issue-6577 (cloud session — own container)
    Domain: domain:drivers
    Scope of this dispatch: the driver-sql internal-consistency half (the two truthiness doors in sql-driver.ts, drifted to ~:3922/:3962, plus limit: 0 pinning for the unfrozen SQL-family drivers). The driver-memory one-liner and the MongoDB boundary stay OUT — #5499-frozen; the freeze question goes to the maintainer separately, not silently flipped here. The PR will say "Part of #6577", NOT "Fixes" — the issue stays open for the frozen half's ruling.
    File surface: packages/drivers/driver-sql/src/sql-driver.ts (two if (query.limit) sites), driver-sql test files, possibly scripts/check-driver-conformance.mjs + the shared case-set if a limit: 0 conformance pin is added (with DEBT rows for the frozen drivers, not flips).
    Serial constraints cleared: PR #6706 (issue #6518) touches sql-driver.ts and is IN THE MERGE QUEUE right now — this dispatch carries a hard precondition: do not branch until #6706's merge commit is on origin/main (verify by ancestry, not by memory). #6543 lands in unique-violation.ts (disjoint, per #6706's successor-repricing table). #6409/#6401 also touch sql-driver.ts and remain queued behind this one.


    Generated by Claude Code

  4. os-zhuang commented on Aug 8, 2026

    @os-zhuang
    Contributor

    Maintainer ruling (2026-08-08 ~14:3xZ, chat) — the freeze question surfaced per the triage split is answered: A+ approved, verbatim: 「A+ 批准,按这个范围执行」.

    Scope of the narrow #5499 freeze exception, exactly as put to the maintainer:

    1. memory-driver.ts limit door truthiness → presence (one line) + the two same-shape sites in memory-analytics.ts ($limit stage, SQL string builder);
    2. mongodb-driver.ts: explicit limit === 0 short-circuit guard returning an empty result BEFORE the upstream driver — the contract's semantics are not delegated to the MongoDB driver's own "0 = no limit" definition;
    3. limit: 0 pinned in the shared driver conformance case-set across ALL FIVE drivers — no DEBT rows; future drift goes red at the gate;
    4. The [裁决] driver-memory / driver-mongodb 投入冻结 —— 维护者 2026-08-05 口径(跨单锚点) #5499 freeze remains in force for everything else — the drivers(memory, mongodb): the $contains family still folds case — the last two backends left on the wrong side of #4706 Q2 = A #6682 case-folding programme and all other investment in driver-memory / driver-mongodb stay frozen. This exception is the limit door only.

    Consequences: the in-flight dispatch (branch claude/issue-6577-sql-limit-presence, session_017qrJvYzSD5xhky5amXrnm2) is re-scoped to the full card; its PR says "Fixes #6577" (not "Part of") and closes this issue entirely, clearing it from the target:v17 board. File surface widens accordingly: + packages/drivers/driver-memory/src/memory-driver.ts, memory-analytics.ts, packages/drivers/driver-mongodb/src/mongodb-driver.ts, shared conformance case-set + scripts/check-driver-conformance.mjs, with changesets for the three touched driver packages.


    Generated by Claude Code

  5. os-zhuang commented on Aug 8, 2026

    @os-zhuang
    Contributor

    os-dev report

    {
      "issue": 6577,
      "session": "session_017qrJvYzSD5xhky5amXrnm2",
      "branch": "claude/issue-6577-sql-limit-presence",
      "worktree": "objectstack-issue-6577",
      "pr": 6793,
      "pr_url": "https://github.com/objectstack-ai/objectstack/pull/6793",
      "pr_state": "draft",
      "pr_body_opens_with": "Fixes objectstack-ai/objectstack#6577",
      "closes_issue": true,
      "ci": "all 25 checks green on 12c8176; mergeable_state clean",
      "merged_anything": false,
    
      "scope": {
        "dispatched_as": "unfrozen driver-sql half only",
        "re_scoped_to": "full card",
        "authority": "maintainer ruling on this issue, comment 5226535233 (2026-08-08T14:27:29Z), verbatim 「A+ 批准,按这个范围执行」",
        "freeze_exception": "the limit door only",
        "frozen_surface_left_untouched": [
          "#6682 case-folding programme — both FILTER_TEXT_CASES DEBT rows byte-for-byte as #6706 left them",
          "driver-memory `offset` truthiness — slice(0) IS the identity slice, so presence and truthiness are behaviourally indistinguishable; flipping it would be a diff with no measurement behind it",
          "driver-mongodb aggregate() `$limit` — outside the ruled door, and it fails LOUDLY (MongoDB rejects `$limit: 0`) rather than over-returning, so it is a different failure mode. Recorded, not fixed."
        ]
      },
    
      "hard_precondition": {
        "requirement": "do not branch until PR #6706 is merged to origin/main",
        "honoured": true,
        "method": "git fetch polled every 120s; verified by ancestry, never from memory",
        "observed_while_blocked": "#6706 was green on all 24 checks but ABSENT from the gh-readonly-queue refs (queue held 6705/6709/6717/6718/6720). Reported as blocked-not-failed at that point rather than branching early.",
        "merged_at": "2026-08-08T14:21:57Z",
        "merge_commit": "3172831",
        "branched_from": "3172831"
      },
    
      "premise_still_valid": true,
      "premise_evidence": {
        "method": "probed each driver's real read door on 3172831 BEFORE any line moved — executed, not read",
        "driver_sql": {
          "find({limit:0})": "0 rows; emits `select * from `orders` order by `id` asc limit ?`",
          "findWithWindowFunctions({limit:0})": "3 of 3 rows — the whole table",
          "analyzeQuery({limit:0})": "`select * from `orders`` — no LIMIT clause at all"
        },
        "driver_memory": {
          "find({limit:0})": "3 of 3 rows",
          "find({limit:0, offset:1})": "2 rows — OFFSET applied, LIMIT not"
        },
        "line_drift": "triage anchored :3922/:3962; #6706 moved them to :4197/:4237. Located by the `if (query.limit) builder.limit(query.limit)` pattern, never by line number.",
        "pm_assumptions_all_verified": {
          "two truthiness sites survive #6706": true,
          "findRows presence door already correct (:3047/:3048)": true,
          "turso remote already presence (remote-transport.ts :1485)": true,
          "check:driver-conformance passed with the divergence unpinned": true
        }
      },
    
      "changes": {
        "driver-sql": "findWithWindowFunctions + analyzeQuery: limit/offset truthiness -> presence",
        "driver-memory": "memory-driver.ts find() slice -> presence; memory-analytics.ts $limit stage and SQL string builder -> presence. Mingo honours `{$limit: 0}` as zero records (measured 3 in / 0 out), so no short-circuit needed.",
        "driver-mongodb": "new `returnsNoRecords()` short-circuit — find -> [], findOne -> null, BEFORE the client is consulted. Presence was already correct; the bug was that the upstream client DEFINES limit 0 as 'no limit'. `=== 0` not `<= 0`, deliberately.",
        "driver-turso": "remote transport emitted OFFSET independently of LIMIT — illegal in SQLite, so `find(obj,{offset:N})` threw `near \"OFFSET\": syntax error` for EVERY N. Now emits knex's `LIMIT -1` sentinel, matching the local transport.",
        "spec": "new additive export PAGINATION_ZERO_LIMIT_CASES + regenerated api-surface/data.json",
        "conformance": "new CASE_SETS row; ZERO DEBT rows for it — all five drivers answer it"
      },
    
      "conformance_result": "check-driver-conformance: OK — 33 covered cell(s), 2 in the DEBT ledger, 0 exempt. The 2 survivors are the untouched FILTER_TEXT_CASES rows pointing at #6682.",
      "conformance_choice": "shared case-set, not a driver-sql-local test. Added as a SEPARATE marker from PAGINATION_CASES: the two properties fail independently, and extending the existing marker would have turned the then-frozen memory/mongodb suites red on cells they already COVERED — which fails the script's RECONCILED invariant. A new marker gave them legitimately-uncovered cells (honest DEBT rows). After the scope amendment both were implemented and those DEBT rows were deleted in the same PR, exactly as the ledger's own rule requires.",
    
      "tests": {
        "new_file": "packages/drivers/driver-sql/src/sql-driver-limit-zero-presence.test.ts",
        "extended": [
          "driver-sql/sql-driver-pagination-conformance.test.ts (per dialect cell)",
          "driver-sqlite-wasm/sqlite-wasm-pagination-conformance.test.ts",
          "driver-turso/turso-pagination-conformance.test.ts (local)",
          "driver-turso/turso-remote-pagination-conformance.test.ts (remote + the bare-offset defect + compiled-statement pins)",
          "driver-memory/memory-pagination-conformance.test.ts",
          "driver-mongodb/mongodb-pagination-conformance.test.ts (live case-set + an always-running server-free guard block)"
        ],
        "fail_before_pass_after": true,
        "reverse_verification": [
          { "revert": "both sql-driver.ts doors", "predicted": "3 window + 2 analyzeQuery cases red, 8 controls green", "measured": "5 failed / 8 passed — exact" },
          { "revert": "memory-driver.ts slice", "predicted": "3 zero cases red, controls green", "measured": "3 failed / 19 passed — exact" },
          { "revert": "mongodb guard", "predicted": "3 guard cases red, failing on a CONNECTION error not a row count", "measured": "3 failed / 6 passed — exact; the 2 controls asserting the client IS consulted stayed green" },
          { "revert": "turso LIMIT -1 sentinel", "predicted": "bare-offset control red with a SQL syntax error", "measured": "SqliteError: near \"OFFSET\": syntax error" }
        ],
        "row_counts_asserted": "every empty-result case asserts a concrete count (0), each stated beside the non-zero control it must not become (2 and 12). No bare absence-of-error assertions."
      },
    
      "cells_executed": {
        "sqlite / sqlite-wasm / turso both transports / memory": "ran locally and in CI",
        "live postgres + mysql": "RAN — in CI. Not provisionable in the authoring container (declared skips via declareUnprovisionedCell, never faked green), but CI's `Temporal Conformance (live PG + MySQL)` job is GREEN on 12c8176, so the six new cases executed against both live servers.",
        "live mongod": "NOT run — mongodb-memory-server could not fetch its binary (download blocked), and CI provisions none either. Declared skip by name; 19 live cases stayed skipped. The guard is nonetheless proved unconditionally by a server-free block on a never-connected driver against an unreachable URI — for THIS contract that is the stronger instrument, since the claim IS 'no client is consulted'."
      },
    
      "gates": {
        "enumerated_from": ".github/workflows/lint.yml",
        "count": 54,
        "result": "all 54 check:* steps OK, run one by one",
        "also_green": ["pnpm lint", "turbo run typecheck 120/120", "spec tsc --noEmit", "check:empty-changeset", "check:adr-0087-registration"],
        "reds_i_caused_and_fixed": [
          "check:query-options-erasure, twice (263->267, then ->270): new test call sites had picked up `as any` on the query argument. Fixed by TYPING the call sites, not by raising the ceiling. Back at 263, 'no files added'."
        ],
        "environment_not_diff": [
          "check:i18n / check:i18n-coverage / check:app-nav-i18n / check:type-check-debt fail on an unbuilt tree and say 'Nothing was measured'. Green after turbo run build, exactly as lint.yml orders them."
        ],
        "local_full_test_run": "one red: plugin-email's attachment-queue test timed out at 5s under 120-package parallel load (transform 74s / import 218s that run). Re-run alone: 302/302 pass. Unrelated to this diff; CI's sharded Test Core 1-3/3 is green and is the authority over my single-box run."
      },
    
      "changeset": {
        "file": ".changeset/limit-zero-presence-sql-doors.md",
        "levels": {
          "@objectstack/driver-sql": "patch",
          "@objectstack/driver-memory": "patch",
          "@objectstack/driver-mongodb": "patch",
          "@objectstack/driver-turso": "patch",
          "@objectstack/spec": "minor"
        },
        "reasoning": "Behaviour fixes, user-visible, result sets only ever narrower — patch on the four drivers. driver-turso is included because its bare-offset syntax-error fix ships here. spec is minor: the export is additive, nothing existing moved. check:adr-0087-registration confirms no declared surface moves — `limit` still exists and still takes a number; what changed is that the value is now honoured."
      },
    
      "corrections_made_during_the_work": [
        "My first changeset draft claimed the driver-sql `offset` flip changed the emitted statement. Measured: knex ELIDES a zero offset on better-sqlite3, pg and mysql2 alike, so it changes nothing. Claim corrected, and the no-op is now PINNED as a no-op rather than sold as a fix.",
        "My first driver-memory DEBT row said 'probed' when it had only been read. I ran the probe before the sentence shipped — and the row was deleted entirely once the scope amendment let the defect be fixed."
      ],
    
      "open_questions": [
        {
          "q": "driver-mongodb `aggregate()` still forwards `limit` to a `$limit` stage on presence, and MongoDB REJECTS `$limit: 0`.",
          "adjudicated": "Left alone. The ruling scoped the exception to the find door, and this failure mode is LOUD (a server error) rather than the silent over-return the card is about — it fails safe. Wants its own decision about whether aggregate({limit:0}) should short-circuit too.",
          "blocking": false
        },
        {
          "q": "The turso bare-offset syntax error was outside the dispatched surface.",
          "adjudicated": "Fixed rather than deferred. It was surfaced by a control case this PR adds, and both alternatives were worse: dropping the control would hide a measured live defect (a faked green), and shipping the control without the fix leaves CI red. Called out prominently in the PR body and changeset as a SEPARATE defect so a reviewer can split it if they disagree.",
          "blocking": false
        },
        {
          "q": "driver-memory's `offset` is still truthiness-checked.",
          "adjudicated": "Deliberate — slice(0) is the identity slice, so there is no behaviour to fix, and the exception was scoped to the limit door.",
          "blocking": false
        }
      ],
    
      "successor_repricing": [
        { "issue": 6682, "effect": "unaffected", "why": "Case folding on the query paths of driver-memory / driver-mongodb — disjoint from the limit door. Both packages' FILTER_TEXT_CASES DEBT rows are untouched and still point at it. Still #5499-frozen; this PR's exception does not widen to it." },
        { "issue": 6520, "effect": "unaffected", "why": "`$icontains` vocabulary; no filter-operator surface touched." },
        { "issue": 6409, "effect": "unaffected", "why": "count_distinct in the SQL family — aggregation projection, no seam shared with the pagination clause." },
        { "issue": 6401, "effect": "unaffected", "why": "GroupByNode.alias; group-by AST, no overlap." },
        { "issue": 6402, "effect": "very slightly easier", "why": "turso `options?: any` narrowing — remote-transport.ts gains no new `any`, and its pagination assembly now has row-level AND compiled-statement coverage it did not have." },
        { "issue": 5653, "effect": "unaffected", "why": "turso remote tie-breaker — this PR touches the LIMIT/OFFSET tail of the same builder but not the ORDER BY; that suite stayed green throughout." }
      ],
    
      "out_of_scope_findings": [
        {
          "issue": 6792,
          "title": "SqlDriver.findWithWindowFunctions and analyzeQuery skip applyTenantScope",
          "posture": "finding, filed unassigned, search-first-deduped (searched applyTenantScope / findWithWindowFunctions / tenant-scope read-door phrasings; nearest neighbours #3724, #3249, #2754, #4286 all closed and different)",
          "why_not_fixed_here": "applyTenantScope's own doc calls itself 'the single chokepoint for read-side tenant isolation in the SQL driver' and says every CRUD method routes through it — 13 sites do; these two do not. The window-function door RETURNS ROWS, so on a multi-tenant deployment that is a tenant-wall bypass. Different defect, different blast radius, wants its own ruling; folding a security fix into a limit:0 PR would bury it.",
          "honesty_note": "Located by inspection, NOT measured end-to-end. Severity depends on reachability (the method is not on IDataDriver), and the issue says so explicitly rather than grading itself."
        }
      ],
    
      "constraints_honoured": {
        "content/docs/releases": "untouched",
        "pin_bumps": "none",
        "new_as_any_as_never_ts_ignore": 0,
        "spec_source_change": "one additive export + regenerated api-surface/data.json",
        "frozen_packages": "limit door only",
        "english_only_on_github": "yes; the Chinese rulings are quoted verbatim, untranslated"
      },
    
      "status": "delivered"
    }

    Generated by Claude Code

  6. os-zhuang commented on Aug 8, 2026

    @os-zhuang
    Contributor

    ACCEPT — PR #6793 passed the step-7 review against the A+ ruling; marking it ready and enabling auto-merge. This card closes with it and clears from the target:v17 board.

    Scope verified against the diff (16 files, +698/−7), not against the report's own claims:

    • Frozen packages touched at the limit door only — memory-driver.ts (14 lines), memory-analytics.ts (15), mongodb-driver.ts (35, the returnsNoRecords() short-circuit). Both FILTER_TEXT_CASES DEBT rows untouched; drivers(memory, mongodb): the $contains family still folds case — the last two backends left on the wrong side of #4706 Q2 = A #6682 stays frozen.
    • driver-sql two truthiness doors flipped (located by pattern — fix(drivers): text-operator case folding is the contract's answer, not the dialect's (#6518) #6706 had drifted them to :4197/:4237).
    • Conformance: new case-set marker, 33 covered / 2 DEBT / 0 exempt; the 2 survivors are the untouched case-folding rows. No DEBT row for limit: 0 on any driver, as ruled.
    • Gates as job conclusions: all 26 checks green on 12c8176, including ESLint, TypeScript Type Check, Test Core ×3, Dogfood ×3, and Temporal Conformance (live PG + MySQL) — so the six new cases executed against live Postgres and MySQL, not just sqlite.
    • Reverse verification predicted before each run, four experiments, all exact. Every empty-result case asserts a concrete row count beside its non-zero control.
    • No content/docs/releases/ edits, no pin bumps, zero new as any/as never; check:query-options-erasure went back to 263 by typing the new call sites rather than raising the ceiling.

    Two judgment calls endorsed:

    1. The turso bare-offset fix rode along (remote-transport.ts, +18). It is outside the dispatched surface, but a control case this PR adds surfaced it as a live defect — find(obj, {offset: N}) threw near "OFFSET": syntax error for every N. Dropping the control would have hidden a measured defect and shipping it without the fix would have left CI legitimately red; the fix is in the same LIMIT/OFFSET assembly, flagged prominently in the PR body and changeset so it can be split if a reviewer disagrees. Endorsed.
    2. mongodb aggregate()'s $limit left alone — outside the ruled door, and it fails loudly (the server rejects $limit: 0) rather than over-returning. Recorded as its own open question rather than silently widened.

    Out-of-scope finding #6792 (filed unassigned): findWithWindowFunctions and analyzeQuery skip applyTenantScope, whose own doc calls itself the single chokepoint for read-side tenant isolation. The window-function door returns rows, so on a multi-tenant deployment that reads as a tenant-wall bypass. Located by inspection, not measured end-to-end — flagged to the triage seat for grading at that severity rather than as routine cleanup.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions