Skip to content

test(objectql): conjoin $or/$and with sibling filters in six driver doubles - #7846

Merged
huangyiirene merged 1 commit into
mainfrom
claude/issue-7620-objectql-or-matcher-conjoin
Aug 11, 2026
Merged

test(objectql): conjoin $or/$and with sibling filters in six driver doubles#7846
huangyiirene merged 1 commit into
mainfrom
claude/issue-7620-objectql-or-matcher-conjoin

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Part of #7620

⚠️Part of, not Fixes, and deliberately so.#7620 names 16 files across four packages. This PR carries the six in packages/objectql/src — the domain:engine-core lane, per the claim comment on the card. The remaining ten (6 plugin-sharing, 3 plugin-security, 1 runtime) belong to two other seats and are routed separately, so the card must survive this merge.

What

Six in-memory driver doubles built a WHERE matcher that returned early on $and/$or, discarding every sibling equality key in the same object:

if(Array.isArray(where.$and))returnwhere.$and.every((w)=>matchesWhere(row,w));if(Array.isArray(where.$or))returnwhere.$or.some((w)=>matchesWhere(row,w));for(const[k,v]ofObject.entries(where)){/* the siblings, never reached */}

A real driver ANDs them. So a query shaped like SysMetadataRepository.listDrafts's —

{state: 'draft',package_id: 'app.x',$or: [{organization_id: ORG},{organization_id: null}]}

— would have been answered on the $or alone, handing back rows matching neither state nor package_id. Not a stricter or looser edge case: a different query, with the suite staying green while testing it.

The fix folds $and/$or into the entries loop so they compose with their siblings, matching the corrected form protocol-revert-org-scope.test.ts already carries from #7619 (re-verified intact on current main).

filematcher calls observed$or/$and seen
publish-meta-response-conformance.test.ts600
protocol-recorded-by-null.test.ts440
protocol-save-meta-repo-path-real-engine.test.ts210
protocol-registry-shadow.test.ts70
save-meta-response-conformance.test.ts00
plugin.authoring-channel.test.ts00

Live vs dormant — measured, not assumed

The card names establishing this as step one. A probe was installed in each of the six matchers, logging every where it was handed, and the suites run:

132 matcher calls across the six suites, and not one $or or $and. All six are dormant.

The two zero-call files never invoke their matcher at all — those suites drive writes, not reads. The control that makes the silence evidence rather than a dead probe is the 132 plain-equality calls the same instrumentation did record.

Consequence: no existing test outcome changes, and none should. There was no correction-induced failure to report — the interesting result this card could have produced (a test that was passing against a query nobody wrote) did not materialise in this lane. The card's own note that sharing and security are the likeliest to be live is unaffected by this measurement and still worth the other seats' attention.

Dormant is still worth closing: nothing distinguished "this double is faithful here" from "this double quietly changed the fixture", and the next test to add an $or would have inherited a matcher that lies.

Capability preservation

Each matcher keeps exactly the operator surface it already had — $eq unwrapping, the undefinednull comparison normalisation, and the skip for any other $-prefixed key. A non-array $and/$or still falls through to that skip, exactly as before. Measured first: the six proved semantically identical, differing only in indentation (one is 2-space) and an intermediate rowVal variable, so there was no lowest-common-denominator to flatten anything to.

No shared helper — stated deliberately

