Repository navigation
feat(objectql): a conformance kit a plugin driver outside this repository runs in its own CI - #27798
Conversation
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2g15Dr6sEsgv4sGBkq
…eset Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2g15Dr6sEsgv4sGBkq
📓 Docs Drift CheckThis PR changes 1 package(s): 28 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 8 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 19 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 9a70c771c3905ce86de79963730204d7fb3fcb13 && git checkout 9a70c771c3905ce86de79963730204d7fb3fcb13
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 38651598a7d8e72151ddedde3eb02e4fb0c207b6 eb7990be468b9b2c888d52098d7a07c6c766eb05 && git checkout -B drift-repro 38651598a7d8e72151ddedde3eb02e4fb0c207b6 && git merge --no-ff eb7990be468b9b2c888d52098d7a07c6c766eb05
node scripts/docs-audit/affected-docs.mjs --json 38651598a7d8e72151ddedde3eb02e4fb0c207b6
|
|
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV The seat's at-tier review call was refused by the model quota, and per contract-review.md the tier is not lowered. Owed on this head: one same-shape PM ruling on the PR's open question: this PR closes #27744 ( |
|
triage#1 · os-sales · session_01L6bhgV4fMGJHSdSdx3u9mK Contract-review-claim: Generated by Claude Code |
|
triage#1 · os-sales · session_01L6bhgV4fMGJHSdSdx3u9mK Contract reviewServed-tier: Face: the ① Derived judgments
② Semver level
③ Boundary flags
Must-fix: none. Implemented-by: VERDICT: PASS Generated by Claude Code |
…-process OData service Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2g15Dr6sEsgv4sGBkq
|
triage#1 · os-sales · session_01L6bhgV4fMGJHSdSdx3u9mK Contract-review-claim: Generated by Claude Code |
|
triage#1 · os-sales · session_01L6bhgV4fMGJHSdSdx3u9mK Contract reviewServed-tier: Delta review on record 6511619545 (head What moved since the previous record — two commits. (a) ① Derived judgments
② Semver levelStands as judged in record 6511619545: the changeset ③ Boundary flags
Must-fix: none. Implemented-by: VERDICT: PASS Generated by Claude Code |
|
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV 维护者速读
席位意见:ACCEPT。契约复核 PASS 在案(分诊 6513256862, 席位核对
|
|
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV The 速读 line 风险与回滚 says changeset |
Requested by 田騏 · project thread
Part of #27744
Clause-②: yes
Metadata-protocol: none
维护者速读
@objectstack/objectql新增并导出一套插件驱动一致性测试套件(conformance kit):仓库外的驱动(如闭源 Salesforce 驱动)在自己的 CI 里调用它,用 spec 的驱动一致性用例表检验引擎对插件驱动的兜底契约(读、筛选下推或兜底、计数、写入拒绝、故障应答、introspectSchema形状)。packages/objectql/src/plugin-driver-conformance.ts(判定规则在judgeRows/judgeReadThrow/flooredRead);packages/objectql/src/plugin-driver-conformance.test.ts(每个变异驱动应在哪条用例上失败)。pnpm --filter @objectstack/objectql exec vitest run src/plugin-driver-conformance.test.ts,应见 330 个用例全绿(其中套件形态注册了约 300 个逐例测试)。What changes
@objectstack/objectqlexports a conformance kit for plugin drivers (driver.NAMEservices a server plugin publishes) that live outside this repository. The driver's own CI runs it; a change to the contract here then turns that CI red.external-driver-floor.ts), against the spec's driver conformance tables, never any one driver:floor/shape: per fixture, the plainest read the floor sends returns every stored row once, string ids, no_id, and every stored value unchanged (anullstaysnull, a number stays a number, an instant may come back as a nativeDate).floor/filter: every row ofFILTER_LOGIC_CASES, the evaluated rows ofFILTER_TEXT_CASESand everyTEMPORAL_CASESfilter (lowered as the engine lowers it, and again through its relative tokens). The driver's own answer to the query the floor sends must hold every matching row and only stored rows, or refuse with 400, 404 or 422; the floored answer must equal the table'sexpected.floor/count:countthrough the floor, perFILTER_LOGIC_CASESrow.floor/order: the floor's paged walk for everyPAGINATION_CASESsort is a partition in the requested order.floor/write: caller-named write probes; a refused one must reach the caller as422 EXTERNAL_WRITE_REFUSED.floor/outage: with the caller's unavailable remote,find,findOneandcountreach the caller as503 ERR_DATASOURCE_UNAVAILABLE, never as rows and never as a 4xx.floor/introspect: theIntrospectedSchemashape when the driver offersintrospectSchema().DriverCapabilitiescarries no pushdown claim (retired in 17.0.0), so each read result carriespushdown: exact | superset | refusedand each ordered readorder: honoured | not-honoured.directtier checks that the driver answers the whole query itself: exact filter,count,findOne, deterministic paged walks (PAGINATION_CASES,PAGINATION_UNORDERED_CASES) andlimitby presence (PAGINATION_ZERO_LIMIT_CASES). The floor needs none of it. It is the oracle the epic's P3 verified-pushdown credential can key on (case ids are stable:tier/group/fixture/case name).definePluginDriverConformanceSuite({ describe, it, afterAll }, options)registers one test per case (vitest or jest);runPluginDriverConformance(options)answers a report with no framework;createPluginDriverConformance(options)hands out the raw cases.setup(fixture)builds the driver over a remote holding exactly the fixture's rows: a fake of the remote's API in front of the driver's real translation code, or a sandbox seeded frompluginDriverConformanceFixtures(). Reads share one setup per fixture; each write probe gets a fresh one; every setup is torn down once. Absent optional inputs (setupUnavailable,writeProbes,introspectSchema) answernot-offered, never a silent pass.Why
Epic #27261 P2, maintainer order 2026-10-29T22:01Z 「同意」: vendor-specific drivers stay out of this repository as plugin packages, verified by a public conformance kit. Until now the floor's contract was pinned only by this package's internal tests, which a driver in another repository never runs.
Tests
packages/objectql/src/plugin-driver-conformance.test.tsholds the kit to both halves of being an instrument:exact, every orderhonoured); an every-row driver (the guide's step 1: floor tier passes, measuredsupersetandnot-honoured, direct tier fails); a driver refusing$orwith status 400 (floor passes, measuredrefused); a remote answering instants as nativeDates; absent optional inputs reportednot-offered; teardown once per setup.$or; anullstored as''; a number stored as text; a refusal with no status; a row answered twice; an invented row; an outage answered as[](all three reads, a count of 0 included) or as a 404; a write refusal declaring 500; a probe whose outcome differs either way;introspectSchemaspellingisPrimary; direct tier: a count ignoring the filter, a paged walk with no stable order.definePluginDriverConformanceSuiteunder this file's own vitestdescribe/it/afterAll) runs the exact driver through both tiers, as a vendor's CI would.Measured at head
07def8cc(origin/main968cacfdmerged; the merge touched nothing in@objectstack/objectql's dependency closure):pnpm --filter @objectstack/objectql test — 491 files / 9574 tests passed
The new file alone:
Tests 330 passed (330).pnpm --filter @objectstack/objectql typecheck — exit 0
No new test-typecheck debt.
Acceptance notes
Part of, notFixes. The card's other two items are outside this claim's file surface and are left to their own carriers: running the kit fromdriver-odata(driver-odata: a declarative OData v4 datasource driver (plugin-published id, pushdown for $filter/$orderby/$top/$skip/$count, the engine floor for the rest) — epic #27261 P2 #27741 owns that package and is in flight; its PR, or a follow-up once it lands, adds one test callingdefinePluginDriverConformanceSuitewith asetupthat builds the OData driver over a fake OData service holding the fixture rows, plus write probes), and the guide's plugin-driver section pointing to the kit (content/docs/data-modeling/virtual-objects.mdx, step 3 of "The engine re-applies every query"; the guide card docs: the external-systems guide gains the OData datasource section and the three-way choice (declarative OData, plugin driver, DataSync mirror) — epic #27261 P2 #27747 can carry it). The PM decides whether this PR closes the card once those are placed.supports-declared pushdown".DriverCapabilitieshas no pushdown declaration to read, so the kit measures pushdown per case instead; that measurement is what the P3 credential can be built on.TEMPORAL_TIME_CASES(no time-of-day field in the floor's comparand classes yet).@objectstack/objectqlbecause it drives the floor itself (createExternalDriverFloor), so a vendor tests against the floor of the version it installs.Verification
dispatch-gates --commands at 07def8c: 59 derived, 59 run, all exit 0
Every derived family run locally, exit codes captured before any pipe.
check:dual-build-cjs-loadsfirst exited 3 (no builtdist/yet); rerun aftercheck:type-check-debtbuilt the packages: exit 0.The test-double ratchets read the new file:
check:objectql-double-limit(none new),check:where-matcher(none new),check:engine-double-contractexit 0.The remaining families are CI's (the PR's check-runs).
Human Minimum
packages/specholds no runtime logic. (No spec change.)eslint --no-inline-configover the three changed source files exits 0 (the repo-widepnpm lintis CI's run).main, one pull request.packages/spectouched: not touched.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_017ihL2g15Dr6sEsgv4sGBkq
Generated by Claude Code