A helper local to packages/objectql would genuinely have reduced six to one. Rejected anyway, for three reasons:

  1. publish-meta-response-conformance.test.ts carries the repo's own written rationale against it: "a gate that imports its own substrate from another gate's file couples two tripwires that must be able to fail independently."
  2. fix(metadata-protocol,metadata): revert reads the history row under the key the writer stored it with (#7559) #7619's reference correction is inline for the same reason, and it is the template this card says to copy.
  3. An objectql-local helper cannot serve the ten remaining files in plugin-sharing / plugin-security / runtime — a cross-package one is out of scope by construction — so it would add a second convention rather than consolidate to one.

Verification

All run locally in a dedicated worktree at b54aaab.

gateresult
packages/objectql vitest (full)185 files / 3274 tests passed, 0 failed
pnpm check:query-options-erasureexit 0 — 67 non-test sites, none new; baseline key set verified against b54aaab, no files added
pnpm check:type-check-debtexit 0 — 33 ledger entries re-measured, none above its recorded number
pnpm check:durability-log-levelexit 0
pnpm check:engine-double-contractexit 0 — 155 pinned, unchanged
node scripts/check-engine-split-ratio.mjsexit 0
eslint on the sixclean

Gate list derived with node scripts/pm/dispatch-gates.mjs <the six paths>, not enumerated by hand. Neither ratchet baseline was raised. Nothing here let me lower a ledger entry: packages/objectql is fully type-checked and carries no entry, and the surplus the debt gate reports sits in unrelated packages.

Not in this PR


Generated by Claude Code

…er doubles (part of #7620)
Six in-memory driver doubles in `packages/objectql/src` returned early on
`$and`/`$or`, discarding every sibling equality key in the same `where`
object. A real driver ANDs them, so a query like
{ state: 'draft', package_id: 'app.x',
$or: [{ organization_id: ORG }, { organization_id: null }] }
was answered on the `$or` alone — a different query than the one written,
with the suite still green.
Fold `$and`/`$or` into the entries loop, matching the corrected form
`protocol-revert-org-scope.test.ts` already carries from #7619. Each
matcher keeps exactly the operator surface it had: `$eq` unwrapping, the
`undefined`->`null` comparison normalisation, and the skip for any other
`$`-prefixed key (which a non-array `$and`/`$or` still falls through to).
Measured, not assumed: a probe in each matcher logging every `where` it
was handed recorded 132 calls across the six suites and not one `$or` or
`$and` — all six are dormant. The 132 plain-equality calls are the
control proving the probe was live. No existing outcome changes;
packages/objectql is 185 files / 3274 tests passing before and after.
Deliberately not extracted into a shared helper: the repo's own rationale
in `publish-meta-response-conformance.test.ts` keeps these harnesses
self-contained so two gates can fail independently, and an objectql-local
helper could not serve the ten remaining files in other packages anyway.
Part of #7620 — this is the `packages/objectql` lane only; the
plugin-sharing, plugin-security and runtime files are routed separately.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Da8i4RxJBSv73tgr92D9KB
@vercel

vercelBot commented Aug 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 11, 2026 8:33pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 0 changed package(s). ✅

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 11, 2026
@huangyiirene
huangyiirene marked this pull request as ready for review August 11, 2026 21:20
@huangyiirene
huangyiirene added this pull request to the merge queueAug 11, 2026
Merged via the queue into main with commit 255f2d7Aug 11, 2026
26 checks passed
@huangyiirene
huangyiirene deleted the claude/issue-7620-objectql-or-matcher-conjoin branch August 11, 2026 21:32
huangyiirene pushed a commit that referenced this pull request Aug 11, 2026
… tier 1, part of #7620)
CI red on PR #7857: `packages/objectql/src/protocol-commit-history.test.ts` had
two org-scoped revert cases fail with COMMIT_NOT_FOUND. Measured rather than
assumed: its `matchesWhere` was pure flat equality, so the widened lookup
`{ id, $or: [{organization_id: <org>}, {organization_id: null}] }` compared
`row['$or']` against the array and matched nothing.
The double is the blind party, not the fix. Both failing rows carry the
CALLER'S OWN org (`organization_id: 'org_a'`, request org `'org_a'`), so they
match the FIRST `$or` branch outright — the same row the strict equality already
accepted. No real behaviour changed, and neither case's subject (#6602's
registry org-asymmetry) involves the commit lookup at all; it is merely the door
they enter through.
Conjoined with the sibling keys in the entries loop, matching the corrected form
#7846 landed across six doubles in this package an hour earlier. Not the
early-returning `if ($or) return …some(…)` shape those six carried before it:
that discards sibling keys, so `{ id, $or: [...] }` would stop constraining `id`
and could return some other commit whose org matched. This file was not among
#7846's six because it had no operator handling to correct, so it is a new
member of the #7620 lane rather than a regression of it.
`undefined` normalises to `null` on comparison, same as the six, because a
column a row never set reads as NULL out of a real driver.
@objectstack/objectql: 185 files / 3274 tests passing (was 184/3272 with the two
failures) — exactly the two cases restored, nothing else moved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019hxiiv8qFCUmDThHU1k7HV
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@huangyiirene@claude