From ebae4b6e9ef0bcdeb4621b4c66b397645515e25e Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 26 Aug 2026 03:05:12 +0000 Subject: [PATCH 1/3] test(engine-doubles): adopt assertEngineFindOnePredicate across 212 files / 245 findOne doubles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The adoption half of #12068. Discovery was NOT re-derived by hand: the population is `check:engine-double-contract`'s own reported (file, line) answers with a findOne slice installed, so the batch cannot be narrower or wider than what the gate scores. `@objectstack/service-datasource` gains `@objectstack/metadata-core` as a devDependency — the one package in the remainder that depended on neither home of the predicate. Acyclic, measured rather than cited: `turbo run build --filter=@objectstack/service-datasource --dry` exits 0 with zero circular-dependency reports and metadata-core present in the graph. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01W6HFzyH98W1YaQXhJUJt6o --- .../core/src/utils/migration-journal.test.ts | 3 ++- packages/mcp/src/__tests__/plugin.test.ts | 3 ++- packages/mcp/src/mcp-stdio-tools.test.ts | 4 ++-- ...te-response-internal-fields.tripwire.test.ts | 4 ++-- .../src/plugin.record-resource-exposure.test.ts | 4 ++-- .../mcp/src/stdio-data-bridge.exposure.test.ts | 3 ++- .../mcp/src/stdio-data-bridge.not-found.test.ts | 3 ++- .../src/migrations/recorded-by-sentinel.test.ts | 3 ++- .../protocol-publish-drafts-advisories.test.ts | 3 ++- .../src/protocol-publish-drafts-closure.test.ts | 3 ++- ...rotocol-publish-drafts-endpoint-gate.test.ts | 3 ++- .../protocol-publish-drafts-org-scope.test.ts | 3 ++- ...rotocol-publish-drafts-package-scope.test.ts | 3 ++- ...otocol.adr0005-org-override-rollback.test.ts | 3 ++- .../src/protocol.audit-field-governance.test.ts | 3 ++- .../src/protocol.batch-atomic.test.ts | 4 ++-- .../src/protocol.batch-not-attempted.test.ts | 4 ++-- .../src/protocol.batch-row-conformance.test.ts | 4 ++-- .../src/protocol.batch-row-driver-text.test.ts | 4 ++-- .../src/protocol.batch-row-http-status.test.ts | 4 ++-- .../src/protocol.batch-verb-driver-code.test.ts | 3 ++- .../src/protocol.batch-verb-driver-text.test.ts | 3 ++- .../src/protocol.bulk-record-not-found.test.ts | 4 ++-- .../src/protocol.capability-write-door.test.ts | 3 ++- .../src/protocol.code-only-types.test.ts | 3 ++- .../protocol.container-issue-descent.test.ts | 5 +++-- ...tocol.dashboard-dataset-publish-gate.test.ts | 3 ++- ...ol.delete-object-registry-unregister.test.ts | 3 ++- .../src/protocol.delete-receipt-wording.test.ts | 3 ++- .../src/protocol.delete-rewrap-envelope.test.ts | 3 ++- ...tocol.destructive-409-face-inventory.test.ts | 2 ++ ...col.destructive-gate-reachable-types.test.ts | 3 ++- .../protocol.diagnostics-store-outage.test.ts | 12 +++++++----- ...ff-canonical-type-and-history-outage.test.ts | 3 ++- .../protocol.diff-credential-redaction.test.ts | 3 ++- .../src/protocol.diff-dead-history-read.test.ts | 3 ++- .../src/protocol.driver-text-disclosure.test.ts | 3 ++- .../src/protocol.dropped-fields.bulk.test.ts | 6 +++--- .../src/protocol.dropped-fields.test.ts | 8 ++++---- .../protocol.flow-org-override-closed.test.ts | 3 ++- .../protocol.graft-folded-form-sections.test.ts | 3 ++- ...tocol.hydrate-overlay-canonical-type.test.ts | 4 +++- .../src/protocol.i18n-bundle-list-merge.test.ts | 5 +++-- .../protocol.injected-system-columns.test.ts | 3 ++- ....invalid-metadata-422-face-inventory.test.ts | 5 +++-- .../src/protocol.item-name-grammar.test.ts | 3 ++- .../src/protocol.legacy-overlay-delete.test.ts | 4 +++- .../src/protocol.lifecycle-audit-rows.test.ts | 3 ++- .../protocol.lock-gate-canonical-type.test.ts | 2 ++ .../src/protocol.lock-gate-fail-closed.test.ts | 3 ++- .../src/protocol.many-data-atomic.test.ts | 4 ++-- ...col.meta-list-runtime-baseline-dedup.test.ts | 4 +++- ...tocol.meta-types-mint-door-agreement.test.ts | 5 +++-- .../src/protocol.metadata-redaction.test.ts | 3 ++- .../src/protocol.metadata-store-outage.test.ts | 6 ++++-- ...col.migrate-stored-noncanonical-type.test.ts | 3 ++- ...ject-registry-write-through-spelling.test.ts | 3 ++- ...scoped-cold-boot-audit-live-registry.test.ts | 5 +++-- .../protocol.org-scoped-cold-boot-audit.test.ts | 5 +++-- .../protocol.org-scoped-write-refused.test.ts | 3 ++- .../src/protocol.package-closure-gate.test.ts | 3 ++- .../protocol.package-publish-audit-rows.test.ts | 3 ++- .../protocol.platform-schedule-org-gate.test.ts | 3 ++- ....publish-commit-capture-read-failure.test.ts | 3 ++- ...rotocol.publish-item-draft-org-scope.test.ts | 3 ++- ...rotocol.publish-item-rebind-announce.test.ts | 3 ++- ....publish-side-effects-canonical-type.test.ts | 3 ++- ...otocol.publish-stored-type-canonical.test.ts | 3 ++- .../src/protocol.read-decorations.test.ts | 3 ++- ...protocol.read-seam-empty-accumulator.test.ts | 13 +++++++------ .../protocol.read-verb-canonical-fold.test.ts | 2 ++ .../src/protocol.record-not-found.test.ts | 4 ++-- ...col.record-package-commit-durability.test.ts | 3 ++- .../src/protocol.reference-derivation.test.ts | 4 +++- ...otocol.reference-target-unanswerable.test.ts | 4 +++- ...rotocol.revert-stored-type-canonical.test.ts | 3 ++- .../src/protocol.runtime-authoring-gate.test.ts | 3 ++- .../protocol.save-flow-canonicalization.test.ts | 3 ++- .../src/protocol.save-meta-missing-item.test.ts | 3 ++- .../src/protocol.save-receipt-wording.test.ts | 3 ++- .../src/protocol.save-union-issues.test.ts | 5 +++-- .../src/protocol.stored-conversions.test.ts | 3 ++- .../src/protocol.stored-migration.test.ts | 3 ++- .../src/protocol.stored-residue-resave.test.ts | 3 ++- .../src/protocol.unrecognised-meta-type.test.ts | 3 ++- .../src/protocol.update-path-id-wins.test.ts | 3 ++- .../src/protocol.upsert-existence.test.ts | 3 ++- ...te-response-internal-fields.tripwire.test.ts | 4 ++-- .../src/search-clone-schema-conformance.test.ts | 3 ++- .../seed-loader-composite-external-id.test.ts | 3 ++- .../src/seed-loader-deferred-dropped.test.ts | 3 ++- .../src/seed-loader-deferred-failure.test.ts | 3 ++- .../src/seed-loader-driver-text.test.ts | 5 +++-- .../seed-loader-engine-schema-fallback.test.ts | 3 ++- .../src/seed-loader-env-scope.test.ts | 4 ++-- ...loader-existing-records-read-failure.test.ts | 3 ++- .../seed-loader-multi-value-reference.test.ts | 3 ++- .../src/seed-loader-name-probe.test.ts | 3 ++- .../src/seed-loader-pointer-pair.test.ts | 3 ++- .../src/seed-loader-replay.test.ts | 3 ++- .../src/seed-loader-retry.test.ts | 3 ++- .../seed-loader-state-machine-exempt.test.ts | 4 ++-- .../src/seed-loader-summary-stale.test.ts | 3 ++- .../src/seed-loader-unresolved-drop.test.ts | 3 ++- .../sys-metadata-repository.contract.test.ts | 3 ++- .../sys-metadata-repository.draft-drain.test.ts | 3 ++- ...ata-repository.draft-package-inherit.test.ts | 3 ++- ...metadata-repository.history-counters.test.ts | 3 ++- ...adata-repository.package-writability.test.ts | 3 ++- .../sys-metadata-repository.recorded-by.test.ts | 3 ++- .../view-container-runtime-expansion.test.ts | 5 +++-- .../migrate-sys-notification-to-event.test.ts | 5 +++-- .../accept-invitation-adopt-membership.test.ts | 3 ++- ...dmin-revoke-user-session-match-guard.test.ts | 3 ++- .../src/audience-posture-setting.test.ts | 3 ++- .../plugin-auth/src/audience-posture.test.ts | 3 ++- .../src/auth-contains-filter.test.ts | 3 ++- .../src/auth-manager.jwt-eddsa-fallback.test.ts | 3 ++- ...th-manager.optional-plugin-isolation.test.ts | 2 ++ .../plugin-auth/src/auth-manager.test.ts | 7 +++++-- .../src/auth-where-operator-coverage.test.ts | 4 ++-- .../src/change-email-delete-user-wiring.test.ts | 3 ++- .../first-session-membership-ordering.test.ts | 6 ++++-- .../src/impersonation-bearer-rotation.test.ts | 3 ++- .../src/membership-policy-setting.test.ts | 3 ++- .../src/org-create-posture-gate.test.ts | 3 ++- .../src/organization-add-member.test.ts | 3 ++- .../src/remove-member-permission-guard.test.ts | 3 ++- .../src/remove-user-atomicity.test.ts | 3 ++- .../src/revoke-session-match-guard.test.ts | 3 ++- .../scim-case-insensitive-identifier.test.ts | 3 ++- .../plugin-auth/src/session-of-record.test.ts | 3 ++- .../plugin-auth/src/session-tombstone.test.ts | 3 ++- .../src/authored-row-write-verdict.test.ts | 3 ++- .../src/check-only-write-scope.test.ts | 3 ++- .../src/controlled-by-parent-chain.test.ts | 2 ++ ...led-by-parent-detail-write-authority.test.ts | 2 ++ .../controlled-by-parent-master-widener.test.ts | 2 ++ .../src/controlled-by-parent-sharing.test.ts | 3 ++- .../plugin-security/src/explain-engine.test.ts | 3 ++- .../src/field-masking-rule.test.ts | 5 +++-- .../src/invitation-placement.test.ts | 3 ++- .../packaged-permission-set-lock-gate.test.ts | 3 ++- .../src/packaged-permission-set-lock.test.ts | 3 ++- .../packaged-permission-set-restore-leg.test.ts | 3 ++- .../src/permission-denied-user-copy.test.ts | 3 ++- .../src/permission-set-active.test.ts | 3 ++- .../src/permission-set-projection.test.ts | 2 ++ .../src/permission-set-resolution-memo.test.ts | 3 ++- ...olve-permission-sets-for-context.pin.test.ts | 3 ++- .../src/row-write-widener-composition.test.ts | 3 ++- .../src/security-denial-user-copy.test.ts | 3 ++- .../plugin-security/src/security-plugin.test.ts | 10 ++++++---- .../src/select-only-write-visibility.test.ts | 3 ++- .../src/store-fault-fail-closed.test.ts | 2 ++ .../src/vama-write-path-convergence.test.ts | 3 ++- .../src/authored-row-write-deferral.test.ts | 3 ++- .../src/share-link-eligibility.test.ts | 4 ++-- .../plugin-webhooks/src/auto-enqueuer.test.ts | 2 ++ .../src/bootstrap-declared-webhooks.test.ts | 2 ++ .../src/webhook-drop-durable-record.test.ts | 3 ++- .../src/webhook-signing-secret.test.ts | 5 +++-- .../src/meta-compound-save-force-parity.test.ts | 3 ++- .../src/meta-compound-save-mode-parity.test.ts | 3 ++- .../src/meta-object-extension-agreement.test.ts | 4 ++-- ...ta-object-extension-property-classes.test.ts | 4 ++-- ...eta-object-materialization-agreement.test.ts | 4 ++-- .../meta-object-overlay-extension-fold.test.ts | 4 ++-- ...ta-object-search-companion-agreement.test.ts | 4 ++-- .../rest/src/meta-published-overlay.test.ts | 3 ++- .../rest/src/public-form-lookup-picker.test.ts | 5 +++-- .../src/public-form-routes.stored-row.test.ts | 5 +++-- .../src/rest-server-meta-read-org-scope.test.ts | 3 ++- ...ion-execution-calldata-batch-retired.test.ts | 3 ++- .../action-execution-calldata-not-found.test.ts | 4 ++-- .../meta-published-runtime-publish.test.ts | 3 ++- .../meta-save-destructive-remedy.test.ts | 3 ++- .../src/meta-compound-arity-mint-door.test.ts | 3 ++- .../runtime/src/meta-field-overlay-lock.test.ts | 3 ++- .../src/meta-overlay-read-your-writes.test.ts | 4 ++-- .../runtime/src/meta-write-org-scope.test.ts | 3 ++- packages/runtime/src/seed-loader.test.ts | 3 ++- .../src/builtin/crud-bulk-intent.test.ts | 4 ++-- .../src/builtin/crud-config-aliases.test.ts | 4 +++- .../src/builtin/crud-filter-guard.test.ts | 4 +++- .../src/builtin/crud-output-var.test.ts | 4 +++- .../src/builtin/crud-runas.test.ts | 4 +++- ...otify-organization-stamp.integration.test.ts | 4 +++- .../record-lookup-expand.integration.test.ts | 2 ++ .../service-automation/src/run-summary.test.ts | 17 +++++++++++------ .../runas-grant-resolution.integration.test.ts | 4 +++- .../services/service-datasource/package.json | 1 + .../__tests__/datasource-admin-plugin.test.ts | 2 ++ ...delivery-headers-at-rest.integration.test.ts | 4 ++-- .../service-messaging/src/email-channel.test.ts | 2 ++ .../service-messaging/src/inbox-channel.test.ts | 2 ++ .../src/messaging-service-plugin.test.ts | 7 +++++-- .../src/messaging-service.test.ts | 15 +++++++++++---- .../src/notification-schema-conformance.test.ts | 3 ++- .../src/preference-resolver.test.ts | 4 +++- .../src/read-receipt-organization.test.ts | 2 ++ .../src/recipient-resolver.test.ts | 2 ++ .../service-messaging/src/sms-channel.test.ts | 2 ++ .../src/sql-outbox-audit-columns.test.ts | 2 ++ .../src/template-renderer.test.ts | 2 ++ .../src/attachment-access-hooks.test.ts | 6 +++--- .../src/attachment-lifecycle.test.ts | 3 ++- .../src/file-reference-lifecycle.test.ts | 2 ++ .../src/lax-deviation-reclamation-gate.test.ts | 3 ++- .../service-storage/src/metadata-store.test.ts | 3 ++- .../src/storage-routes.metadata-outage.test.ts | 3 ++- .../tombstone-download-live-reference.test.ts | 3 ++- pnpm-lock.yaml | 3 +++ 213 files changed, 498 insertions(+), 260 deletions(-) diff --git a/packages/core/src/utils/migration-journal.test.ts b/packages/core/src/utils/migration-journal.test.ts index bfc0839703d..6165b045a76 100644 --- a/packages/core/src/utils/migration-journal.test.ts +++ b/packages/core/src/utils/migration-journal.test.ts @@ -27,7 +27,7 @@ import { assertEngineUpdateDispatch, type EngineDeleteDispatchInput, type EngineUpdateDispatchData, - type EngineUpdateDispatchInput, + type EngineUpdateDispatchInput, assertEngineFindOnePredicate, } from '@objectstack/metadata-core'; import { runMigrationJournal, @@ -85,6 +85,7 @@ class FakeEngine { } async findOne(objectName: string, query?: { where?: Record }): Promise { + assertEngineFindOnePredicate(objectName, query); return (await this.find(objectName, query))[0] ?? null; } diff --git a/packages/mcp/src/__tests__/plugin.test.ts b/packages/mcp/src/__tests__/plugin.test.ts index f5f97c070c4..03c78778cad 100644 --- a/packages/mcp/src/__tests__/plugin.test.ts +++ b/packages/mcp/src/__tests__/plugin.test.ts @@ -2,6 +2,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { MCPServerPlugin } from '../plugin.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; // --------------------------------------------------------------------------- // Mock PluginContext @@ -69,7 +70,7 @@ function createMockMetadataService() { function createMockDataEngine() { return { find: vi.fn(async () => []), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), insert: vi.fn(), update: vi.fn(), delete: vi.fn(), diff --git a/packages/mcp/src/mcp-stdio-tools.test.ts b/packages/mcp/src/mcp-stdio-tools.test.ts index 6639c125815..60ae4ac3a20 100644 --- a/packages/mcp/src/mcp-stdio-tools.test.ts +++ b/packages/mcp/src/mcp-stdio-tools.test.ts @@ -41,7 +41,7 @@ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { MCPServerRuntime } from './mcp-server-runtime.js'; import { MCPServerPlugin } from './plugin.js'; import type { McpDataBridge } from './mcp-http-tools.js'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; // --------------------------------------------------------------------------- // A real stdio client: newline-delimited JSON-RPC over the transport's pipes @@ -503,7 +503,7 @@ describe('#8034 plugin composition: os serve stdio wiring', () => { }), aggregate: vi.fn(async () => []), count: vi.fn(async () => 0), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), }; } diff --git a/packages/mcp/src/mcp-write-response-internal-fields.tripwire.test.ts b/packages/mcp/src/mcp-write-response-internal-fields.tripwire.test.ts index ce4469b3856..87a4e773e29 100644 --- a/packages/mcp/src/mcp-write-response-internal-fields.tripwire.test.ts +++ b/packages/mcp/src/mcp-write-response-internal-fields.tripwire.test.ts @@ -46,7 +46,7 @@ import type { ExecutionContext } from '@objectstack/spec/kernel'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; import { omitInternalFieldsFromWriteResponse } from '@objectstack/core'; import { createStdioDataBridge } from './stdio-data-bridge.js'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** The value that must NEVER appear in any MCP response. */ const SENTINEL = 'INTERNAL-SENTINEL-8497-NEVER-SERIALIZED'; @@ -81,7 +81,7 @@ function makeSentinelEngine(): IDataEngine { }); return { find: vi.fn(async () => [storedRow()]), - findOne: vi.fn(async () => storedRow()), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return storedRow(); }), insert: vi.fn(async (_o: string, data: Record) => writtenRow((data?.id as string) ?? 'new-1', data)), update: vi.fn(async (_o: string, data: Record, options?: any) => { diff --git a/packages/mcp/src/plugin.record-resource-exposure.test.ts b/packages/mcp/src/plugin.record-resource-exposure.test.ts index deffd4c3941..0220fe5f9db 100644 --- a/packages/mcp/src/plugin.record-resource-exposure.test.ts +++ b/packages/mcp/src/plugin.record-resource-exposure.test.ts @@ -50,7 +50,7 @@ import type { IMetadataService } from '@objectstack/spec/contracts'; import type { MCPServerRuntime } from './mcp-server-runtime.js'; import { MCPServerPlugin } from './plugin.js'; import { enforceApiExposure, GATED_ACTIONS, type McpExposureError } from './stdio-data-bridge.js'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; // --------------------------------------------------------------------------- // A real stdio client: newline-delimited JSON-RPC over the transport's pipes @@ -172,7 +172,7 @@ function fakeObjectQL() { }), aggregate: vi.fn(async () => []), count: vi.fn(async () => 0), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), }; } diff --git a/packages/mcp/src/stdio-data-bridge.exposure.test.ts b/packages/mcp/src/stdio-data-bridge.exposure.test.ts index 8651196d95c..75f2fcc02a4 100644 --- a/packages/mcp/src/stdio-data-bridge.exposure.test.ts +++ b/packages/mcp/src/stdio-data-bridge.exposure.test.ts @@ -39,6 +39,7 @@ import { DATA_ACTION_TO_API_OPERATION } from '@objectstack/spec/data'; import type { ExecutionContext } from '@objectstack/spec/kernel'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; import { createStdioDataBridge, GATED_ACTIONS, type McpExposureError } from './stdio-data-bridge.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; // --------------------------------------------------------------------------- // Doubles @@ -54,7 +55,7 @@ import { createStdioDataBridge, GATED_ACTIONS, type McpExposureError } from './s function makeEngine(rows: Array> = [{ id: 'r1', title: 'row' }]) { return { find: vi.fn(async () => rows), - findOne: vi.fn(async () => rows[0] ?? null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return rows[0] ?? null; }), insert: vi.fn(), update: vi.fn(), delete: vi.fn(), diff --git a/packages/mcp/src/stdio-data-bridge.not-found.test.ts b/packages/mcp/src/stdio-data-bridge.not-found.test.ts index 53b81aa8bc0..e533773eb5a 100644 --- a/packages/mcp/src/stdio-data-bridge.not-found.test.ts +++ b/packages/mcp/src/stdio-data-bridge.not-found.test.ts @@ -23,12 +23,13 @@ import { describe, it, expect, vi } from 'vitest'; import type { ExecutionContext } from '@objectstack/spec/kernel'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; import { createStdioDataBridge } from './stdio-data-bridge.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** An engine that resolves NO row for any id — every by-id write is a miss. */ function makeEmptyEngine() { return { find: vi.fn(async () => []), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), insert: vi.fn(), update: vi.fn(), delete: vi.fn(), diff --git a/packages/metadata-protocol/src/migrations/recorded-by-sentinel.test.ts b/packages/metadata-protocol/src/migrations/recorded-by-sentinel.test.ts index cf042f02db4..f08d972ff0e 100644 --- a/packages/metadata-protocol/src/migrations/recorded-by-sentinel.test.ts +++ b/packages/metadata-protocol/src/migrations/recorded-by-sentinel.test.ts @@ -29,7 +29,7 @@ import { runMigrationJournal, readRunJournal } from '@objectstack/core'; // package both sides already depend on, which is what makes this line legal. import { assertEngineDeleteDispatch, - assertEngineUpdateDispatch, + assertEngineUpdateDispatch, assertEngineFindOnePredicate, } from '@objectstack/metadata-core'; import { createRecordedBySentinelPlan, @@ -77,6 +77,7 @@ class FakeEngine { } async findOne(objectName: string, query?: { where?: Record }): Promise { + assertEngineFindOnePredicate(objectName, query); return (await this.find(objectName, query))[0] ?? null; } diff --git a/packages/metadata-protocol/src/protocol-publish-drafts-advisories.test.ts b/packages/metadata-protocol/src/protocol-publish-drafts-advisories.test.ts index cadcabecc1f..0bbadbaaef2 100644 --- a/packages/metadata-protocol/src/protocol-publish-drafts-advisories.test.ts +++ b/packages/metadata-protocol/src/protocol-publish-drafts-advisories.test.ts @@ -35,7 +35,7 @@ */ import { describe, expect, it } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -117,6 +117,7 @@ function makeStubEngine() { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol-publish-drafts-closure.test.ts b/packages/metadata-protocol/src/protocol-publish-drafts-closure.test.ts index ceebef10d70..b2f81eab116 100644 --- a/packages/metadata-protocol/src/protocol-publish-drafts-closure.test.ts +++ b/packages/metadata-protocol/src/protocol-publish-drafts-closure.test.ts @@ -56,7 +56,7 @@ import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'; // The producer's OWN write-verb dispatch decisions, so the fake engine below // cannot accept a call ObjectQL refuses. From `@objectstack/metadata-core`, // never from `@objectstack/objectql` — that import would close a cycle. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -155,6 +155,7 @@ function makeStubEngine(options?: { liveObjects?: unknown[]; livePermissions?: u const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol-publish-drafts-endpoint-gate.test.ts b/packages/metadata-protocol/src/protocol-publish-drafts-endpoint-gate.test.ts index 97d856d55da..1450cb457c0 100644 --- a/packages/metadata-protocol/src/protocol-publish-drafts-endpoint-gate.test.ts +++ b/packages/metadata-protocol/src/protocol-publish-drafts-endpoint-gate.test.ts @@ -8,7 +8,7 @@ import { describe, expect, it } from 'vitest'; // would close a dependency cycle turbo rejects outright — which is why all 26 // of this package's (file, verb) pairs sat in the gate's DEBT ledger until // #5619 sank the two predicates into a package both sides already depend on. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { identityFreeEndpointGateFailure, ApiEndpointSchema } from '@objectstack/spec/api'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -149,6 +149,7 @@ function makeStubEngine(namespace?: string) { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol-publish-drafts-org-scope.test.ts b/packages/metadata-protocol/src/protocol-publish-drafts-org-scope.test.ts index 7d34f46e001..67d22a65834 100644 --- a/packages/metadata-protocol/src/protocol-publish-drafts-org-scope.test.ts +++ b/packages/metadata-protocol/src/protocol-publish-drafts-org-scope.test.ts @@ -8,7 +8,7 @@ import { describe, expect, it } from 'vitest'; // would close a dependency cycle turbo rejects outright — which is why all 26 // of this package's (file, verb) pairs sat in the gate's DEBT ledger until // #5619 sank the two predicates into a package both sides already depend on. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; /** @@ -126,6 +126,7 @@ function makeStubEngine() { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol-publish-drafts-package-scope.test.ts b/packages/metadata-protocol/src/protocol-publish-drafts-package-scope.test.ts index f00660d0615..368a5a4f76d 100644 --- a/packages/metadata-protocol/src/protocol-publish-drafts-package-scope.test.ts +++ b/packages/metadata-protocol/src/protocol-publish-drafts-package-scope.test.ts @@ -6,7 +6,7 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; // refuses. Imported from `@objectstack/metadata-core` and not from // `@objectstack/objectql`: objectql DEPENDS ON this package, so that import // would close a dependency cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, hashSpec } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, hashSpec, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; /** @@ -135,6 +135,7 @@ function makeStubEngine() { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol.adr0005-org-override-rollback.test.ts b/packages/metadata-protocol/src/protocol.adr0005-org-override-rollback.test.ts index bce30b73bd1..bf63d093f31 100644 --- a/packages/metadata-protocol/src/protocol.adr0005-org-override-rollback.test.ts +++ b/packages/metadata-protocol/src/protocol.adr0005-org-override-rollback.test.ts @@ -98,7 +98,7 @@ * cannot see it. */ import { describe, expect, it } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -119,6 +119,7 @@ function makeStubEngine(artifacts: Array<{ type: string; name: string }> = []) { `${w.type}|${w.name}|${w.organization_id ?? '__env__'}|${w.state ?? 'active'}`; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); for (const row of rows.values()) { if (opts.where.type !== undefined && row.type !== opts.where.type) continue; if (opts.where.name !== undefined && row.name !== opts.where.name) continue; diff --git a/packages/metadata-protocol/src/protocol.audit-field-governance.test.ts b/packages/metadata-protocol/src/protocol.audit-field-governance.test.ts index 5a9d760eead..17e335d6697 100644 --- a/packages/metadata-protocol/src/protocol.audit-field-governance.test.ts +++ b/packages/metadata-protocol/src/protocol.audit-field-governance.test.ts @@ -45,7 +45,7 @@ import { describe, expect, it } from 'vitest'; // below cannot accept a call ObjectQL refuses. From `@objectstack/metadata-core` // and not `@objectstack/objectql`: objectql DEPENDS ON this package, so that // import would close a cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { AUDIT_PROVENANCE_FIELDS } from '@objectstack/spec/data'; import { ObjectStackProtocolImplementation } from './index.js'; @@ -82,6 +82,7 @@ function makeStubEngine() { }; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return findRow(opts.where)?.row ?? null; }, async find(_t: string, opts: { where: Record }) { diff --git a/packages/metadata-protocol/src/protocol.batch-atomic.test.ts b/packages/metadata-protocol/src/protocol.batch-atomic.test.ts index 7518d0000b9..c0ade64b05a 100644 --- a/packages/metadata-protocol/src/protocol.batch-atomic.test.ts +++ b/packages/metadata-protocol/src/protocol.batch-atomic.test.ts @@ -14,7 +14,7 @@ // is already in the database. import { describe, it, expect, vi } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; const SCHEMA = { @@ -47,7 +47,7 @@ function makeTransactionalEngine(opts: { driverCanTransact?: boolean } = {}) { if (data?.title === POISON) throw new Error('update exploded'); return { id: options?.where?.id, ...data }; }); - const findOne = vi.fn(async (_object: string, options?: any) => ({ id: options?.where?.id })); + const findOne = vi.fn(async (_object: string, options?: any) => { assertEngineFindOnePredicate(_object, options); return ({ id: options?.where?.id }); }); const del = vi.fn(async (_object: string, options?: any) => { assertEngineDeleteDispatch(options); return { deleted: 1 }; diff --git a/packages/metadata-protocol/src/protocol.batch-not-attempted.test.ts b/packages/metadata-protocol/src/protocol.batch-not-attempted.test.ts index 6752d02e38f..adb3e62442e 100644 --- a/packages/metadata-protocol/src/protocol.batch-not-attempted.test.ts +++ b/packages/metadata-protocol/src/protocol.batch-not-attempted.test.ts @@ -40,7 +40,7 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; const SCHEMA = { @@ -101,7 +101,7 @@ function makeStoreEngine() { rows.delete(id); return { deleted: 1 }; }); - const findOne = vi.fn(async (_object: string, options?: any) => rows.get(options?.where?.id) ?? null); + const findOne = vi.fn(async (_object: string, options?: any) => { assertEngineFindOnePredicate(_object, options); return rows.get(options?.where?.id) ?? null; }); const engine: any = { registry: { getObject: (n: string) => (n === 'showcase_private_note' ? SCHEMA : undefined) }, diff --git a/packages/metadata-protocol/src/protocol.batch-row-conformance.test.ts b/packages/metadata-protocol/src/protocol.batch-row-conformance.test.ts index ae3ffd98853..9ac2db42976 100644 --- a/packages/metadata-protocol/src/protocol.batch-row-conformance.test.ts +++ b/packages/metadata-protocol/src/protocol.batch-row-conformance.test.ts @@ -27,7 +27,7 @@ import { describe, it, expect, vi } from 'vitest'; import { BatchOperationResultSchema, BatchUpdateResponseSchema } from '@objectstack/spec/api'; import { ObjectStackProtocolImplementation } from './protocol.js'; -import { assertEngineUpdateDispatch, assertEngineDeleteDispatch } from '@objectstack/metadata-core'; +import { assertEngineUpdateDispatch, assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; const SCHEMA = { name: 'invoice', fields: { title: { name: 'title', type: 'text' } } }; @@ -74,7 +74,7 @@ function makeStoreEngine() { rows.delete(id); return { deleted: 1 }; }), - findOne: vi.fn(async (_object: string, options?: any) => rows.get(options?.where?.id)), + findOne: vi.fn(async (_object: string, options?: any) => { assertEngineFindOnePredicate(_object, options); return rows.get(options?.where?.id); }), getDefaultDriverName: () => 'default', getDriverByName: () => ({ beginTransaction: async () => handle }), transaction: vi.fn(async (callback: (ctx: any) => Promise, baseContext?: any) => { diff --git a/packages/metadata-protocol/src/protocol.batch-row-driver-text.test.ts b/packages/metadata-protocol/src/protocol.batch-row-driver-text.test.ts index d95933ae7d7..7de21344d35 100644 --- a/packages/metadata-protocol/src/protocol.batch-row-driver-text.test.ts +++ b/packages/metadata-protocol/src/protocol.batch-row-driver-text.test.ts @@ -66,7 +66,7 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { resolveThrownHttpError, validationFailureDetails } from '@objectstack/types'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -161,7 +161,7 @@ function makeEngine(throwOn: (verb: string, id: unknown) => unknown | undefined) const engine: any = { registry: { getObject: (n: string) => (n === 'leave_request' ? SCHEMA : undefined) }, - findOne: vi.fn(async (_o: string, opts?: any) => rows.get(opts?.where?.id) ?? null), + findOne: vi.fn(async (_o: string, opts?: any) => { assertEngineFindOnePredicate(_o, opts); return rows.get(opts?.where?.id) ?? null; }), insert: vi.fn(async (_o: string, data: any) => { const boom = throwOn('insert', data?.id); if (boom) throw boom; diff --git a/packages/metadata-protocol/src/protocol.batch-row-http-status.test.ts b/packages/metadata-protocol/src/protocol.batch-row-http-status.test.ts index 2cca99bde01..37f5cd79f3c 100644 --- a/packages/metadata-protocol/src/protocol.batch-row-http-status.test.ts +++ b/packages/metadata-protocol/src/protocol.batch-row-http-status.test.ts @@ -57,7 +57,7 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { resolveThrownHttpError } from '@objectstack/types'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -163,7 +163,7 @@ function makeEngine(throwOn: (verb: string, id: unknown) => unknown | undefined) const engine: any = { registry: { getObject: (n: string) => (n === 'leave_request' ? SCHEMA : undefined) }, - findOne: vi.fn(async (_o: string, opts?: any) => rows.get(opts?.where?.id) ?? null), + findOne: vi.fn(async (_o: string, opts?: any) => { assertEngineFindOnePredicate(_o, opts); return rows.get(opts?.where?.id) ?? null; }), insert: vi.fn(async (_o: string, data: any) => { const boom = throwOn('insert', data?.id); if (boom) throw boom; diff --git a/packages/metadata-protocol/src/protocol.batch-verb-driver-code.test.ts b/packages/metadata-protocol/src/protocol.batch-verb-driver-code.test.ts index 3dca35b01c6..0fb2299dea2 100644 --- a/packages/metadata-protocol/src/protocol.batch-verb-driver-code.test.ts +++ b/packages/metadata-protocol/src/protocol.batch-verb-driver-code.test.ts @@ -96,7 +96,7 @@ import { describe, expect, it, vi } from 'vitest'; // [#5619] The producer's OWN write-verb dispatch decisions (#4550 delete / // #5480 update), from `@objectstack/metadata-core` — never `@objectstack/objectql`, // which depends on THIS package and would close a cycle. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; // The closed union itself. Asserting membership against the SCHEMA rather than // against a literal is what makes section 1 a contract test: whatever lands on // the wire has to parse, whoever changes the catalog next. @@ -201,6 +201,7 @@ function makeKernel(opts: { return Array.from(rows.values()).filter((r) => match(r, o?.where ?? {})); }, async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); boom('findOne', table); if (table !== 'sys_metadata') return null; for (const r of rows.values()) if (match(r, o?.where ?? {})) return r; diff --git a/packages/metadata-protocol/src/protocol.batch-verb-driver-text.test.ts b/packages/metadata-protocol/src/protocol.batch-verb-driver-text.test.ts index 75f69cd8e5c..fea7800e1f9 100644 --- a/packages/metadata-protocol/src/protocol.batch-verb-driver-text.test.ts +++ b/packages/metadata-protocol/src/protocol.batch-verb-driver-text.test.ts @@ -94,7 +94,7 @@ import { describe, expect, it, vi } from 'vitest'; // [#5619] The producer's OWN write-verb dispatch decisions (#4550 delete / // #5480 update). From `@objectstack/metadata-core`, never `@objectstack/objectql` // — objectql depends on THIS package, so that import would close a cycle. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; // --------------------------------------------------------------------------- @@ -188,6 +188,7 @@ function makeKernel(opts: { return Array.from(rows.values()).filter((r) => match(r, o?.where ?? {})); }, async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); boom('findOne', table); if (table !== 'sys_metadata') return null; for (const r of rows.values()) if (match(r, o?.where ?? {})) return r; diff --git a/packages/metadata-protocol/src/protocol.bulk-record-not-found.test.ts b/packages/metadata-protocol/src/protocol.bulk-record-not-found.test.ts index 777e348503a..163750fd710 100644 --- a/packages/metadata-protocol/src/protocol.bulk-record-not-found.test.ts +++ b/packages/metadata-protocol/src/protocol.bulk-record-not-found.test.ts @@ -32,7 +32,7 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; const SCHEMA = { @@ -86,7 +86,7 @@ function makeStoreEngine() { rows.delete(id); return { deleted: 1 }; }); - const findOne = vi.fn(async (_object: string, options?: any) => rows.get(options?.where?.id) ?? null); + const findOne = vi.fn(async (_object: string, options?: any) => { assertEngineFindOnePredicate(_object, options); return rows.get(options?.where?.id) ?? null; }); const engine: any = { registry: { getObject: (n: string) => (n === 'showcase_task' ? SCHEMA : undefined) }, diff --git a/packages/metadata-protocol/src/protocol.capability-write-door.test.ts b/packages/metadata-protocol/src/protocol.capability-write-door.test.ts index 0f53e2c22aa..c540b6af36e 100644 --- a/packages/metadata-protocol/src/protocol.capability-write-door.test.ts +++ b/packages/metadata-protocol/src/protocol.capability-write-door.test.ts @@ -92,7 +92,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; // #5480 update). Imported from `@objectstack/metadata-core`, never from // `@objectstack/objectql`: objectql DEPENDS ON this package, so that import // would close a dependency cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -112,6 +112,7 @@ function makeStubEngine(registeredTypes: string[] = []) { `${w.type}|${w.name}|${w.organization_id ?? '__env__'}|${w.state ?? 'active'}`; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); for (const row of rows.values()) { if (opts.where.type !== undefined && row.type !== opts.where.type) continue; if (opts.where.name !== undefined && row.name !== opts.where.name) continue; diff --git a/packages/metadata-protocol/src/protocol.code-only-types.test.ts b/packages/metadata-protocol/src/protocol.code-only-types.test.ts index 3f4e1add61e..34b6816293f 100644 --- a/packages/metadata-protocol/src/protocol.code-only-types.test.ts +++ b/packages/metadata-protocol/src/protocol.code-only-types.test.ts @@ -36,7 +36,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; // would close a dependency cycle turbo rejects outright — which is why all 26 // of this package's (file, verb) pairs sat in the gate's DEBT ledger until // #5619 sank the two predicates into a package both sides already depend on. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; import { resetEnvWritableMetadataTypes } from './sys-metadata-repository.js'; @@ -168,6 +168,7 @@ function makeStubEngine(artifacts: Array<{ type: string; name: string }> = []) { const writes: Array<{ op: 'insert' | 'update' | 'delete'; table: string }> = []; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); for (const row of rows.values()) { if (opts.where.type !== undefined && row.type !== opts.where.type) continue; if (opts.where.name !== undefined && row.name !== opts.where.name) continue; diff --git a/packages/metadata-protocol/src/protocol.container-issue-descent.test.ts b/packages/metadata-protocol/src/protocol.container-issue-descent.test.ts index 048ba5fdaf7..f20f4b65632 100644 --- a/packages/metadata-protocol/src/protocol.container-issue-descent.test.ts +++ b/packages/metadata-protocol/src/protocol.container-issue-descent.test.ts @@ -55,7 +55,7 @@ import { z } from 'zod'; // [#5619] The producer's OWN write-verb dispatch decisions, so the fake engine // cannot accept a call ObjectQL would refuse. From `@objectstack/metadata-core` // and not `@objectstack/objectql`, which depends on this package. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; import { getMetadataTypeSchema } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation, zodIssuesToMetadataIssues } from './protocol.js'; @@ -76,7 +76,8 @@ function makeProtocol() { const rows = new Map(); let nextId = 0; const engine: any = { - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async find() { return []; }, async insert(table: string, data: Record) { if (table === 'sys_metadata_audit') return { id: 'audit_skip' }; diff --git a/packages/metadata-protocol/src/protocol.dashboard-dataset-publish-gate.test.ts b/packages/metadata-protocol/src/protocol.dashboard-dataset-publish-gate.test.ts index 506a00e9b6e..0fbe201a80d 100644 --- a/packages/metadata-protocol/src/protocol.dashboard-dataset-publish-gate.test.ts +++ b/packages/metadata-protocol/src/protocol.dashboard-dataset-publish-gate.test.ts @@ -44,7 +44,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; // Imported from `@objectstack/metadata-core` and not from // `@objectstack/objectql`: objectql DEPENDS ON this package, so that import // would close a dependency cycle turbo rejects outright (#5619). -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; // ───────────────────────────────────────────────────────────────────────────── @@ -129,6 +129,7 @@ function makeStubEngine() { }; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return findRow(opts.where)?.row ?? null; }, async find(_t: string, opts: { where: Record }) { diff --git a/packages/metadata-protocol/src/protocol.delete-object-registry-unregister.test.ts b/packages/metadata-protocol/src/protocol.delete-object-registry-unregister.test.ts index 3301e632c6e..301a34de629 100644 --- a/packages/metadata-protocol/src/protocol.delete-object-registry-unregister.test.ts +++ b/packages/metadata-protocol/src/protocol.delete-object-registry-unregister.test.ts @@ -36,7 +36,7 @@ import { describe, expect, it, vi } from 'vitest'; // #5480 update). Imported from `@objectstack/metadata-core`, never from // `@objectstack/objectql`: objectql DEPENDS ON this package, so that import // would close a dependency cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -129,6 +129,7 @@ function makeHarness(opts: { const engine: any = { async findOne(table: string, query: { where?: Record } = {}) { + assertEngineFindOnePredicate(table, query); if (table !== 'sys_metadata') return null; return rows.find((r) => matches(r, query.where)) ?? null; }, diff --git a/packages/metadata-protocol/src/protocol.delete-receipt-wording.test.ts b/packages/metadata-protocol/src/protocol.delete-receipt-wording.test.ts index ce95380deba..4c922f0aed5 100644 --- a/packages/metadata-protocol/src/protocol.delete-receipt-wording.test.ts +++ b/packages/metadata-protocol/src/protocol.delete-receipt-wording.test.ts @@ -46,7 +46,7 @@ import { afterEach, describe, expect, it } from 'vitest'; // #5480 update). Imported from `@objectstack/metadata-core`, never from // `@objectstack/objectql`: objectql DEPENDS ON this package, so that import // would close a dependency cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; import { resetEnvWritableMetadataTypes } from './sys-metadata-repository.js'; @@ -88,6 +88,7 @@ function makeStubEngine(opts: { const engine: any = { async findOne(table: string, query: { where?: Record } = {}) { + assertEngineFindOnePredicate(table, query); if (table !== 'sys_metadata') return null; return rows.find((r) => matches(r, query.where)) ?? null; }, diff --git a/packages/metadata-protocol/src/protocol.delete-rewrap-envelope.test.ts b/packages/metadata-protocol/src/protocol.delete-rewrap-envelope.test.ts index ee8ea711ffc..b514cd9b170 100644 --- a/packages/metadata-protocol/src/protocol.delete-rewrap-envelope.test.ts +++ b/packages/metadata-protocol/src/protocol.delete-rewrap-envelope.test.ts @@ -75,7 +75,7 @@ * cannot be tested against a harness that mocks `deleteMetaItem`. */ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ErrorCode } from '@objectstack/spec/api'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -173,6 +173,7 @@ function makeSession(opts: { const engine: any = { async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesWhere(h, o.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol.destructive-409-face-inventory.test.ts b/packages/metadata-protocol/src/protocol.destructive-409-face-inventory.test.ts index 847fea04646..ba0aecb1d20 100644 --- a/packages/metadata-protocol/src/protocol.destructive-409-face-inventory.test.ts +++ b/packages/metadata-protocol/src/protocol.destructive-409-face-inventory.test.ts @@ -145,6 +145,7 @@ import { describe, expect, it } from 'vitest'; // rows 1-3 of the inventory one measurement instead of three guesses. import { resolveThrownHttpError } from '@objectstack/types'; import { ObjectStackProtocolImplementation } from './protocol.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; // --------------------------------------------------------------------------- // Harness — the `sys_metadata`-backed kernel the #8333 batch-verb suite uses, @@ -207,6 +208,7 @@ function makeKernel(opts: { seed?: Row[] } = {}) { return Array.from(rows.values()).filter((r) => match(r, o?.where ?? {})); }, async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); if (table !== 'sys_metadata') return null; for (const r of rows.values()) if (match(r, o?.where ?? {})) return r; return null; diff --git a/packages/metadata-protocol/src/protocol.destructive-gate-reachable-types.test.ts b/packages/metadata-protocol/src/protocol.destructive-gate-reachable-types.test.ts index beb61e67e18..9564f14dc37 100644 --- a/packages/metadata-protocol/src/protocol.destructive-gate-reachable-types.test.ts +++ b/packages/metadata-protocol/src/protocol.destructive-gate-reachable-types.test.ts @@ -79,7 +79,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; // Imported from `@objectstack/metadata-core`, ⛔ never from // `@objectstack/objectql`: objectql DEPENDS ON this package, so that import // would close a dependency cycle turbo rejects outright. -import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; // Reason 1 is a claim about the AUTHORABLE SHAPE of a `field` body, so it is // asserted against the schema itself rather than restated in prose here. import { FieldSchema } from '@objectstack/spec/data'; @@ -164,6 +164,7 @@ function makeKernel(seed: Row[] = [], artifacts: Record = {}) { return Array.from(rows.values()).filter((r) => match(r, o?.where ?? {})); }, async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); if (table !== 'sys_metadata') return null; for (const r of rows.values()) if (match(r, o?.where ?? {})) return r; return null; diff --git a/packages/metadata-protocol/src/protocol.diagnostics-store-outage.test.ts b/packages/metadata-protocol/src/protocol.diagnostics-store-outage.test.ts index 5539c9f9c9c..3a32fd92988 100644 --- a/packages/metadata-protocol/src/protocol.diagnostics-store-outage.test.ts +++ b/packages/metadata-protocol/src/protocol.diagnostics-store-outage.test.ts @@ -87,6 +87,7 @@ import { describe, it, expect, vi } from 'vitest'; import { ErrorCode } from '@objectstack/spec/api'; import { DEFAULT_METADATA_TYPE_REGISTRY, getMetadataTypeSchema } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** * The set the sweep walks — derived from the same two spec symbols the @@ -112,7 +113,8 @@ function emptyRegistry(overrides: Record = {}) { /** An engine whose every read REJECTS — a metadata store the protocol cannot reach. */ function engineThatCannotBeRead(error: () => unknown) { - const reject = vi.fn(async () => { throw error(); }); + const reject = vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { + assertEngineFindOnePredicate(object, query); throw error(); }); return { registry: emptyRegistry(), find: reject, findOne: reject } as any; } @@ -231,7 +233,7 @@ describe('[#8855] the discrimination is selective, not a blanket refusal', () => }, }), find: vi.fn(async () => []), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), } as any; const p = new ObjectStackProtocolImplementation(engine); @@ -257,7 +259,7 @@ describe('[#8855] the discrimination is selective, not a blanket refusal', () => }] : [] )), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), } as any; const p = new ObjectStackProtocolImplementation(engine); @@ -275,7 +277,7 @@ describe('[#8924] a caller error the producer classified is refused loudly, neve return { registry: emptyRegistry(), find: vi.fn(async () => []), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), } as any; } @@ -339,7 +341,7 @@ describe('[#8924] a caller error the producer classified is refused loudly, neve }, }), find: vi.fn(async () => []), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), } as any; const p = new ObjectStackProtocolImplementation(engine); diff --git a/packages/metadata-protocol/src/protocol.diff-canonical-type-and-history-outage.test.ts b/packages/metadata-protocol/src/protocol.diff-canonical-type-and-history-outage.test.ts index 97b4ec4da92..f59dd0674ba 100644 --- a/packages/metadata-protocol/src/protocol.diff-canonical-type-and-history-outage.test.ts +++ b/packages/metadata-protocol/src/protocol.diff-canonical-type-and-history-outage.test.ts @@ -38,7 +38,7 @@ * the signal to re-pick the fixture, not to delete the assertion. */ import { describe, expect, it } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, hashSpec } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, hashSpec, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { PLURAL_TO_SINGULAR } from '@objectstack/spec/shared'; import { ObjectStackProtocolImplementation } from './index.js'; @@ -109,6 +109,7 @@ function makeStubEngine(opts: { historyError?: () => Error } = {}) { return (tables[table] ?? []).filter((r) => matches(r, o.where)); }, async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); return (tables[table] ?? []).find((r) => matches(r, o.where)) ?? null; }, async insert() { return { id: 'stub' }; }, diff --git a/packages/metadata-protocol/src/protocol.diff-credential-redaction.test.ts b/packages/metadata-protocol/src/protocol.diff-credential-redaction.test.ts index 031ec986fdf..2fe850c28b5 100644 --- a/packages/metadata-protocol/src/protocol.diff-credential-redaction.test.ts +++ b/packages/metadata-protocol/src/protocol.diff-credential-redaction.test.ts @@ -39,7 +39,7 @@ * cannot distinguish (a diff that emitted no values at all would pass it). */ import { afterEach, describe, expect, it } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, hashSpec } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, hashSpec, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { getMetadataTypeRedactor, registerMetadataTypeRedactor } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './index.js'; @@ -120,6 +120,7 @@ function makeStubEngine() { return (tables[table] ?? []).filter((r) => matches(r, opts.where)); }, async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); return (tables[table] ?? []).find((r) => matches(r, opts.where)) ?? null; }, async insert() { return { id: 'stub' }; }, diff --git a/packages/metadata-protocol/src/protocol.diff-dead-history-read.test.ts b/packages/metadata-protocol/src/protocol.diff-dead-history-read.test.ts index f980fd55b50..1d82ef6dec0 100644 --- a/packages/metadata-protocol/src/protocol.diff-dead-history-read.test.ts +++ b/packages/metadata-protocol/src/protocol.diff-dead-history-read.test.ts @@ -27,7 +27,7 @@ * re-pick the fixture from the registry, not to delete the assertion. */ import { describe, expect, it } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, hashSpec } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, hashSpec, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './index.js'; /** Takes `historyMetaItem`'s early return — neither flag set in the registry. */ @@ -82,6 +82,7 @@ function makeStubEngine(opts: { throwOnHistory?: boolean } = {}) { return (tables[table] ?? []).filter((r) => matches(r, o.where)); }, async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); return (tables[table] ?? []).find((r) => matches(r, o.where)) ?? null; }, async insert() { return { id: 'stub' }; }, diff --git a/packages/metadata-protocol/src/protocol.driver-text-disclosure.test.ts b/packages/metadata-protocol/src/protocol.driver-text-disclosure.test.ts index 0c823ee32b0..c9611ded543 100644 --- a/packages/metadata-protocol/src/protocol.driver-text-disclosure.test.ts +++ b/packages/metadata-protocol/src/protocol.driver-text-disclosure.test.ts @@ -94,7 +94,7 @@ import { describe, expect, it } from 'vitest'; // [#5619] The producer's OWN write-verb dispatch decisions (#4550 delete / // #5480 update). From `@objectstack/metadata-core`, never `@objectstack/objectql` // — objectql depends on THIS package, so that import would close a cycle. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { looksLikeInternalErrorLeak } from '@objectstack/types'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -217,6 +217,7 @@ function makeKernel(opts: { return Array.from(rows.values()); }, async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); boom('findOne'); if (table !== 'sys_metadata') return null; for (const row of rows.values()) { diff --git a/packages/metadata-protocol/src/protocol.dropped-fields.bulk.test.ts b/packages/metadata-protocol/src/protocol.dropped-fields.bulk.test.ts index d5b260c1d6b..38cab925c88 100644 --- a/packages/metadata-protocol/src/protocol.dropped-fields.bulk.test.ts +++ b/packages/metadata-protocol/src/protocol.dropped-fields.bulk.test.ts @@ -12,7 +12,7 @@ // response has no per-row slot; the insert strip is schema-uniform). import { describe, it, expect, vi } from 'vitest'; -import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; const SCHEMA = { @@ -38,7 +38,7 @@ describe('updateManyData — per-row droppedFields + context threading (#3455)', // fixture pretends to update — existence must mean one thing in a harness. // (It answered a flat `null` while nothing called it; a row that does not // exist is now correctly refused before `engine.update`.) - const findOne = vi.fn(async (_object: string, options?: any) => ({ id: options?.where?.id, title: 'stored' })); + const findOne = vi.fn(async (_object: string, options?: any) => { assertEngineFindOnePredicate(_object, options); return ({ id: options?.where?.id, title: 'stored' }); }); const engine = { registry: { getObject: () => SCHEMA }, update, findOne }; const p = new ObjectStackProtocolImplementation(engine as any); @@ -187,7 +187,7 @@ describe('batchData — per-row droppedFields + context threading (#3455)', () = }); // [#5088] See the updateManyData fixture above: `findOne` is now the // existence probe in front of the write, so it must answer for `rec-1`. - const findOne = vi.fn(async (_object: string, options?: any) => ({ id: options?.where?.id })); + const findOne = vi.fn(async (_object: string, options?: any) => { assertEngineFindOnePredicate(_object, options); return ({ id: options?.where?.id }); }); const engine = { registry: { getObject: () => SCHEMA }, update, insert: vi.fn(), findOne }; const p = new ObjectStackProtocolImplementation(engine as any); diff --git a/packages/metadata-protocol/src/protocol.dropped-fields.test.ts b/packages/metadata-protocol/src/protocol.dropped-fields.test.ts index 1c8422a01e8..0e451917c86 100644 --- a/packages/metadata-protocol/src/protocol.dropped-fields.test.ts +++ b/packages/metadata-protocol/src/protocol.dropped-fields.test.ts @@ -14,7 +14,7 @@ import { describe, it, expect, vi } from 'vitest'; import { ObjectStackProtocolImplementation } from './protocol.js'; -import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; const SCHEMA = { name: 'approval_case', @@ -38,7 +38,7 @@ describe('updateData — forwards engine write strips as droppedFields (#3431)', // PATCH of an id that names no row is now a 404 rather than a 200 with a // null record. These fixtures are about the strip channel, not about // missing records, so they describe an engine that has the row. - findOne: vi.fn(async () => ({ id: 'rec-1' })), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return ({ id: 'rec-1' }); }), }; const p = new ObjectStackProtocolImplementation(engine as any); const res: any = await p.updateData({ @@ -63,7 +63,7 @@ describe('updateData — forwards engine write strips as droppedFields (#3431)', options?.onFieldsDropped?.({ object, fields: ['approval_status'], reason: 'readonly' }); return { id: 'rec-1' }; }), - findOne: vi.fn(async () => ({ id: 'rec-1' })), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return ({ id: 'rec-1' }); }), }; const p = new ObjectStackProtocolImplementation(engine as any); const res: any = await p.updateData({ object: 'approval_case', id: 'rec-1', data: {} }); @@ -80,7 +80,7 @@ describe('updateData — forwards engine write strips as droppedFields (#3431)', assertEngineUpdateDispatch(data, options); return { id: 'rec-1', ...data }; }), - findOne: vi.fn(async () => ({ id: 'rec-1' })), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return ({ id: 'rec-1' }); }), }; const p = new ObjectStackProtocolImplementation(engine as any); const res: any = await p.updateData({ object: 'approval_case', id: 'rec-1', data: { title: 'B' } }); diff --git a/packages/metadata-protocol/src/protocol.flow-org-override-closed.test.ts b/packages/metadata-protocol/src/protocol.flow-org-override-closed.test.ts index c4221c14bdc..c499d35dadb 100644 --- a/packages/metadata-protocol/src/protocol.flow-org-override-closed.test.ts +++ b/packages/metadata-protocol/src/protocol.flow-org-override-closed.test.ts @@ -83,7 +83,7 @@ import { describe, expect, it } from 'vitest'; // #5480 update). Imported from `@objectstack/metadata-core`, never from // `@objectstack/objectql`: objectql DEPENDS ON this package, so that import // would close a dependency cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -104,6 +104,7 @@ function makeStubEngine(artifacts: Array<{ type: string; name: string }> = []) { `${w.type}|${w.name}|${w.organization_id ?? '__env__'}|${w.state ?? 'active'}`; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); for (const row of rows.values()) { if (opts.where.type !== undefined && row.type !== opts.where.type) continue; if (opts.where.name !== undefined && row.name !== opts.where.name) continue; diff --git a/packages/metadata-protocol/src/protocol.graft-folded-form-sections.test.ts b/packages/metadata-protocol/src/protocol.graft-folded-form-sections.test.ts index 23e1a4b0370..2aa35014e0c 100644 --- a/packages/metadata-protocol/src/protocol.graft-folded-form-sections.test.ts +++ b/packages/metadata-protocol/src/protocol.graft-folded-form-sections.test.ts @@ -32,7 +32,7 @@ import { describe, expect, it } from 'vitest'; import { ViewMetadataSchema } from '@objectstack/spec/ui'; import { assertEngineDeleteDispatch, - assertEngineUpdateDispatch, + assertEngineUpdateDispatch, assertEngineFindOnePredicate, } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation, graftFoldedFormSections } from './protocol.js'; @@ -72,6 +72,7 @@ function makeProtocol() { }; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return findRow(opts.where)?.row ?? null; }, async find(_t: string, opts: { where: Record }) { diff --git a/packages/metadata-protocol/src/protocol.hydrate-overlay-canonical-type.test.ts b/packages/metadata-protocol/src/protocol.hydrate-overlay-canonical-type.test.ts index 237349cd4df..3b5cb2b1d84 100644 --- a/packages/metadata-protocol/src/protocol.hydrate-overlay-canonical-type.test.ts +++ b/packages/metadata-protocol/src/protocol.hydrate-overlay-canonical-type.test.ts @@ -116,6 +116,7 @@ import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { PLURAL_TO_SINGULAR, canonicalMetaUrlType } from '@objectstack/spec/shared'; import { ObjectStackProtocolImplementation } from './protocol.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; interface StoredRow { id: string; @@ -142,7 +143,8 @@ function makeUnscopedProtocol(rows: StoredRow[]) { return (r as unknown as Record)[k] === v; })); }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, // ⛔ No `update` / `delete` / `insert` on this double, deliberately. // Both paths under test are READ-then-register — `loadMetaFromDb` // issues `find` only, and the direct helper calls touch nothing but diff --git a/packages/metadata-protocol/src/protocol.i18n-bundle-list-merge.test.ts b/packages/metadata-protocol/src/protocol.i18n-bundle-list-merge.test.ts index 62614bca8ff..8ff5830e78b 100644 --- a/packages/metadata-protocol/src/protocol.i18n-bundle-list-merge.test.ts +++ b/packages/metadata-protocol/src/protocol.i18n-bundle-list-merge.test.ts @@ -50,7 +50,7 @@ import { describe, expect, it } from 'vitest'; // [#7774] The identity table's home is `@objectstack/metadata-core`, not the // `SchemaRegistry` that first needed it: `@objectstack/objectql` depends on // THIS package, so importing the registry's copy would close a cycle. -import { ITEM_KEY_DISCRIMINATORS } from '@objectstack/metadata-core'; +import { ITEM_KEY_DISCRIMINATORS, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; const PKG = 'com.acme.crm'; @@ -124,7 +124,8 @@ function makeEngine(opts: { items?: unknown[]; rows?: Row[] } = {}) { return true; }); }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, } as any, }; } diff --git a/packages/metadata-protocol/src/protocol.injected-system-columns.test.ts b/packages/metadata-protocol/src/protocol.injected-system-columns.test.ts index 0247ddfbef0..d3196fffc95 100644 --- a/packages/metadata-protocol/src/protocol.injected-system-columns.test.ts +++ b/packages/metadata-protocol/src/protocol.injected-system-columns.test.ts @@ -45,7 +45,7 @@ import { describe, expect, it } from 'vitest'; // below cannot accept a call ObjectQL refuses. From `@objectstack/metadata-core` // and not `@objectstack/objectql`: objectql DEPENDS ON this package, so that // import would close a cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { AUDIT_PROVENANCE_FIELDS } from '@objectstack/spec/data'; import { ObjectStackProtocolImplementation } from './index.js'; @@ -82,6 +82,7 @@ function makeStubEngine() { }; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return findRow(opts.where)?.row ?? null; }, async find(_t: string, opts: { where: Record }) { diff --git a/packages/metadata-protocol/src/protocol.invalid-metadata-422-face-inventory.test.ts b/packages/metadata-protocol/src/protocol.invalid-metadata-422-face-inventory.test.ts index 93e4845aafc..db63dec3aa4 100644 --- a/packages/metadata-protocol/src/protocol.invalid-metadata-422-face-inventory.test.ts +++ b/packages/metadata-protocol/src/protocol.invalid-metadata-422-face-inventory.test.ts @@ -82,7 +82,7 @@ * needs no rebuild, and its RED result rules out a stale-artifact false green. */ import { describe, expect, it } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -101,7 +101,8 @@ function makeProtocol() { const rows = new Map(); let nextId = 0; const engine: any = { - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async find() { return []; }, async insert(table: string, data: Record) { if (table === 'sys_metadata_audit') return { id: 'audit_skip' }; diff --git a/packages/metadata-protocol/src/protocol.item-name-grammar.test.ts b/packages/metadata-protocol/src/protocol.item-name-grammar.test.ts index ddeaff9be6a..accddc94802 100644 --- a/packages/metadata-protocol/src/protocol.item-name-grammar.test.ts +++ b/packages/metadata-protocol/src/protocol.item-name-grammar.test.ts @@ -41,7 +41,7 @@ import { describe, expect, it } from 'vitest'; // [#5619] The producer's OWN write-verb dispatch decisions, so the fake engine // below cannot accept a call ObjectQL itself refuses. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -76,6 +76,7 @@ function makeProtocol(seedRows: Array> = []) { const deletes: Array | undefined> = []; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); for (const row of rows.values()) { if (opts.where.type !== undefined && row.type !== opts.where.type) continue; if (opts.where.name !== undefined && row.name !== opts.where.name) continue; diff --git a/packages/metadata-protocol/src/protocol.legacy-overlay-delete.test.ts b/packages/metadata-protocol/src/protocol.legacy-overlay-delete.test.ts index 45ec7cd6410..8a0447579b2 100644 --- a/packages/metadata-protocol/src/protocol.legacy-overlay-delete.test.ts +++ b/packages/metadata-protocol/src/protocol.legacy-overlay-delete.test.ts @@ -82,7 +82,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; // #5480 update), so the fake engine below cannot accept a call ObjectQL // refuses. Imported from `@objectstack/metadata-core` and not from // `@objectstack/objectql`, which depends on this package. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; import { SysMetadataRepository, resetEnvWritableMetadataTypes } from './sys-metadata-repository.js'; @@ -174,6 +174,7 @@ function makeSession(opts: { const engine: any = { async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesWhere(h, o.where)) ?? null; } @@ -590,6 +591,7 @@ describe('#6960 — SysMetadataRepository: the delete verb diverges, the put ver const historyRows: Array> = []; const engine: any = { async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesWhere(h, o.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol.lifecycle-audit-rows.test.ts b/packages/metadata-protocol/src/protocol.lifecycle-audit-rows.test.ts index 51dc9eb93a1..fdcdcbf5510 100644 --- a/packages/metadata-protocol/src/protocol.lifecycle-audit-rows.test.ts +++ b/packages/metadata-protocol/src/protocol.lifecycle-audit-rows.test.ts @@ -92,7 +92,7 @@ import { describe, expect, it, vi } from 'vitest'; // `@objectstack/metadata-core` and NOT from `@objectstack/objectql`: objectql // depends on this package, so that import would close a dependency cycle turbo // rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -186,6 +186,7 @@ function makeStubEngine(opts: { failAudit?: boolean } = {}): Harness { const engine: any = { async findOne(table: string, opts2: { where: Record }) { + assertEngineFindOnePredicate(table, opts2); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts2.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol.lock-gate-canonical-type.test.ts b/packages/metadata-protocol/src/protocol.lock-gate-canonical-type.test.ts index 8e058b4cde4..365deb24833 100644 --- a/packages/metadata-protocol/src/protocol.lock-gate-canonical-type.test.ts +++ b/packages/metadata-protocol/src/protocol.lock-gate-canonical-type.test.ts @@ -76,6 +76,7 @@ import { describe, it, expect, vi } from 'vitest'; import { ObjectStackProtocolImplementation } from './protocol.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * An overlay row exactly as `SysMetadataRepository` stores it: keyed by the @@ -127,6 +128,7 @@ function harness(opts: { getObjectOwner: () => undefined, }, findOne: vi.fn(async (object: string, query: any) => { + assertEngineFindOnePredicate(object, query); if (object !== 'sys_metadata') return null; const where = (query?.where ?? {}) as Record; overlayQueries.push(where); diff --git a/packages/metadata-protocol/src/protocol.lock-gate-fail-closed.test.ts b/packages/metadata-protocol/src/protocol.lock-gate-fail-closed.test.ts index 10b41bc8103..3becb9c4db3 100644 --- a/packages/metadata-protocol/src/protocol.lock-gate-fail-closed.test.ts +++ b/packages/metadata-protocol/src/protocol.lock-gate-fail-closed.test.ts @@ -88,7 +88,7 @@ import { describe, it, expect, vi } from 'vitest'; import { ErrorCode } from '@objectstack/spec/api'; import { ObjectStackProtocolImplementation } from './protocol.js'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** A registry holding only what the test explicitly puts in it. */ function registry(items: Record = {}) { @@ -161,6 +161,7 @@ function engineWithTransientLockReadFault(opts: { const engine: any = { registry: registry(opts.registryItems ?? {}), findOne: vi.fn(async (object: string, query: any) => { + assertEngineFindOnePredicate(object, query); if (object !== 'sys_metadata') { calls.push(`findOne:${object}`); return null; diff --git a/packages/metadata-protocol/src/protocol.many-data-atomic.test.ts b/packages/metadata-protocol/src/protocol.many-data-atomic.test.ts index 489eecbe9c3..55a83103bff 100644 --- a/packages/metadata-protocol/src/protocol.many-data-atomic.test.ts +++ b/packages/metadata-protocol/src/protocol.many-data-atomic.test.ts @@ -21,7 +21,7 @@ // test reads the store back afterwards. import { describe, it, expect, vi } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; const SCHEMA = { name: 'invoice', fields: { title: { name: 'title', type: 'text' } } }; @@ -70,7 +70,7 @@ function makeStoreEngine(opts: { driverCanTransact?: boolean; hasTransaction?: b registry: { getObject: (n: string) => (n === 'invoice' ? SCHEMA : undefined) }, update, delete: del, - findOne: vi.fn(async (_object: string, options?: any) => rows.get(options?.where?.id)), + findOne: vi.fn(async (_object: string, options?: any) => { assertEngineFindOnePredicate(_object, options); return rows.get(options?.where?.id); }), getDefaultDriverName: () => 'default', getDriverByName: () => (driverCanTransact ? { beginTransaction: async () => handle } : {}), }; diff --git a/packages/metadata-protocol/src/protocol.meta-list-runtime-baseline-dedup.test.ts b/packages/metadata-protocol/src/protocol.meta-list-runtime-baseline-dedup.test.ts index 4c6a33927ef..ddd6e53dd90 100644 --- a/packages/metadata-protocol/src/protocol.meta-list-runtime-baseline-dedup.test.ts +++ b/packages/metadata-protocol/src/protocol.meta-list-runtime-baseline-dedup.test.ts @@ -60,6 +60,7 @@ */ import { describe, expect, it } from 'vitest'; import { ObjectStackProtocolImplementation } from './protocol.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; const PKG = 'com.acme.showcase'; const OTHER_PKG = 'com.acme.partner'; @@ -118,7 +119,8 @@ function makeEngine(opts: { items?: any[]; rows?: Row[] } = {}) { return true; }); }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, } as any; } diff --git a/packages/metadata-protocol/src/protocol.meta-types-mint-door-agreement.test.ts b/packages/metadata-protocol/src/protocol.meta-types-mint-door-agreement.test.ts index a087ed74adb..2b47d203ae6 100644 --- a/packages/metadata-protocol/src/protocol.meta-types-mint-door-agreement.test.ts +++ b/packages/metadata-protocol/src/protocol.meta-types-mint-door-agreement.test.ts @@ -57,7 +57,7 @@ import { describe, expect, it } from 'vitest'; // [#5619] The producer's OWN write-verb dispatch decisions, so the fake engine // below cannot accept a call ObjectQL itself refuses. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; /** @@ -76,7 +76,8 @@ function makeProtocol() { const rows = new Map>(); let nextId = 0; const engine: any = { - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async find() { return []; }, async insert(table: string, data: Record) { if (table !== 'sys_metadata') return { id: 'side_effect_skip' }; diff --git a/packages/metadata-protocol/src/protocol.metadata-redaction.test.ts b/packages/metadata-protocol/src/protocol.metadata-redaction.test.ts index 37be24c50e9..8ae065a04ca 100644 --- a/packages/metadata-protocol/src/protocol.metadata-redaction.test.ts +++ b/packages/metadata-protocol/src/protocol.metadata-redaction.test.ts @@ -37,7 +37,7 @@ * destroy the #8081 item-3 operator inventory. */ import { afterEach, describe, expect, it } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, hashSpec } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, hashSpec, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { getMetadataTypeRedactor, getMetadataTypeSchema, @@ -84,6 +84,7 @@ function makeStubEngine() { }; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return findRow(opts.where)?.row ?? null; }, async find(_t: string, opts: { where: Record }) { diff --git a/packages/metadata-protocol/src/protocol.metadata-store-outage.test.ts b/packages/metadata-protocol/src/protocol.metadata-store-outage.test.ts index 31c2a3520fb..b8f59dcebfd 100644 --- a/packages/metadata-protocol/src/protocol.metadata-store-outage.test.ts +++ b/packages/metadata-protocol/src/protocol.metadata-store-outage.test.ts @@ -66,6 +66,7 @@ import { describe, it, expect, vi } from 'vitest'; import { ErrorCode } from '@objectstack/spec/api'; import { ObjectStackProtocolImplementation } from './protocol.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** A registry with nothing in it — the overlay read is the only source. */ function emptyRegistry(items: Record = {}) { @@ -84,7 +85,8 @@ function emptyRegistry(items: Record = {}) { * store the protocol cannot reach. */ function engineThatCannotBeRead(error: () => unknown, registryItems: Record = {}) { - const reject = vi.fn(async () => { throw error(); }); + const reject = vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { + assertEngineFindOnePredicate(object, query); throw error(); }); return { registry: emptyRegistry(registryItems), find: reject, @@ -97,7 +99,7 @@ function engineWithRows(rows: any[] = [], registryItems: Record = { return { registry: emptyRegistry(registryItems), find: vi.fn(async () => rows), - findOne: vi.fn(async () => rows[0] ?? null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return rows[0] ?? null; }), } as any; } diff --git a/packages/metadata-protocol/src/protocol.migrate-stored-noncanonical-type.test.ts b/packages/metadata-protocol/src/protocol.migrate-stored-noncanonical-type.test.ts index d57610d1e84..811116eb436 100644 --- a/packages/metadata-protocol/src/protocol.migrate-stored-noncanonical-type.test.ts +++ b/packages/metadata-protocol/src/protocol.migrate-stored-noncanonical-type.test.ts @@ -53,7 +53,7 @@ import { describe, expect, it } from 'vitest'; // cannot accept a call the real ObjectQL engine refuses (#4550 delete / #5480 // update). Imported from `@objectstack/metadata-core` rather than // `@objectstack/objectql`, which depends on this package. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; import { formatStoredMigrationReport, storedMigrationClean } from './stored-migration.js'; @@ -122,6 +122,7 @@ function makeStubEngine(seedRows: SeedRow[]) { return rowsOf(t).filter((r) => matches(r, opts?.where ?? {})); }, async findOne(t: string, opts?: { where?: Record }) { + assertEngineFindOnePredicate(t, opts); return rowsOf(t).find((r) => matches(r, opts?.where ?? {})) ?? null; }, async insert(t: string, row: Record) { diff --git a/packages/metadata-protocol/src/protocol.object-registry-write-through-spelling.test.ts b/packages/metadata-protocol/src/protocol.object-registry-write-through-spelling.test.ts index d1b295249ea..eaaaab3991b 100644 --- a/packages/metadata-protocol/src/protocol.object-registry-write-through-spelling.test.ts +++ b/packages/metadata-protocol/src/protocol.object-registry-write-through-spelling.test.ts @@ -134,7 +134,7 @@ import { PLURAL_TO_SINGULAR, canonicalMetaUrlType } from '@objectstack/spec/shar // `@objectstack/metadata-core` and NOT from `@objectstack/objectql`: objectql // depends on this package, so that import would close a dependency cycle turbo // rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -229,6 +229,7 @@ function makeStubEngine() { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_commit') return commit; if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; diff --git a/packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit-live-registry.test.ts b/packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit-live-registry.test.ts index 2187045ebf7..1ea4a008836 100644 --- a/packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit-live-registry.test.ts +++ b/packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit-live-registry.test.ts @@ -67,7 +67,7 @@ import { describe, expect, it, vi } from 'vitest'; // [#5619] The producer's OWN write-verb dispatch decisions (#4550 delete / // #5480 update). From `@objectstack/metadata-core`, never `@objectstack/objectql` // — objectql depends on THIS package, so that import would close a cycle. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -117,7 +117,8 @@ function makeEngine( async find(_table: string, q: { where: Record }) { return rows.filter((r) => matchesWhere(r, q.where)); }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async insert() { return { id: 'x' }; }, async update(_t: string, data: Record, o?: Record) { assertEngineUpdateDispatch(data, o); diff --git a/packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit.test.ts b/packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit.test.ts index 418667eb56b..8855a901ff6 100644 --- a/packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit.test.ts +++ b/packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit.test.ts @@ -60,7 +60,7 @@ import { describe, expect, it, vi } from 'vitest'; // [#5619] The producer's OWN write-verb dispatch decisions (#4550 delete / // #5480 update). From `@objectstack/metadata-core`, never `@objectstack/objectql` // — objectql depends on THIS package, so that import would close a cycle. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -109,7 +109,8 @@ function makeEngine(rows: Row[], opts: { dropPredicates?: boolean } = {}) { if (opts.dropPredicates) return rows.filter((r) => r.state === q.where.state); return rows.filter((r) => matchesWhere(r, q.where)); }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async insert() { return { id: 'x' }; }, async update(_t: string, data: Record, o?: Record) { assertEngineUpdateDispatch(data, o); diff --git a/packages/metadata-protocol/src/protocol.org-scoped-write-refused.test.ts b/packages/metadata-protocol/src/protocol.org-scoped-write-refused.test.ts index c8c9b33fe5c..1c9f1d16e0b 100644 --- a/packages/metadata-protocol/src/protocol.org-scoped-write-refused.test.ts +++ b/packages/metadata-protocol/src/protocol.org-scoped-write-refused.test.ts @@ -73,7 +73,7 @@ import { afterEach, describe, expect, it } from 'vitest'; // #5480 update). Imported from `@objectstack/metadata-core`, never from // `@objectstack/objectql`: objectql DEPENDS ON this package, so that import // would close a dependency cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -141,6 +141,7 @@ function makeStubEngine(artifacts: Array<{ type: string; name: string }> = []) { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { return historyRows.find((h) => { const w = opts.where; diff --git a/packages/metadata-protocol/src/protocol.package-closure-gate.test.ts b/packages/metadata-protocol/src/protocol.package-closure-gate.test.ts index c219ce123ba..0ef81d25c6a 100644 --- a/packages/metadata-protocol/src/protocol.package-closure-gate.test.ts +++ b/packages/metadata-protocol/src/protocol.package-closure-gate.test.ts @@ -32,7 +32,7 @@ import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'; // The producer's OWN write-verb dispatch decisions, so the fake engine cannot // accept a call ObjectQL refuses. From `@objectstack/metadata-core`, never from // `@objectstack/objectql` — that import would close a cycle turbo rejects. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; const OWN = 'com.acme.crm'; @@ -105,6 +105,7 @@ function makeStubEngine() { }; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return findRow(opts.where)?.row ?? null; }, async find(_t: string, opts: { where: Record }) { diff --git a/packages/metadata-protocol/src/protocol.package-publish-audit-rows.test.ts b/packages/metadata-protocol/src/protocol.package-publish-audit-rows.test.ts index 810938c1ed3..24aa5020dd6 100644 --- a/packages/metadata-protocol/src/protocol.package-publish-audit-rows.test.ts +++ b/packages/metadata-protocol/src/protocol.package-publish-audit-rows.test.ts @@ -98,7 +98,7 @@ import { describe, expect, it, vi } from 'vitest'; // `@objectstack/metadata-core` and NOT from `@objectstack/objectql`: objectql // depends on this package, so that import would close a dependency cycle turbo // rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -219,6 +219,7 @@ function makeStubEngine(opts: { failAudit?: boolean } = {}): Harness { const engine: any = { async findOne(table: string, opts2: { where: Record }) { + assertEngineFindOnePredicate(table, opts2); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts2.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol.platform-schedule-org-gate.test.ts b/packages/metadata-protocol/src/protocol.platform-schedule-org-gate.test.ts index 2d001a2cac8..4d58b887f64 100644 --- a/packages/metadata-protocol/src/protocol.platform-schedule-org-gate.test.ts +++ b/packages/metadata-protocol/src/protocol.platform-schedule-org-gate.test.ts @@ -53,7 +53,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; // Imported from `@objectstack/metadata-core` and not from `@objectstack/objectql`: // objectql DEPENDS ON this package, so that import would close a dependency // cycle turbo rejects outright (#5619). -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; import { PLATFORM_SCHEDULE_CREATE_RECORD_ORG_MISSING, @@ -344,6 +344,7 @@ function makeStubEngine() { }; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return findRow(opts.where)?.row ?? null; }, async find(_t: string, opts: { where: Record }) { diff --git a/packages/metadata-protocol/src/protocol.publish-commit-capture-read-failure.test.ts b/packages/metadata-protocol/src/protocol.publish-commit-capture-read-failure.test.ts index bb2cad88ad4..d9f2f2650d2 100644 --- a/packages/metadata-protocol/src/protocol.publish-commit-capture-read-failure.test.ts +++ b/packages/metadata-protocol/src/protocol.publish-commit-capture-read-failure.test.ts @@ -59,7 +59,7 @@ import { describe, it, expect } from 'vitest'; // cannot accept a call ObjectQL refuses. From `@objectstack/metadata-core`, not // `@objectstack/objectql` — objectql depends on THIS package, so that import // would close a dependency cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -141,6 +141,7 @@ function makeStubEngine() { const engine = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata' && opts?.where?.state === 'active') { activeReads.push(opts.where); if (captureFailure !== null) { diff --git a/packages/metadata-protocol/src/protocol.publish-item-draft-org-scope.test.ts b/packages/metadata-protocol/src/protocol.publish-item-draft-org-scope.test.ts index 3a2c4d10255..53633b5341d 100644 --- a/packages/metadata-protocol/src/protocol.publish-item-draft-org-scope.test.ts +++ b/packages/metadata-protocol/src/protocol.publish-item-draft-org-scope.test.ts @@ -28,7 +28,7 @@ */ import { describe, expect, it } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; import type { MetaItemPublishedEvent } from './protocol.js'; @@ -112,6 +112,7 @@ function makeStubEngine() { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol.publish-item-rebind-announce.test.ts b/packages/metadata-protocol/src/protocol.publish-item-rebind-announce.test.ts index 75d13c52503..de8005098fe 100644 --- a/packages/metadata-protocol/src/protocol.publish-item-rebind-announce.test.ts +++ b/packages/metadata-protocol/src/protocol.publish-item-rebind-announce.test.ts @@ -27,7 +27,7 @@ */ import { describe, expect, it } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; import type { MetaItemPublishedEvent } from './protocol.js'; @@ -111,6 +111,7 @@ function makeStubEngine() { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol.publish-side-effects-canonical-type.test.ts b/packages/metadata-protocol/src/protocol.publish-side-effects-canonical-type.test.ts index 84eb40257ed..67723c395be 100644 --- a/packages/metadata-protocol/src/protocol.publish-side-effects-canonical-type.test.ts +++ b/packages/metadata-protocol/src/protocol.publish-side-effects-canonical-type.test.ts @@ -60,7 +60,7 @@ import { describe, expect, it, vi } from 'vitest'; // `@objectstack/metadata-core` and NOT from `@objectstack/objectql`: objectql // depends on this package, so that import would close a dependency cycle turbo // rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -131,6 +131,7 @@ function makeStubEngine() { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { return historyRows.find((h) => { const w = opts.where; diff --git a/packages/metadata-protocol/src/protocol.publish-stored-type-canonical.test.ts b/packages/metadata-protocol/src/protocol.publish-stored-type-canonical.test.ts index b6f1f3f806c..f4cade4dc2d 100644 --- a/packages/metadata-protocol/src/protocol.publish-stored-type-canonical.test.ts +++ b/packages/metadata-protocol/src/protocol.publish-stored-type-canonical.test.ts @@ -80,7 +80,7 @@ import { describe, expect, it } from 'vitest'; // `@objectstack/metadata-core` and NOT from `@objectstack/objectql`: objectql // depends on this package, so that import would close a dependency cycle turbo // rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -174,6 +174,7 @@ function makeStubEngine(): Harness { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol.read-decorations.test.ts b/packages/metadata-protocol/src/protocol.read-decorations.test.ts index 3a3c97d6c9b..7fac82a6f40 100644 --- a/packages/metadata-protocol/src/protocol.read-decorations.test.ts +++ b/packages/metadata-protocol/src/protocol.read-decorations.test.ts @@ -29,7 +29,7 @@ import { describe, expect, it } from 'vitest'; // would close a dependency cycle turbo rejects outright — which is why all 26 // of this package's (file, verb) pairs sat in the gate's DEBT ledger until // #5619 sank the two predicates into a package both sides already depend on. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { FlowSchema } from '@objectstack/spec/automation'; import { METADATA_READ_DECORATIONS, getMetadataTypeSchema } from '@objectstack/spec/kernel'; import { @@ -71,6 +71,7 @@ function makeStubEngine() { }; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return findRow(opts.where)?.row ?? null; }, async find(_t: string, opts: { where: Record }) { diff --git a/packages/metadata-protocol/src/protocol.read-seam-empty-accumulator.test.ts b/packages/metadata-protocol/src/protocol.read-seam-empty-accumulator.test.ts index 7198ab27538..76a1d800e93 100644 --- a/packages/metadata-protocol/src/protocol.read-seam-empty-accumulator.test.ts +++ b/packages/metadata-protocol/src/protocol.read-seam-empty-accumulator.test.ts @@ -41,6 +41,7 @@ import { describe, it, expect, vi } from 'vitest'; import { ErrorCode } from '@objectstack/spec/api'; import { ObjectStackProtocolImplementation } from './protocol.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; interface FixtureObject { name: string; @@ -113,7 +114,7 @@ describe('[#8896] searchAll — an object that could not be READ is not an objec if (object === 'lead') throw error; return [{ id: 'a1', name: 'Acme' }]; }), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), }; return { engine, readCalls }; } @@ -124,7 +125,7 @@ describe('[#8896] searchAll — an object that could not be READ is not an objec find: vi.fn(async (object: string) => ( object === 'acct' ? [{ id: 'a1', name: 'Acme' }] : [{ id: 'l1', name: 'Acme Lead' }] )), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), }; const protocol = new ObjectStackProtocolImplementation(engine as never); @@ -235,7 +236,7 @@ describe('[#11754] searchAll — a registry that cannot ENUMERATE is not a regis listItems: () => [], }, find, - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), }; const protocol = new ObjectStackProtocolImplementation(engine as never); @@ -271,7 +272,7 @@ describe('[#11754] searchAll — a registry that cannot ENUMERATE is not a regis const engine = { registry: { ...fixtureRegistry([]), getAllObjects: vi.fn(() => []) }, find: vi.fn(async () => []), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), }; const protocol = new ObjectStackProtocolImplementation(engine as never); @@ -293,7 +294,7 @@ describe('[#11754] searchAll — a registry that cannot ENUMERATE is not a regis listItems: () => [], }, find: vi.fn(async () => []), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), }; const protocol = new ObjectStackProtocolImplementation(engine as never); @@ -337,7 +338,7 @@ describe('[#8896] findReferencesToMeta — a source type that could not be READ if (failingType !== null && type === failingType) throw error; return []; }), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), }; return { engine, typeReads }; } diff --git a/packages/metadata-protocol/src/protocol.read-verb-canonical-fold.test.ts b/packages/metadata-protocol/src/protocol.read-verb-canonical-fold.test.ts index ecb230a52b7..c4c81832df7 100644 --- a/packages/metadata-protocol/src/protocol.read-verb-canonical-fold.test.ts +++ b/packages/metadata-protocol/src/protocol.read-verb-canonical-fold.test.ts @@ -62,6 +62,7 @@ import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { META_URL_TO_SINGULAR, PLURAL_TO_SINGULAR, metaUrlSpellingRefusal } from '@objectstack/spec/shared'; import { ObjectStackProtocolImplementation } from './protocol.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** Manifest-ABSENT and `allowOrgOverride: true` — history reads REAL rows for it. */ const OVERLAY_ABSENT_TYPE = 'translation'; @@ -109,6 +110,7 @@ function makeStubEngine() { return (tables[table] ?? []).filter((r) => matches(r, where)); }, async findOne(table: string, o: { where?: Record } = {}) { + assertEngineFindOnePredicate(table, o); reads.push({ table, where: o.where ?? {} }); return (tables[table] ?? []).find((r) => matches(r, o.where ?? {})) ?? null; }, diff --git a/packages/metadata-protocol/src/protocol.record-not-found.test.ts b/packages/metadata-protocol/src/protocol.record-not-found.test.ts index efd4096c6f5..9acdebb5c40 100644 --- a/packages/metadata-protocol/src/protocol.record-not-found.test.ts +++ b/packages/metadata-protocol/src/protocol.record-not-found.test.ts @@ -21,7 +21,7 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; const SCHEMA = { name: 'task', fields: { title: { name: 'title', type: 'text' } } }; @@ -33,7 +33,7 @@ const SCHEMA = { name: 'task', fields: { title: { name: 'title', type: 'text' } */ function makeProtocol(rows: Record = {}) { const store = new Map(Object.entries(rows)); - const findOne = vi.fn(async (_object: string, opts: any) => store.get(String(opts?.where?.id)) ?? null); + const findOne = vi.fn(async (_object: string, opts: any) => { assertEngineFindOnePredicate(_object, opts); return store.get(String(opts?.where?.id)) ?? null; }); const update = vi.fn(async (_object: string, data: any, opts: any) => { assertEngineUpdateDispatch(data, opts); const id = String(opts?.where?.id); diff --git a/packages/metadata-protocol/src/protocol.record-package-commit-durability.test.ts b/packages/metadata-protocol/src/protocol.record-package-commit-durability.test.ts index c1fc275bd8f..0de0b947d71 100644 --- a/packages/metadata-protocol/src/protocol.record-package-commit-durability.test.ts +++ b/packages/metadata-protocol/src/protocol.record-package-commit-durability.test.ts @@ -52,7 +52,7 @@ import { describe, it, expect, vi, afterEach } from 'vitest'; // cannot accept a call ObjectQL refuses. From `@objectstack/metadata-core`, not // `@objectstack/objectql` — objectql depends on THIS package, so that import // would close a dependency cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -126,6 +126,7 @@ function makeStubEngine() { const engine = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table !== 'sys_metadata') { return (sideTables[table] ?? []).find((r) => matchesWhere(r, opts.where)) ?? null; } diff --git a/packages/metadata-protocol/src/protocol.reference-derivation.test.ts b/packages/metadata-protocol/src/protocol.reference-derivation.test.ts index f818c112adf..22eb8b0b715 100644 --- a/packages/metadata-protocol/src/protocol.reference-derivation.test.ts +++ b/packages/metadata-protocol/src/protocol.reference-derivation.test.ts @@ -16,6 +16,7 @@ import { describe, expect, it } from 'vitest'; import { ObjectStackProtocolImplementation } from './protocol.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** * Registry-backed stub. Reference scanning reads through `getMetaItems`, which @@ -25,7 +26,8 @@ import { ObjectStackProtocolImplementation } from './protocol.js'; function protocolWith(items: Record>>) { const engine: any = { async find() { return []; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async count() { return 0; }, registry: { listItems: (type: string) => items[type] ?? [], diff --git a/packages/metadata-protocol/src/protocol.reference-target-unanswerable.test.ts b/packages/metadata-protocol/src/protocol.reference-target-unanswerable.test.ts index 8e4f633a6e9..f85b646a8fa 100644 --- a/packages/metadata-protocol/src/protocol.reference-target-unanswerable.test.ts +++ b/packages/metadata-protocol/src/protocol.reference-target-unanswerable.test.ts @@ -39,12 +39,14 @@ import { describe, expect, it } from 'vitest'; import { ObjectStackProtocolImplementation } from './protocol.js'; import { REFERENCE_SITES } from './reference-sites.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** Same registry-backed stub the sibling derivation suite uses. */ function protocolWith(items: Record>>) { const engine: any = { async find() { return []; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async count() { return 0; }, registry: { listItems: (type: string) => items[type] ?? [], diff --git a/packages/metadata-protocol/src/protocol.revert-stored-type-canonical.test.ts b/packages/metadata-protocol/src/protocol.revert-stored-type-canonical.test.ts index 3dc3bac68bc..0457d14984f 100644 --- a/packages/metadata-protocol/src/protocol.revert-stored-type-canonical.test.ts +++ b/packages/metadata-protocol/src/protocol.revert-stored-type-canonical.test.ts @@ -109,7 +109,7 @@ import { PLURAL_TO_SINGULAR, canonicalMetaUrlType } from '@objectstack/spec/shar // `@objectstack/metadata-core` and NOT from `@objectstack/objectql`: objectql // depends on this package, so that import would close a dependency cycle turbo // rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -202,6 +202,7 @@ function makeStubEngine() { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_commit') return commit; if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; diff --git a/packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts b/packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts index 83256b758c9..2ec5ee7b8cf 100644 --- a/packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts +++ b/packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts @@ -30,7 +30,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; // would close a dependency cycle turbo rejects outright — which is why all 26 // of this package's (file, verb) pairs sat in the gate's DEBT ledger until // #5619 sank the two predicates into a package both sides already depend on. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; // [#4716] The advisory-tier rule the Q2 fence test proves its body WOULD trip // — imported from the full barrel deliberately: this is a TEST, not the gate // (the gate itself may only reach the registry through `@objectstack/lint/runtime`, @@ -99,6 +99,7 @@ function makeStubEngine() { }; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return findRow(opts.where)?.row ?? null; }, async find(_t: string, opts: { where: Record }) { diff --git a/packages/metadata-protocol/src/protocol.save-flow-canonicalization.test.ts b/packages/metadata-protocol/src/protocol.save-flow-canonicalization.test.ts index d291aba810b..8dd04542874 100644 --- a/packages/metadata-protocol/src/protocol.save-flow-canonicalization.test.ts +++ b/packages/metadata-protocol/src/protocol.save-flow-canonicalization.test.ts @@ -28,7 +28,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { hashSpec, assertEngineDeleteDispatch, - assertEngineUpdateDispatch, + assertEngineUpdateDispatch, assertEngineFindOnePredicate, } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -100,6 +100,7 @@ function makeStubEngine() { }; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return findRow(opts.where)?.row ?? null; }, async find(_t: string, opts: { where: Record }) { diff --git a/packages/metadata-protocol/src/protocol.save-meta-missing-item.test.ts b/packages/metadata-protocol/src/protocol.save-meta-missing-item.test.ts index cab1e132432..fb0c4bf5433 100644 --- a/packages/metadata-protocol/src/protocol.save-meta-missing-item.test.ts +++ b/packages/metadata-protocol/src/protocol.save-meta-missing-item.test.ts @@ -51,6 +51,7 @@ import { describe, it, expect, vi } from 'vitest'; import { ObjectStackProtocolImplementation, clientFacingFailureText } from './protocol.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** * A protocol over an engine whose every verb is a tripwire: this guard is the @@ -58,7 +59,7 @@ import { ObjectStackProtocolImplementation, clientFacingFailureText } from './pr * all would mean the check had moved behind something with side effects. */ function makeProtocol() { - const findOne = vi.fn(async () => null); + const findOne = vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }); const find = vi.fn(async () => [] as unknown[]); const engine = { registry: { getObject: () => undefined }, diff --git a/packages/metadata-protocol/src/protocol.save-receipt-wording.test.ts b/packages/metadata-protocol/src/protocol.save-receipt-wording.test.ts index fbbeadfe6b7..752b7fce95e 100644 --- a/packages/metadata-protocol/src/protocol.save-receipt-wording.test.ts +++ b/packages/metadata-protocol/src/protocol.save-receipt-wording.test.ts @@ -46,7 +46,7 @@ import { afterEach, describe, expect, it } from 'vitest'; // #5480 update). Imported from `@objectstack/metadata-core`, never from // `@objectstack/objectql`: objectql DEPENDS ON this package, so that import // would close a dependency cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation } from './protocol.js'; import { resetEnvWritableMetadataTypes } from './sys-metadata-repository.js'; @@ -68,6 +68,7 @@ function makeStubEngine(artifacts: Array<{ type: string; name: string }> = []) { `${w.type}|${w.name}|${w.organization_id ?? '__env__'}|${w.state ?? 'active'}`; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); for (const row of rows.values()) { if (opts.where.type !== undefined && row.type !== opts.where.type) continue; if (opts.where.name !== undefined && row.name !== opts.where.name) continue; diff --git a/packages/metadata-protocol/src/protocol.save-union-issues.test.ts b/packages/metadata-protocol/src/protocol.save-union-issues.test.ts index ef62a454fcf..ea2d86a5447 100644 --- a/packages/metadata-protocol/src/protocol.save-union-issues.test.ts +++ b/packages/metadata-protocol/src/protocol.save-union-issues.test.ts @@ -30,7 +30,7 @@ import { describe, expect, it } from 'vitest'; // would close a dependency cycle turbo rejects outright — which is why all 26 // of this package's (file, verb) pairs sat in the gate's DEBT ledger until // #5619 sank the two predicates into a package both sides already depend on. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; import { getMetadataTypeSchema } from '@objectstack/spec/kernel'; import { ObjectStackProtocolImplementation, zodIssuesToMetadataIssues } from './protocol.js'; @@ -51,7 +51,8 @@ function makeProtocol() { const rows = new Map(); let nextId = 0; const engine: any = { - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async find() { return []; }, async insert(table: string, data: Record) { if (table === 'sys_metadata_audit') return { id: 'audit_skip' }; diff --git a/packages/metadata-protocol/src/protocol.stored-conversions.test.ts b/packages/metadata-protocol/src/protocol.stored-conversions.test.ts index 76977599e47..5140a4eb92e 100644 --- a/packages/metadata-protocol/src/protocol.stored-conversions.test.ts +++ b/packages/metadata-protocol/src/protocol.stored-conversions.test.ts @@ -23,7 +23,7 @@ import { describe, expect, it } from 'vitest'; // would close a dependency cycle turbo rejects outright — which is why all 26 // of this package's (file, verb) pairs sat in the gate's DEBT ledger until // #5619 sank the two predicates into a package both sides already depend on. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -58,6 +58,7 @@ function makeStubEngine(seedRows: Array & { type: string; name: str const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return rows.find((r) => matches(r, opts.where)) ?? null; }, async find(_t: string, opts: { where: Record }) { diff --git a/packages/metadata-protocol/src/protocol.stored-migration.test.ts b/packages/metadata-protocol/src/protocol.stored-migration.test.ts index 7dd9d2a2a7a..616ea5dbc6c 100644 --- a/packages/metadata-protocol/src/protocol.stored-migration.test.ts +++ b/packages/metadata-protocol/src/protocol.stored-migration.test.ts @@ -25,7 +25,7 @@ import { describe, expect, it } from 'vitest'; // would close a dependency cycle turbo rejects outright — which is why all 26 // of this package's (file, verb) pairs sat in the gate's DEBT ledger until // #5619 sank the two predicates into a package both sides already depend on. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; import { formatStoredMigrationReport, storedMigrationClean } from './stored-migration.js'; @@ -84,6 +84,7 @@ function makeStubEngine( return rowsOf(t).filter((r) => matches(r, opts?.where ?? {})); }, async findOne(t: string, opts?: { where?: Record }) { + assertEngineFindOnePredicate(t, opts); return rowsOf(t).find((r) => matches(r, opts?.where ?? {})) ?? null; }, async insert(t: string, row: Record) { diff --git a/packages/metadata-protocol/src/protocol.stored-residue-resave.test.ts b/packages/metadata-protocol/src/protocol.stored-residue-resave.test.ts index 1e9d8672edc..17638f54457 100644 --- a/packages/metadata-protocol/src/protocol.stored-residue-resave.test.ts +++ b/packages/metadata-protocol/src/protocol.stored-residue-resave.test.ts @@ -42,7 +42,7 @@ import { describe, expect, it } from 'vitest'; // [#5619] The producer's OWN write-verb dispatch decisions, so the fake engine // below cannot accept a call ObjectQL itself refuses. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; function matches(r: Record, where: Record): boolean { @@ -90,6 +90,7 @@ function makeStubEngine(seedRows: Array>) { return rowsOf(t).filter((r) => matches(r, opts?.where ?? {})); }, async findOne(t: string, opts?: { where?: Record }) { + assertEngineFindOnePredicate(t, opts); return rowsOf(t).find((r) => matches(r, opts?.where ?? {})) ?? null; }, async insert(t: string, row: Record) { diff --git a/packages/metadata-protocol/src/protocol.unrecognised-meta-type.test.ts b/packages/metadata-protocol/src/protocol.unrecognised-meta-type.test.ts index 3702dfeea4a..4bc49204f19 100644 --- a/packages/metadata-protocol/src/protocol.unrecognised-meta-type.test.ts +++ b/packages/metadata-protocol/src/protocol.unrecognised-meta-type.test.ts @@ -54,7 +54,7 @@ import { describe, expect, it } from 'vitest'; // [#5619] The producer's OWN write-verb dispatch decisions, so the fake engine // below cannot accept a call ObjectQL itself refuses. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; interface Row { @@ -93,6 +93,7 @@ function makeProtocol(seedRows: Array> = []) { const deletes: Array | undefined> = []; const engine: any = { async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); for (const row of rows.values()) { if (opts.where.type !== undefined && row.type !== opts.where.type) continue; if (opts.where.name !== undefined && row.name !== opts.where.name) continue; diff --git a/packages/metadata-protocol/src/protocol.update-path-id-wins.test.ts b/packages/metadata-protocol/src/protocol.update-path-id-wins.test.ts index e4b208059dd..b5195cea531 100644 --- a/packages/metadata-protocol/src/protocol.update-path-id-wins.test.ts +++ b/packages/metadata-protocol/src/protocol.update-path-id-wins.test.ts @@ -58,7 +58,7 @@ import { describe, it, expect, vi } from 'vitest'; import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, - resolveEngineUpdateDispatch, + resolveEngineUpdateDispatch, assertEngineFindOnePredicate, } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -92,6 +92,7 @@ type Row = Record & { id: string }; function makeProtocol(rows: Row[]) { const store = new Map(rows.map((r) => [r.id, { ...r }])); const findOne = vi.fn(async (_object: string, opts: any) => { + assertEngineFindOnePredicate(_object, opts); const row = store.get(String(opts?.where?.id)); return row ? { ...row } : null; }); diff --git a/packages/metadata-protocol/src/protocol.upsert-existence.test.ts b/packages/metadata-protocol/src/protocol.upsert-existence.test.ts index bd0209a2b80..6dd37b77ad3 100644 --- a/packages/metadata-protocol/src/protocol.upsert-existence.test.ts +++ b/packages/metadata-protocol/src/protocol.upsert-existence.test.ts @@ -26,7 +26,7 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; const SCHEMA = { @@ -55,6 +55,7 @@ function makeRlsEngine() { context?.isSystem === true || row.owner_id === context?.userId; const findOne = vi.fn(async (_object: string, options?: any) => { + assertEngineFindOnePredicate(_object, options); const row = rows.get(options?.where?.id) ?? null; if (!row) return null; return visible(row, options?.context) ? row : null; diff --git a/packages/metadata-protocol/src/protocol.write-response-internal-fields.tripwire.test.ts b/packages/metadata-protocol/src/protocol.write-response-internal-fields.tripwire.test.ts index 66b3f7d6fc4..000b129eb6b 100644 --- a/packages/metadata-protocol/src/protocol.write-response-internal-fields.tripwire.test.ts +++ b/packages/metadata-protocol/src/protocol.write-response-internal-fields.tripwire.test.ts @@ -45,7 +45,7 @@ // enumeration is shown to pick it up, and the scan is shown to catch its leak. import { describe, it, expect } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; import { collectInternalWriteResponseFields, @@ -106,7 +106,7 @@ function makeSentinelEngine() { assertEngineDeleteDispatch(options); return { deleted: 1 }; }, - findOne: async (_object: string, options?: any) => storedRow(options?.where?.id ?? 'row-1'), + findOne: async (_object: string, options?: any) => { assertEngineFindOnePredicate(_object, options); return storedRow(options?.where?.id ?? 'row-1'); }, find: async (_object: string, _options?: any) => [storedRow('row-1')], count: async () => 1, validate: async () => ({ valid: true, issues: [] }), diff --git a/packages/metadata-protocol/src/search-clone-schema-conformance.test.ts b/packages/metadata-protocol/src/search-clone-schema-conformance.test.ts index 0d3262496d5..0833c66ac0c 100644 --- a/packages/metadata-protocol/src/search-clone-schema-conformance.test.ts +++ b/packages/metadata-protocol/src/search-clone-schema-conformance.test.ts @@ -30,6 +30,7 @@ import { describe, it, expect, vi } from 'vitest'; import { CloneDataResponseSchema, SearchAllHitSchema, SearchAllResponseSchema } from '@objectstack/spec/api'; import { ObjectStackProtocolImplementation } from './protocol.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** What a caller actually holds after the REST relay: the JSON body. */ function overTheWire(value: T): T { @@ -144,7 +145,7 @@ function makeCloneProtocol() { const inserts: Array<{ object: string; data: Record }> = []; const engine = { registry: { getObject: (n: string) => (n === 'customer' ? customer : undefined) }, - findOne: vi.fn(async () => ({ ...source })), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return ({ ...source }); }), insert: vi.fn(async (object: string, data: Record) => { inserts.push({ object, data }); return { id: 'cus_2', ...data, created_at: '2026-08-25T00:00:00Z' }; diff --git a/packages/metadata-protocol/src/seed-loader-composite-external-id.test.ts b/packages/metadata-protocol/src/seed-loader-composite-external-id.test.ts index 0731bd00f79..c4bece344d7 100644 --- a/packages/metadata-protocol/src/seed-loader-composite-external-id.test.ts +++ b/packages/metadata-protocol/src/seed-loader-composite-external-id.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * Composite externalId (framework#3434). @@ -43,6 +43,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as any)(objectName, { ...query, limit: 1 }); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/seed-loader-deferred-dropped.test.ts b/packages/metadata-protocol/src/seed-loader-deferred-dropped.test.ts index a0abb67c927..5acf8f8bcee 100644 --- a/packages/metadata-protocol/src/seed-loader-deferred-dropped.test.ts +++ b/packages/metadata-protocol/src/seed-loader-deferred-dropped.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * #5127 / #11674 — pass 2 RESOLVES the target; does it have a record to write @@ -52,6 +52,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as any)(objectName, { ...query, limit: 1 }); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/seed-loader-deferred-failure.test.ts b/packages/metadata-protocol/src/seed-loader-deferred-failure.test.ts index 3bf39259e0f..24406d1d43d 100644 --- a/packages/metadata-protocol/src/seed-loader-deferred-failure.test.ts +++ b/packages/metadata-protocol/src/seed-loader-deferred-failure.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * framework#2805: a pass-2 (deferred) reference back-fill that FAILS must be @@ -37,6 +37,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as any)(objectName, { ...query, limit: 1 }); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/seed-loader-driver-text.test.ts b/packages/metadata-protocol/src/seed-loader-driver-text.test.ts index 79a9201c89a..a2dae2ad398 100644 --- a/packages/metadata-protocol/src/seed-loader-driver-text.test.ts +++ b/packages/metadata-protocol/src/seed-loader-driver-text.test.ts @@ -79,7 +79,7 @@ import { describe, expect, it, vi } from 'vitest'; import { validationFailureDetails } from '@objectstack/types'; import { SeedLoaderService } from './seed-loader.js'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; // --------------------------------------------------------------------------- // The physical conditions @@ -145,7 +145,7 @@ function createMetadata(): IMetadataService { function failingEngine(thrown: () => unknown): IDataEngine { return { find: vi.fn(async () => []), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), insert: vi.fn(async () => { throw thrown(); }), update: vi.fn(async (_o: string, data: any, options?: any) => { assertEngineUpdateDispatch(data, options); @@ -221,6 +221,7 @@ describe('[#8442] raw driver text is withheld from the seed `errors[].message`', : rows; }), findOne: vi.fn(async (o: string, q?: any) => { + assertEngineFindOnePredicate(o, q); const rows = await (engine.find as any)(o, q); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/seed-loader-engine-schema-fallback.test.ts b/packages/metadata-protocol/src/seed-loader-engine-schema-fallback.test.ts index 5b9d7fa951d..616bf8111f5 100644 --- a/packages/metadata-protocol/src/seed-loader-engine-schema-fallback.test.ts +++ b/packages/metadata-protocol/src/seed-loader-engine-schema-fallback.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * Reference-graph fallback to the ENGINE schema registry. @@ -49,6 +49,7 @@ function createFaithfulEngine(schemas: Record) { return records; }), findOne: vi.fn(async (objectName: string, query?: any) => { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as any)(objectName, { ...query, limit: 1 }); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/seed-loader-env-scope.test.ts b/packages/metadata-protocol/src/seed-loader-env-scope.test.ts index dc9ad27facf..d2f879a5d6a 100644 --- a/packages/metadata-protocol/src/seed-loader-env-scope.test.ts +++ b/packages/metadata-protocol/src/seed-loader-env-scope.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { SeedLoaderService } from './seed-loader.js'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** * `Seed.env` is ENFORCED, not merely authorable (framework#4704). @@ -50,7 +50,7 @@ function createEngine() { if (typeof query?.limit === 'number') records = records.slice(0, query.limit); return records; }), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), insert: vi.fn(async (objectName: string, data: any) => { if (!store[objectName]) store[objectName] = []; if (Array.isArray(data)) { diff --git a/packages/metadata-protocol/src/seed-loader-existing-records-read-failure.test.ts b/packages/metadata-protocol/src/seed-loader-existing-records-read-failure.test.ts index f051d085890..9ba072e8762 100644 --- a/packages/metadata-protocol/src/seed-loader-existing-records-read-failure.test.ts +++ b/packages/metadata-protocol/src/seed-loader-existing-records-read-failure.test.ts @@ -42,7 +42,7 @@ import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts' // refuses. From `@objectstack/metadata-core`, not `@objectstack/objectql` — // objectql depends on THIS package, so that import would close a dependency // cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; // `.js` extension deliberately, unlike the older sibling seed-loader tests: // `moduleResolution: nodenext` requires it, and an extensionless specifier is // exactly the TS2835 that makes up part of this package's frozen TEST_DEBT @@ -92,6 +92,7 @@ function createEngine() { return records; }), findOne: vi.fn(async (objectName: string, query?: Record) => { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as unknown as (o: string, q: unknown) => Promise)( objectName, { ...query, limit: 1 }, ); diff --git a/packages/metadata-protocol/src/seed-loader-multi-value-reference.test.ts b/packages/metadata-protocol/src/seed-loader-multi-value-reference.test.ts index 997fec59fe1..41454d69f0b 100644 --- a/packages/metadata-protocol/src/seed-loader-multi-value-reference.test.ts +++ b/packages/metadata-protocol/src/seed-loader-multi-value-reference.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * Multi-value reference resolution (`Field.lookup(..., { multiple: true })`). @@ -44,6 +44,7 @@ function createEngine(schemas: Record) { return records.map((r) => ({ ...r })); }), findOne: vi.fn(async (objectName: string, query?: any) => { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as any)(objectName, { ...query, limit: 1 }); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/seed-loader-name-probe.test.ts b/packages/metadata-protocol/src/seed-loader-name-probe.test.ts index 2fbf33c9cd1..f716f97ecd0 100644 --- a/packages/metadata-protocol/src/seed-loader-name-probe.test.ts +++ b/packages/metadata-protocol/src/seed-loader-name-probe.test.ts @@ -7,7 +7,7 @@ import { describe, it, expect, vi } from 'vitest'; // rule and sit in this package's frozen debt; a NEW file must not add to it. import { SeedLoaderService } from './seed-loader.js'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * [#9071] The seed loader's external-key lookup chain must ASK the metadata @@ -105,6 +105,7 @@ function createColumnStrictEngine(columns: Record) { return records; }), findOne: vi.fn(async (objectName: string, query?: any) => { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as any)(objectName, { ...query, limit: 1 }); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/seed-loader-pointer-pair.test.ts b/packages/metadata-protocol/src/seed-loader-pointer-pair.test.ts index 23224800e49..76db8fa3899 100644 --- a/packages/metadata-protocol/src/seed-loader-pointer-pair.test.ts +++ b/packages/metadata-protocol/src/seed-loader-pointer-pair.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader.js'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * Declared pointer-pair resolution — #11339 (ADR-0052 §5, the ActivityPointer @@ -55,6 +55,7 @@ function createFaithfulEngine(schemas: Record) { return records; }), findOne: vi.fn(async (objectName: string, query?: any) => { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as any)(objectName, { ...query, limit: 1 }); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/seed-loader-replay.test.ts b/packages/metadata-protocol/src/seed-loader-replay.test.ts index 8e84b7caca6..b8e1f1746c8 100644 --- a/packages/metadata-protocol/src/seed-loader-replay.test.ts +++ b/packages/metadata-protocol/src/seed-loader-replay.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * Replay regression: seeds with lookup natural keys must survive a dev-server @@ -40,6 +40,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as any)(objectName, { ...query, limit: 1 }); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/seed-loader-retry.test.ts b/packages/metadata-protocol/src/seed-loader-retry.test.ts index f58ab5f23d9..6ddfeb473fb 100644 --- a/packages/metadata-protocol/src/seed-loader-retry.test.ts +++ b/packages/metadata-protocol/src/seed-loader-retry.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * framework#3150: the self-referencing seed path (`hasSelfRef`) writes records @@ -33,6 +33,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as any)(objectName, { ...query, limit: 1 }); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/seed-loader-state-machine-exempt.test.ts b/packages/metadata-protocol/src/seed-loader-state-machine-exempt.test.ts index 4d6a136d2b7..b1e2974d8fb 100644 --- a/packages/metadata-protocol/src/seed-loader-state-machine-exempt.test.ts +++ b/packages/metadata-protocol/src/seed-loader-state-machine-exempt.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** * #3433 — a curated seed is a snapshot of ESTABLISHED facts (a project already @@ -74,7 +74,7 @@ function createEnforcingEngine(): { engine: IDataEngine; store: Record null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), // Per-row partial-success path the seed loader prefers (framework#3172): // one verdict per row, so a rejected row is culled, not thrown as a batch. insertMany: vi.fn(async (objectName: string, rows: any[], opts: any) => diff --git a/packages/metadata-protocol/src/seed-loader-summary-stale.test.ts b/packages/metadata-protocol/src/seed-loader-summary-stale.test.ts index efdabc53769..5e339bad6f3 100644 --- a/packages/metadata-protocol/src/seed-loader-summary-stale.test.ts +++ b/packages/metadata-protocol/src/seed-loader-summary-stale.test.ts @@ -4,7 +4,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoadResultSchema, SeedLoaderResultSchema } from '@objectstack/spec/data'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * framework#4998: a roll-up summary recompute that exhausts its retries must be @@ -45,6 +45,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as any)(objectName, { ...query, limit: 1 }); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/seed-loader-unresolved-drop.test.ts b/packages/metadata-protocol/src/seed-loader-unresolved-drop.test.ts index 5cadee528a4..b2bcd99e2aa 100644 --- a/packages/metadata-protocol/src/seed-loader-unresolved-drop.test.ts +++ b/packages/metadata-protocol/src/seed-loader-unresolved-drop.test.ts @@ -8,7 +8,7 @@ import { describe, it, expect, vi } from 'vitest'; // tests; this one is the one tsc can actually read. import { SeedLoaderService } from './seed-loader.js'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * framework#4997: a record DROPPED because its reference cannot be resolved — @@ -56,6 +56,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineFindOnePredicate(objectName, query); const rows = await (engine.find as any)(objectName, { ...query, limit: 1 }); return rows[0] ?? null; }), diff --git a/packages/metadata-protocol/src/sys-metadata-repository.contract.test.ts b/packages/metadata-protocol/src/sys-metadata-repository.contract.test.ts index 99659fa1b6b..9ff51addda4 100644 --- a/packages/metadata-protocol/src/sys-metadata-repository.contract.test.ts +++ b/packages/metadata-protocol/src/sys-metadata-repository.contract.test.ts @@ -55,7 +55,7 @@ import { describe, it, expect, afterEach } from 'vitest'; import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, - hashSpec, + hashSpec, assertEngineFindOnePredicate, } from '@objectstack/metadata-core'; import { runRepositoryContractTests } from '@objectstack/metadata-core/testing'; import type { MetadataEvent, WatchFilter } from '@objectstack/metadata-core'; @@ -109,6 +109,7 @@ function makeFakeEngine() { return typeof opts.limit === 'number' ? hits.slice(0, opts.limit) : hits; }, async findOne(table: string, opts: { where: Record }): Promise { + assertEngineFindOnePredicate(table, opts); return tableOf(table).find((r) => matches(r, opts.where)) ?? null; }, async insert(table: string, data: Record): Promise<{ id: string }> { diff --git a/packages/metadata-protocol/src/sys-metadata-repository.draft-drain.test.ts b/packages/metadata-protocol/src/sys-metadata-repository.draft-drain.test.ts index 2218f4c9fe5..cc3a01e03d9 100644 --- a/packages/metadata-protocol/src/sys-metadata-repository.draft-drain.test.ts +++ b/packages/metadata-protocol/src/sys-metadata-repository.draft-drain.test.ts @@ -34,7 +34,7 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; // would close a dependency cycle turbo rejects outright — which is why all 26 // of this package's (file, verb) pairs sat in the gate's DEBT ledger until // #5619 sank the two predicates into a package both sides already depend on. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { readFileSync } from 'node:fs'; import { SysMetadataRepository } from './sys-metadata-repository.js'; @@ -143,6 +143,7 @@ function makeFakeEngine() { }); }, async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; } diff --git a/packages/metadata-protocol/src/sys-metadata-repository.draft-package-inherit.test.ts b/packages/metadata-protocol/src/sys-metadata-repository.draft-package-inherit.test.ts index 8ab02ee23b1..e1aec72b961 100644 --- a/packages/metadata-protocol/src/sys-metadata-repository.draft-package-inherit.test.ts +++ b/packages/metadata-protocol/src/sys-metadata-repository.draft-package-inherit.test.ts @@ -29,7 +29,7 @@ import { describe, it, expect } from 'vitest'; // The engine-double contract gate: a fake looser than ObjectQL's own verb // dispatch is how #4434 shipped a dead route with its suite green. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { SysMetadataRepository } from './sys-metadata-repository.js'; interface Row { @@ -65,6 +65,7 @@ function makeFakeEngine(seed: Row[] = []) { rows, history, async findOne(table: string, q: { where: Record }) { + assertEngineFindOnePredicate(table, q); return tableOf(table).find((r) => matches(r, q.where)) ?? null; }, async find(table: string, q: { where: Record }) { diff --git a/packages/metadata-protocol/src/sys-metadata-repository.history-counters.test.ts b/packages/metadata-protocol/src/sys-metadata-repository.history-counters.test.ts index 17e69696f16..1e454fea99a 100644 --- a/packages/metadata-protocol/src/sys-metadata-repository.history-counters.test.ts +++ b/packages/metadata-protocol/src/sys-metadata-repository.history-counters.test.ts @@ -31,7 +31,7 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; // would close a dependency cycle turbo rejects outright — which is why all 26 // of this package's (file, verb) pairs sat in the gate's DEBT ledger until // #5619 sank the two predicates into a package both sides already depend on. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { readFileSync } from 'node:fs'; import { SysMetadataRepository } from './sys-metadata-repository.js'; import { isMissingTableError } from '@objectstack/metadata/errors'; @@ -129,6 +129,7 @@ function makeFakeEngine() { }); }, async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') { if (historyReadFailure) throw historyReadFailure(); return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; diff --git a/packages/metadata-protocol/src/sys-metadata-repository.package-writability.test.ts b/packages/metadata-protocol/src/sys-metadata-repository.package-writability.test.ts index c5da4129797..742aab3b948 100644 --- a/packages/metadata-protocol/src/sys-metadata-repository.package-writability.test.ts +++ b/packages/metadata-protocol/src/sys-metadata-repository.package-writability.test.ts @@ -58,7 +58,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; // refuses. Imported from `@objectstack/metadata-core` and not from // `@objectstack/objectql`: objectql DEPENDS ON this package, so that import // would close a dependency cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import type { MetaRef } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './protocol.js'; import { SysMetadataRepository, resetEnvWritableMetadataTypes } from './sys-metadata-repository.js'; @@ -125,6 +125,7 @@ function makeFakeEngine() { return Array.from(rows.values()); }, async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; return findRow(opts.where)?.row ?? null; }, diff --git a/packages/metadata-protocol/src/sys-metadata-repository.recorded-by.test.ts b/packages/metadata-protocol/src/sys-metadata-repository.recorded-by.test.ts index 7207b528b4a..10baba6befd 100644 --- a/packages/metadata-protocol/src/sys-metadata-repository.recorded-by.test.ts +++ b/packages/metadata-protocol/src/sys-metadata-repository.recorded-by.test.ts @@ -24,7 +24,7 @@ import { describe, it, expect, beforeEach } from 'vitest'; // would close a dependency cycle turbo rejects outright — which is why all 26 // of this package's (file, verb) pairs sat in the gate's DEBT ledger until // #5619 sank the two predicates into a package both sides already depend on. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { SysMetadataRepository } from './sys-metadata-repository.js'; interface Row { [k: string]: unknown } @@ -70,6 +70,7 @@ function makeFakeEngine() { }); }, async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') return historyRows.find((h) => matchesHistory(h, opts.where)) ?? null; return findRow(opts.where)?.row ?? null; }, diff --git a/packages/metadata-protocol/src/view-container-runtime-expansion.test.ts b/packages/metadata-protocol/src/view-container-runtime-expansion.test.ts index 49316e3932b..a370e557f4c 100644 --- a/packages/metadata-protocol/src/view-container-runtime-expansion.test.ts +++ b/packages/metadata-protocol/src/view-container-runtime-expansion.test.ts @@ -28,7 +28,7 @@ * choke point all three runtime hydration callers share. */ import { describe, expect, it } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from './index.js'; interface Row { @@ -62,7 +62,8 @@ function makeStubEngine() { return null; }; const engine: any = { - async findOne(_t: string, opts: { where: Record }) { return findRow(opts.where)?.row ?? null; }, + async findOne(_t: string, opts: { where: Record }) { + assertEngineFindOnePredicate(_t, opts); return findRow(opts.where)?.row ?? null; }, async find(_t: string, opts: { where: Record }) { return Array.from(rows.values()).filter((r) => matches(r, opts.where)); }, diff --git a/packages/metadata/src/migrations/migrate-sys-notification-to-event.test.ts b/packages/metadata/src/migrations/migrate-sys-notification-to-event.test.ts index 69237271684..ba50a34428a 100644 --- a/packages/metadata/src/migrations/migrate-sys-notification-to-event.test.ts +++ b/packages/metadata/src/migrations/migrate-sys-notification-to-event.test.ts @@ -9,7 +9,7 @@ import { describe, it, expect } from 'vitest'; // would close a dependency cycle turbo rejects, and is why both of this file's // (file, verb) pairs sat in the gate's DEBT ledger until #5619 sank the two // predicates into a package that depends on neither side. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; import { migrateSysNotificationToEvent } from './migrate-sys-notification-to-event.js'; /** Columns the legacy (pre-ADR-0030) sys_notification table physically has. */ @@ -57,7 +57,8 @@ function fakeEngine() { return data; }, async find() { return []; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async delete(_object?: string, options?: Record) { assertEngineDeleteDispatch(options); return {}; diff --git a/packages/plugins/plugin-auth/src/accept-invitation-adopt-membership.test.ts b/packages/plugins/plugin-auth/src/accept-invitation-adopt-membership.test.ts index 35c66b35612..51bad787eb2 100644 --- a/packages/plugins/plugin-auth/src/accept-invitation-adopt-membership.test.ts +++ b/packages/plugins/plugin-auth/src/accept-invitation-adopt-membership.test.ts @@ -21,7 +21,7 @@ // (revert the fix → these tests go red) mean anything. import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { AuthManager } from './auth-manager'; import { inviteForAudienceGate } from './audience-gate-test-support'; @@ -93,6 +93,7 @@ const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); const found = rows(name).find((r) => matches(r, q.where)); return found ? { ...found } : null; }, diff --git a/packages/plugins/plugin-auth/src/admin-revoke-user-session-match-guard.test.ts b/packages/plugins/plugin-auth/src/admin-revoke-user-session-match-guard.test.ts index 8cb07bbaff8..5aab4a5221d 100644 --- a/packages/plugins/plugin-auth/src/admin-revoke-user-session-match-guard.test.ts +++ b/packages/plugins/plugin-auth/src/admin-revoke-user-session-match-guard.test.ts @@ -18,7 +18,7 @@ // would prove nothing — the whole question is what answer leaves the library. import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { defaultRoles } from 'better-auth/plugins/admin/access'; import { AuthManager } from './auth-manager'; import { @@ -78,6 +78,7 @@ const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); const row = rows(name).find((r) => matches(r, q.where)); return row ? project(row, q.fields) : null; }, diff --git a/packages/plugins/plugin-auth/src/audience-posture-setting.test.ts b/packages/plugins/plugin-auth/src/audience-posture-setting.test.ts index 6435236c461..7d7cc71f367 100644 --- a/packages/plugins/plugin-auth/src/audience-posture-setting.test.ts +++ b/packages/plugins/plugin-auth/src/audience-posture-setting.test.ts @@ -35,6 +35,7 @@ import type { PluginContext } from '@objectstack/core'; import { AUDIENCE_POSTURES } from '@objectstack/spec/system'; import { AuthPlugin } from './auth-plugin.js'; import { AuthManager } from './auth-manager.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/objectql'; const SECRET = 'test-secret-at-least-32-chars-long'; @@ -45,7 +46,7 @@ function makeEngine() { return { insert: vi.fn(async (_object: string, row: any) => row), find: vi.fn(async () => []), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), }; } diff --git a/packages/plugins/plugin-auth/src/audience-posture.test.ts b/packages/plugins/plugin-auth/src/audience-posture.test.ts index 03c6e4a01a0..cb6c315632c 100644 --- a/packages/plugins/plugin-auth/src/audience-posture.test.ts +++ b/packages/plugins/plugin-auth/src/audience-posture.test.ts @@ -20,7 +20,7 @@ // the ADR-0078 defect this card closes. import { describe, it, expect, vi } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { ERROR_CODE_LEDGER } from '@objectstack/spec/api'; import { AuthManager } from './auth-manager'; import { @@ -77,6 +77,7 @@ const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); const row = rows(name).find((r) => matches(r, q.where)); return row ? project(row, q.fields) : null; }, diff --git a/packages/plugins/plugin-auth/src/auth-contains-filter.test.ts b/packages/plugins/plugin-auth/src/auth-contains-filter.test.ts index 6756ebc4ac6..2629de70f7d 100644 --- a/packages/plugins/plugin-auth/src/auth-contains-filter.test.ts +++ b/packages/plugins/plugin-auth/src/auth-contains-filter.test.ts @@ -91,6 +91,7 @@ import { FILTER_OPERATORS } from '@objectstack/spec/data'; import type { QueryAST } from '@objectstack/spec/data'; import type { IDataEngine } from '@objectstack/core'; import { createObjectQLAdapterFactory } from './objectql-adapter'; +import { assertEngineFindOnePredicate } from '@objectstack/objectql'; /** * The columns face 2 reads, declared — a real table has to be told. @@ -126,7 +127,7 @@ function sqlReadEngine(driver: SqlDriver): IDataEngine { // `find(obj, … as any)` too, and nothing here needs to be off-contract. return { find: (object: string, query: QueryAST) => driver.find(object, query), - findOne: (object: string, query: QueryAST) => driver.findOne(object, query), + findOne: (object: string, query: QueryAST) => { assertEngineFindOnePredicate(object, query); return driver.findOne(object, query); }, count: (object: string, query?: QueryAST) => driver.count(object, query), } as unknown as IDataEngine; } diff --git a/packages/plugins/plugin-auth/src/auth-manager.jwt-eddsa-fallback.test.ts b/packages/plugins/plugin-auth/src/auth-manager.jwt-eddsa-fallback.test.ts index 69a631d6fda..00ebcd4960f 100644 --- a/packages/plugins/plugin-auth/src/auth-manager.jwt-eddsa-fallback.test.ts +++ b/packages/plugins/plugin-auth/src/auth-manager.jwt-eddsa-fallback.test.ts @@ -12,7 +12,7 @@ // if the fallback did not reach jose, these tests would 500 like the bug report. import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { assertEngineDeleteDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { AuthManager } from './auth-manager'; const createMemoryEngine = () => { @@ -49,6 +49,7 @@ const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); return rows(name).find((r) => matches(r, q.where)) ?? null; }, async find(name: string, q: any = {}) { diff --git a/packages/plugins/plugin-auth/src/auth-manager.optional-plugin-isolation.test.ts b/packages/plugins/plugin-auth/src/auth-manager.optional-plugin-isolation.test.ts index 4485279683a..4a9e46da6cb 100644 --- a/packages/plugins/plugin-auth/src/auth-manager.optional-plugin-isolation.test.ts +++ b/packages/plugins/plugin-auth/src/auth-manager.optional-plugin-isolation.test.ts @@ -16,6 +16,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { AuthManager } from './auth-manager'; import { inviteForAudienceGate } from './audience-gate-test-support'; +import { assertEngineFindOnePredicate } from '@objectstack/objectql'; const failures = vi.hoisted(() => ({ oauthProvider: false, bearer: false })); @@ -83,6 +84,7 @@ const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); return rows(name).find((r) => matches(r, q.where)) ?? null; }, async find(name: string, q: any = {}) { diff --git a/packages/plugins/plugin-auth/src/auth-manager.test.ts b/packages/plugins/plugin-auth/src/auth-manager.test.ts index 254e5feb2e0..9ff8cbbe6a9 100644 --- a/packages/plugins/plugin-auth/src/auth-manager.test.ts +++ b/packages/plugins/plugin-auth/src/auth-manager.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { AuthManager, ipMatchesRange } from './auth-manager'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/objectql'; // Mock better-auth so we can control the handler behaviour vi.mock('better-auth', () => ({ @@ -898,7 +898,7 @@ describe('AuthManager', () => { find: vi.fn(async (object: string) => object === 'sys_member' && role !== null ? [{ role }] : [], ), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), count: vi.fn(async () => 0), insert: vi.fn(async () => ({})), update: vi.fn(async (_o: string, data: any, options?: any) => { @@ -3052,6 +3052,7 @@ describe('AuthManager', () => { // in dogfood that a query-agnostic mock had masked. const makeEngine = (user: any) => ({ findOne: vi.fn(async (_obj: string, q: any) => { + assertEngineFindOnePredicate(_obj, q); const w = q?.where ?? {}; if (!user) return null; const matches = Object.entries(w).every(([k, v]) => (user as any)[k] === v); @@ -3665,6 +3666,7 @@ describe('AuthManager', () => { const SECRET = 'test-secret-at-least-32-chars-long'; const makeEngine = (user: any) => ({ findOne: vi.fn(async (_o: string, q: any) => { + assertEngineFindOnePredicate(_o, q); const w = q?.where ?? {}; if (!user) return null; return Object.entries(w).every(([k, v]) => (user as any)[k] === v) ? user : null; @@ -3787,6 +3789,7 @@ describe('AuthManager', () => { const SECRET = 'test-secret-at-least-32-chars-long'; const makeEngine = (user: any, org: any) => ({ findOne: vi.fn(async (obj: string, q: any) => { + assertEngineFindOnePredicate(obj, q); const row = obj === 'sys_organization' ? org : user; if (!row) return null; const w = q?.where ?? {}; diff --git a/packages/plugins/plugin-auth/src/auth-where-operator-coverage.test.ts b/packages/plugins/plugin-auth/src/auth-where-operator-coverage.test.ts index acc0d93059e..718a998448e 100644 --- a/packages/plugins/plugin-auth/src/auth-where-operator-coverage.test.ts +++ b/packages/plugins/plugin-auth/src/auth-where-operator-coverage.test.ts @@ -74,7 +74,7 @@ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { SqlDriver } from '@objectstack/driver-sql'; -import { assertEngineDeleteDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { whereOperators } from '@better-auth/core/db/adapter'; import { FILTER_OPERATORS } from '@objectstack/spec/data'; import type { QueryAST } from '@objectstack/spec/data'; @@ -146,7 +146,7 @@ function sqlEngine(driver: SqlDriver): IDataEngine { // `query-options/no-any-erasure` (#4674/#4918) counts test-side calls too. return { find: (object: string, query: QueryAST) => driver.find(object, query), - findOne: (object: string, query: QueryAST) => driver.findOne(object, query), + findOne: (object: string, query: QueryAST) => { assertEngineFindOnePredicate(object, query); return driver.findOne(object, query); }, count: (object: string, query?: QueryAST) => driver.count(object, query), delete: async (object: string, options: Record) => { const dispatch = assertEngineDeleteDispatch(options); diff --git a/packages/plugins/plugin-auth/src/change-email-delete-user-wiring.test.ts b/packages/plugins/plugin-auth/src/change-email-delete-user-wiring.test.ts index a1e1ac18244..ae69f377301 100644 --- a/packages/plugins/plugin-auth/src/change-email-delete-user-wiring.test.ts +++ b/packages/plugins/plugin-auth/src/change-email-delete-user-wiring.test.ts @@ -32,7 +32,7 @@ */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import type { IEmailService, SendEmailResult, SendTemplateInput } from '@objectstack/spec/contracts'; import { AuthManager } from './auth-manager'; import { inviteForAudienceGate } from './audience-gate-test-support'; @@ -101,6 +101,7 @@ function createMemoryEngine() { return { ...row }; }, async findOne(name: string, query: MemoryQuery = {}): Promise { + assertEngineFindOnePredicate(name, query); const row = rows(name).find((r) => matches(r, query.where)); return row ? project(row, query.fields) : null; }, diff --git a/packages/plugins/plugin-auth/src/first-session-membership-ordering.test.ts b/packages/plugins/plugin-auth/src/first-session-membership-ordering.test.ts index 9af52775c0a..233ea63da7a 100644 --- a/packages/plugins/plugin-auth/src/first-session-membership-ordering.test.ts +++ b/packages/plugins/plugin-auth/src/first-session-membership-ordering.test.ts @@ -38,6 +38,7 @@ import { describe, it, expect, vi } from 'vitest'; import { AuthManager } from './auth-manager.js'; import { loginEventFor } from './auth-session-audit.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/objectql'; const USER = 'u_first_session'; const DEFAULT_ORG = 'org_default'; @@ -77,7 +78,7 @@ function makeEngine(seed: MemberRow[] = []) { ), // eslint-disable-next-line @typescript-eslint/no-explicit-any findOne: vi.fn(async (model: string, q: any) => - model === 'sys_member' ? (rows.find((r) => match(r, q?.where)) ?? null) : null, + { assertEngineFindOnePredicate(model, q); return model === 'sys_member' ? (rows.find((r) => match(r, q?.where)) ?? null) : null; }, ), }; } @@ -231,7 +232,8 @@ describe("[#8247 rule 2] a user's FIRST session settles the membership before re it('a broken engine never breaks session create', async () => { const engine = { - findOne: vi.fn(async () => { throw new Error('db down'); }), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { + assertEngineFindOnePredicate(object, query); throw new Error('db down'); }), find: vi.fn(async () => { throw new Error('db down'); }), insert: vi.fn(async () => { throw new Error('db down'); }), }; diff --git a/packages/plugins/plugin-auth/src/impersonation-bearer-rotation.test.ts b/packages/plugins/plugin-auth/src/impersonation-bearer-rotation.test.ts index 9484d41b72e..0cd3b2f7029 100644 --- a/packages/plugins/plugin-auth/src/impersonation-bearer-rotation.test.ts +++ b/packages/plugins/plugin-auth/src/impersonation-bearer-rotation.test.ts @@ -25,7 +25,7 @@ // calls. import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { AuthManager } from './auth-manager'; import { inviteForAudienceGate } from './audience-gate-test-support'; import { @@ -83,6 +83,7 @@ export const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); const row = rows(name).find((r) => matches(r, q.where)); return row ? project(row, q.fields) : null; }, diff --git a/packages/plugins/plugin-auth/src/membership-policy-setting.test.ts b/packages/plugins/plugin-auth/src/membership-policy-setting.test.ts index 4cc6effacfd..d9c490b2758 100644 --- a/packages/plugins/plugin-auth/src/membership-policy-setting.test.ts +++ b/packages/plugins/plugin-auth/src/membership-policy-setting.test.ts @@ -43,6 +43,7 @@ vi.mock('./reconcile-membership.js', async (importOriginal) => { }); import { reconcileMembership, backfillMemberships, MEMBERSHIP_POLICIES } from './reconcile-membership.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/objectql'; const reconcileSpy = vi.mocked(reconcileMembership); const backfillSpy = vi.mocked(backfillMemberships); @@ -75,7 +76,7 @@ function makeEngine(seed: { users?: Array<{ id: string }>; members?: Array<{ use } return []; }), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), }; } diff --git a/packages/plugins/plugin-auth/src/org-create-posture-gate.test.ts b/packages/plugins/plugin-auth/src/org-create-posture-gate.test.ts index 3e7803b19e6..e1bef818cd1 100644 --- a/packages/plugins/plugin-auth/src/org-create-posture-gate.test.ts +++ b/packages/plugins/plugin-auth/src/org-create-posture-gate.test.ts @@ -55,7 +55,7 @@ // precedent: patch the real thing, never stub our own code). import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { assertEngineDeleteDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { AuthManager } from './auth-manager'; import { createTenancyService, type TenancyService, type TenancyPosture } from './tenancy-service'; @@ -105,6 +105,7 @@ const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); const row = rows(name).find((r) => matches(r, q.where)); return row ? project(row, q.fields) : null; }, diff --git a/packages/plugins/plugin-auth/src/organization-add-member.test.ts b/packages/plugins/plugin-auth/src/organization-add-member.test.ts index db3e87026f4..45451418a07 100644 --- a/packages/plugins/plugin-auth/src/organization-add-member.test.ts +++ b/packages/plugins/plugin-auth/src/organization-add-member.test.ts @@ -31,7 +31,7 @@ import { describe, it, expect, vi, beforeAll, afterAll } from 'vitest'; import { Hono } from 'hono'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { AuthManager } from './auth-manager'; import { AuthPlugin } from './auth-plugin'; import { runOrganizationAddMember } from './organization-add-member.js'; @@ -105,6 +105,7 @@ const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); const row = rows(name).find((r) => matches(r, q.where)); return row ? project(row, q.fields) : null; }, diff --git a/packages/plugins/plugin-auth/src/remove-member-permission-guard.test.ts b/packages/plugins/plugin-auth/src/remove-member-permission-guard.test.ts index fa3652eb21a..2c02bee0949 100644 --- a/packages/plugins/plugin-auth/src/remove-member-permission-guard.test.ts +++ b/packages/plugins/plugin-auth/src/remove-member-permission-guard.test.ts @@ -47,7 +47,7 @@ // so the mounted route is what has to answer here. import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { AuthManager } from './auth-manager'; import { inviteForAudienceGate } from './audience-gate-test-support'; @@ -123,6 +123,7 @@ const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); const row = rows(name).find((r) => matches(r, q.where)); return row ? project(row, q.fields) : null; }, diff --git a/packages/plugins/plugin-auth/src/remove-user-atomicity.test.ts b/packages/plugins/plugin-auth/src/remove-user-atomicity.test.ts index dcb373adbc4..21683ee61ad 100644 --- a/packages/plugins/plugin-auth/src/remove-user-atomicity.test.ts +++ b/packages/plugins/plugin-auth/src/remove-user-atomicity.test.ts @@ -33,7 +33,7 @@ // the double cannot accept a call ObjectQL refuses. import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { SysMember } from '@objectstack/platform-objects'; import { AuthManager } from './auth-manager'; import { inviteForAudienceGate } from './audience-gate-test-support'; @@ -143,6 +143,7 @@ const createMemoryEngine = (vetoUserDelete?: () => Error | undefined) => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); const found = rows(name).find((r) => matches(r, q.where)); return found ? { ...found } : null; }, diff --git a/packages/plugins/plugin-auth/src/revoke-session-match-guard.test.ts b/packages/plugins/plugin-auth/src/revoke-session-match-guard.test.ts index aec1f09e0c7..e50f28fbc87 100644 --- a/packages/plugins/plugin-auth/src/revoke-session-match-guard.test.ts +++ b/packages/plugins/plugin-auth/src/revoke-session-match-guard.test.ts @@ -16,7 +16,7 @@ // answer leaves the library. import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { AuthManager } from './auth-manager'; import { REVOKE_SESSION_NOT_FOUND_CODE, @@ -73,6 +73,7 @@ const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); const row = rows(name).find((r) => matches(r, q.where)); return row ? project(row, q.fields) : null; }, diff --git a/packages/plugins/plugin-auth/src/scim-case-insensitive-identifier.test.ts b/packages/plugins/plugin-auth/src/scim-case-insensitive-identifier.test.ts index b78c48d3a45..99f4b6785e2 100644 --- a/packages/plugins/plugin-auth/src/scim-case-insensitive-identifier.test.ts +++ b/packages/plugins/plugin-auth/src/scim-case-insensitive-identifier.test.ts @@ -86,6 +86,7 @@ import { createObjectQLAdapterFactory, NORMALISED_IDENTIFIER_FIELDS, } from './objectql-adapter'; +import { assertEngineFindOnePredicate } from '@objectstack/objectql'; /** * The `sys_user` columns face 2 touches, declared — a real table has to be told. @@ -130,7 +131,7 @@ function sqlReadEngine(driver: SqlDriver): IDataEngine { // `query-options/no-any-erasure` (#4674/#4918) counts test-side calls too. return { find: (object: string, query: QueryAST) => driver.find(object, query), - findOne: (object: string, query: QueryAST) => driver.findOne(object, query), + findOne: (object: string, query: QueryAST) => { assertEngineFindOnePredicate(object, query); return driver.findOne(object, query); }, count: (object: string, query?: QueryAST) => driver.count(object, query), } as unknown as IDataEngine; } diff --git a/packages/plugins/plugin-auth/src/session-of-record.test.ts b/packages/plugins/plugin-auth/src/session-of-record.test.ts index 69d14a9cd8f..77f583bfce6 100644 --- a/packages/plugins/plugin-auth/src/session-of-record.test.ts +++ b/packages/plugins/plugin-auth/src/session-of-record.test.ts @@ -24,7 +24,7 @@ // and the sign-in after-hook really run. import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { assertEngineDeleteDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { AuthManager } from './auth-manager'; import { cacheSecondaryStorage } from './secondary-storage'; @@ -86,6 +86,7 @@ const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); const row = rows(name).find((r) => matches(r, q.where)); return row ? project(row, q.fields) : null; }, diff --git a/packages/plugins/plugin-auth/src/session-tombstone.test.ts b/packages/plugins/plugin-auth/src/session-tombstone.test.ts index a394240aa19..596b0a4b762 100644 --- a/packages/plugins/plugin-auth/src/session-tombstone.test.ts +++ b/packages/plugins/plugin-auth/src/session-tombstone.test.ts @@ -20,7 +20,7 @@ // the library does around our write. import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { runWithEndpointContext } from '@better-auth/core/context'; import { AuthManager } from './auth-manager'; import { BETTER_AUTH_MOUNTED_SURFACE } from './auth-route-ledger'; @@ -91,6 +91,7 @@ const createMemoryEngine = () => { return { ...row }; }, async findOne(name: string, q: any = {}) { + assertEngineFindOnePredicate(name, q); const row = rows(name).find((r) => matches(r, q.where)); return row ? project(row, q.fields) : null; }, diff --git a/packages/plugins/plugin-security/src/authored-row-write-verdict.test.ts b/packages/plugins/plugin-security/src/authored-row-write-verdict.test.ts index 686e2d8e29e..4f6aa7bd2c7 100644 --- a/packages/plugins/plugin-security/src/authored-row-write-verdict.test.ts +++ b/packages/plugins/plugin-security/src/authored-row-write-verdict.test.ts @@ -34,7 +34,7 @@ // shape: an app policy spelling the identical predicate is app-authored and must // keep counting. import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { PermissionSetSchema } from '@objectstack/spec/security'; import type { PermissionSet } from '@objectstack/spec/security'; import { SecurityPlugin } from './security-plugin.js'; @@ -218,6 +218,7 @@ function makeEngine(opts: { findOneThrows?: boolean } = {}) { return rows.filter((r) => matches(r, options.filter ?? options.where)).slice(0, options.limit ?? 1000); }, async findOne(object: string, options: any = {}) { + assertEngineFindOnePredicate(object, options); // The fail-closed case drives the probe itself into a throw — the method // must swallow it into `abstain` and never reject outward. if (opts.findOneThrows) throw new Error('engine exploded'); diff --git a/packages/plugins/plugin-security/src/check-only-write-scope.test.ts b/packages/plugins/plugin-security/src/check-only-write-scope.test.ts index 8a946e4c65c..f30284f5a9a 100644 --- a/packages/plugins/plugin-security/src/check-only-write-scope.test.ts +++ b/packages/plugins/plugin-security/src/check-only-write-scope.test.ts @@ -56,7 +56,7 @@ // must not change); reverting site 2 alone reddens the site-2 holder describe. // Neither revert reddens the other's pins. import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { SharingService, buildSharingMiddleware } from '@objectstack/plugin-sharing'; import { PermissionSetSchema } from '@objectstack/spec/security'; import type { PermissionSet } from '@objectstack/spec/security'; @@ -279,6 +279,7 @@ function makeEngine() { return rows.filter((r) => matches(r, options.filter ?? options.where)).slice(0, options.limit ?? 1000); }, async findOne(object: string, options: any = {}) { + assertEngineFindOnePredicate(object, options); const rows = await this.find(object, { ...options, limit: 1 }); return rows[0] ?? null; }, diff --git a/packages/plugins/plugin-security/src/controlled-by-parent-chain.test.ts b/packages/plugins/plugin-security/src/controlled-by-parent-chain.test.ts index f05e0d854d0..b3e3465010e 100644 --- a/packages/plugins/plugin-security/src/controlled-by-parent-chain.test.ts +++ b/packages/plugins/plugin-security/src/controlled-by-parent-chain.test.ts @@ -53,6 +53,7 @@ import { SecurityPlugin } from './security-plugin.js'; import { SharingService, type SharingEngine } from '@objectstack/plugin-sharing'; import { matchesFilterCondition } from '@objectstack/formula'; import type { PermissionSet } from '@objectstack/spec/security'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; const REP = 'usr_rep'; const OTHER = 'usr_other'; @@ -275,6 +276,7 @@ function makeStore(rows: Record, quoteModel: string = 'controlled return typeof options?.limit === 'number' ? hits.slice(0, options.limit) : hits; }), findOne: vi.fn(async (object: string, options: any = {}) => { + assertEngineFindOnePredicate(object, options); const all = rows[object] ?? []; return all.find((r) => matchesFilterCondition(r, options?.where ?? null)) ?? null; }), diff --git a/packages/plugins/plugin-security/src/controlled-by-parent-detail-write-authority.test.ts b/packages/plugins/plugin-security/src/controlled-by-parent-detail-write-authority.test.ts index a5519a8814e..9d40b3e341d 100644 --- a/packages/plugins/plugin-security/src/controlled-by-parent-detail-write-authority.test.ts +++ b/packages/plugins/plugin-security/src/controlled-by-parent-detail-write-authority.test.ts @@ -56,6 +56,7 @@ import { matchesFilterCondition } from '@objectstack/formula'; import { PermissionSetSchema } from '@objectstack/spec/security'; import type { PermissionSet } from '@objectstack/spec/security'; import { defaultPermissionSets } from './objects/default-permission-sets.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; const MKT = 'usr_marketing'; const ADMIN = 'usr_admin'; @@ -371,6 +372,7 @@ function makeStore(rows: Record) { return typeof options?.limit === 'number' ? hits.slice(0, options.limit) : hits; }), findOne: vi.fn(async (object: string, options: any = {}) => { + assertEngineFindOnePredicate(object, options); const all = rows[object] ?? []; return all.find((r) => matchesFilterCondition(r, options?.where ?? options?.filter ?? null)) ?? null; }), diff --git a/packages/plugins/plugin-security/src/controlled-by-parent-master-widener.test.ts b/packages/plugins/plugin-security/src/controlled-by-parent-master-widener.test.ts index 5699f30cd82..d5b1d26218e 100644 --- a/packages/plugins/plugin-security/src/controlled-by-parent-master-widener.test.ts +++ b/packages/plugins/plugin-security/src/controlled-by-parent-master-widener.test.ts @@ -59,6 +59,7 @@ import { matchesFilterCondition } from '@objectstack/formula'; import { PermissionSetSchema } from '@objectstack/spec/security'; import type { PermissionSet } from '@objectstack/spec/security'; import { defaultPermissionSets } from './objects/default-permission-sets.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; const MKT = 'usr_marketing'; const ADMIN = 'usr_admin'; @@ -271,6 +272,7 @@ function makeStore(rows: Record) { return typeof options?.limit === 'number' ? hits.slice(0, options.limit) : hits; }), findOne: vi.fn(async (object: string, options: any = {}) => { + assertEngineFindOnePredicate(object, options); const all = rows[object] ?? []; return all.find((r) => matchesFilterCondition(r, options?.where ?? options?.filter ?? null)) ?? null; }), diff --git a/packages/plugins/plugin-security/src/controlled-by-parent-sharing.test.ts b/packages/plugins/plugin-security/src/controlled-by-parent-sharing.test.ts index 77f6136db37..e86204c24d4 100644 --- a/packages/plugins/plugin-security/src/controlled-by-parent-sharing.test.ts +++ b/packages/plugins/plugin-security/src/controlled-by-parent-sharing.test.ts @@ -45,7 +45,7 @@ import { matchesFilterCondition } from '@objectstack/formula'; // the day the validator's own skip list changes. This package's vitest config // aliases `@objectstack/objectql` to `packages/objectql/src`, so this resolves // to the source in the checkout rather than a prebuilt dist. -import { validateRecord } from '@objectstack/objectql'; +import { validateRecord, assertEngineFindOnePredicate } from '@objectstack/objectql'; import type { PermissionSet } from '@objectstack/spec/security'; const REP = 'usr_rep'; @@ -227,6 +227,7 @@ function makeStore(rows: Record, detail: DetailVariant = 'valid', return typeof options?.limit === 'number' ? hits.slice(0, options.limit) : hits; }), findOne: vi.fn(async (object: string, options: any = {}) => { + assertEngineFindOnePredicate(object, options); // [#7505] The one thing this double gains: a store that is DOWN for one // object, so "the row is not there" and "I could not look" stop being the // same observation. diff --git a/packages/plugins/plugin-security/src/explain-engine.test.ts b/packages/plugins/plugin-security/src/explain-engine.test.ts index efa556a1507..d3b0781afcf 100644 --- a/packages/plugins/plugin-security/src/explain-engine.test.ts +++ b/packages/plugins/plugin-security/src/explain-engine.test.ts @@ -6,6 +6,7 @@ import { resolveUserAuthzGrants } from '@objectstack/core'; import { PermissionSetSchema } from '@objectstack/spec/security'; import { PermissionEvaluator } from './permission-evaluator'; import { explainAccess, buildContextForUser, type ExplainEngineDeps } from './explain-engine'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; const SALES_USER = PermissionSetSchema.parse({ name: 'sales_user', @@ -339,7 +340,7 @@ describe('explainAccess — fls reports partial masking (#9127)', () => { // `delegatorSets` stays null, which is a different report entirely. ql: { getSchema: () => PRIVATE_SCHEMA, - findOne: async () => ({ id: 'u_boss' }), + findOne: async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return ({ id: 'u_boss' }); }, find: async () => [], }, getPartialMaskRules: async () => ({ phone: 'phone' }), diff --git a/packages/plugins/plugin-security/src/field-masking-rule.test.ts b/packages/plugins/plugin-security/src/field-masking-rule.test.ts index f992206ebcc..bbee349b696 100644 --- a/packages/plugins/plugin-security/src/field-masking-rule.test.ts +++ b/packages/plugins/plugin-security/src/field-masking-rule.test.ts @@ -22,6 +22,7 @@ import { SecurityPlugin } from './security-plugin.js'; import { FieldMasker, maskFieldValue, MASK_CHAR } from './field-masker.js'; import type { PermissionSet } from '@objectstack/spec/security'; import type { FieldMaskingRule } from '@objectstack/spec/data'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; // --------------------------------------------------------------------------- // maskFieldValue — the preset + keepHead/keepTail transforms @@ -189,7 +190,7 @@ describe('SecurityPlugin — maskingRule middleware enforcement (#8993)', () => const ql: any = { registerMiddleware: (mw: any) => { if (!middleware) middleware = mw; }, getSchema: () => schema, - findOne: async () => null, + findOne: async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }, find: async () => [], }; const metadata = { get: async () => schema, list: async () => sets }; @@ -304,7 +305,7 @@ describe('SecurityPlugin — maskingRule middleware enforcement (#8993)', () => const ql: any = { registerMiddleware: (mw: any) => { if (!middleware) middleware = mw; }, getSchema: () => badSchema, - findOne: async () => null, + findOne: async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }, find: async () => [], }; const metadata = { get: async () => badSchema, list: async () => [setNoCap] }; diff --git a/packages/plugins/plugin-security/src/invitation-placement.test.ts b/packages/plugins/plugin-security/src/invitation-placement.test.ts index c38c21dc37f..5923fd52d01 100644 --- a/packages/plugins/plugin-security/src/invitation-placement.test.ts +++ b/packages/plugins/plugin-security/src/invitation-placement.test.ts @@ -16,6 +16,7 @@ import { createInvitationPlacementService, readPlacementIntent, } from './invitation-placement.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; const INTENT = { businessUnitId: 'bu_plant_a', positions: ['qc_inspector', 'line_lead'] }; @@ -38,7 +39,7 @@ function makeQl(tables: Record = {}) { ), ); }), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), insert: vi.fn(async (_o: string, row: any) => ({ id: 'row', ...row })), }; } diff --git a/packages/plugins/plugin-security/src/packaged-permission-set-lock-gate.test.ts b/packages/plugins/plugin-security/src/packaged-permission-set-lock-gate.test.ts index c8ab939baf5..7aaac1b474d 100644 --- a/packages/plugins/plugin-security/src/packaged-permission-set-lock-gate.test.ts +++ b/packages/plugins/plugin-security/src/packaged-permission-set-lock-gate.test.ts @@ -40,7 +40,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; // The producer's OWN write-verb dispatch decisions, so this fake engine cannot // accept a call ObjectQL refuses (`check:engine-double-contract`; imported // from `@objectstack/metadata-core` exactly as the sibling pins do). -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation, resetEnvWritableMetadataTypes, @@ -116,6 +116,7 @@ function makeFakeEngine(opts?: { listItemsThrows?: boolean }) { return Array.from(rows.values()); }, async findOne(table: string, opts2: { where: Record }) { + assertEngineFindOnePredicate(table, opts2); if (table === 'sys_metadata_history') return null; return findRow(opts2.where)?.row ?? null; }, diff --git a/packages/plugins/plugin-security/src/packaged-permission-set-lock.test.ts b/packages/plugins/plugin-security/src/packaged-permission-set-lock.test.ts index dfcc6f4a760..3fe6f1bcd05 100644 --- a/packages/plugins/plugin-security/src/packaged-permission-set-lock.test.ts +++ b/packages/plugins/plugin-security/src/packaged-permission-set-lock.test.ts @@ -75,7 +75,7 @@ import { describe, it, expect } from 'vitest'; import { PermissionSetSchema } from '@objectstack/spec/security'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { SysPermissionSet } from './objects/sys-permission-set.object.js'; import { createPermissionSetWriteThrough, @@ -143,6 +143,7 @@ function makeQl(declared: any[] | null = null) { return typeof q?.limit === 'number' ? hit.slice(0, q.limit) : hit; }, async findOne(object: string, q: any) { + assertEngineFindOnePredicate(object, q); const rows = tableFor(object); return rows?.find((r) => matches(r, q?.where)) ?? null; }, diff --git a/packages/plugins/plugin-security/src/packaged-permission-set-restore-leg.test.ts b/packages/plugins/plugin-security/src/packaged-permission-set-restore-leg.test.ts index dd839139fe0..3e463686bd1 100644 --- a/packages/plugins/plugin-security/src/packaged-permission-set-restore-leg.test.ts +++ b/packages/plugins/plugin-security/src/packaged-permission-set-restore-leg.test.ts @@ -68,7 +68,7 @@ */ import { describe, it, expect } from 'vitest'; -import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { PermissionSetSchema } from '@objectstack/spec/security'; import { createPermissionSetWriteThrough, @@ -140,6 +140,7 @@ function makeQl(rows: any[], declared: any[]) { ); }, async findOne(object: string, q: any) { + assertEngineFindOnePredicate(object, q); return (await this.find(object, q))[0] ?? null; }, // Opens with the PRODUCER's own dispatch predicate, never a hand-mirrored diff --git a/packages/plugins/plugin-security/src/permission-denied-user-copy.test.ts b/packages/plugins/plugin-security/src/permission-denied-user-copy.test.ts index 6264aea898d..591284d2754 100644 --- a/packages/plugins/plugin-security/src/permission-denied-user-copy.test.ts +++ b/packages/plugins/plugin-security/src/permission-denied-user-copy.test.ts @@ -38,7 +38,7 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { FileI18nAdapter } from '@objectstack/service-i18n'; import { PermissionSetSchema } from '@objectstack/spec/security'; import type { PermissionSet } from '@objectstack/spec/security'; @@ -125,6 +125,7 @@ function makeEngine() { return (tables[object] ??= []).filter((r) => matches(r, options?.where ?? options?.filter)); }, async findOne(object: string, options: any = {}) { + assertEngineFindOnePredicate(object, options); return (await this.find(object, options))[0] ?? null; }, async insert(object: string, data: any) { (tables[object] ??= []).push({ ...data }); return data; }, diff --git a/packages/plugins/plugin-security/src/permission-set-active.test.ts b/packages/plugins/plugin-security/src/permission-set-active.test.ts index 123edf77fb9..673a48df5dd 100644 --- a/packages/plugins/plugin-security/src/permission-set-active.test.ts +++ b/packages/plugins/plugin-security/src/permission-set-active.test.ts @@ -26,6 +26,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SecurityPlugin } from './security-plugin.js'; import type { PermissionSet } from '@objectstack/spec/security'; import type { ISecurityService } from '@objectstack/spec/contracts'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** The metadata-declared baseline every authenticated caller resolves additively. */ const MEMBER_DEFAULT: PermissionSet = { @@ -64,7 +65,7 @@ async function locateSecurityService( const ql: any = { registerMiddleware: () => {}, getSchema: (name: string) => (name === 'deal' ? schema : null), - findOne: async () => null, + findOne: async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }, find: async (object: string, query: any) => { if (object !== 'sys_permission_set') return []; const wanted: string[] = query?.where?.name?.$in ?? []; diff --git a/packages/plugins/plugin-security/src/permission-set-projection.test.ts b/packages/plugins/plugin-security/src/permission-set-projection.test.ts index 00bd08ba8e5..eea212f601b 100644 --- a/packages/plugins/plugin-security/src/permission-set-projection.test.ts +++ b/packages/plugins/plugin-security/src/permission-set-projection.test.ts @@ -35,6 +35,7 @@ import { reconcilePermissionSetProjection, type ProjectionLogger, } from './permission-set-projection.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * In-memory ql over sys_permission_set + sys_metadata. @@ -77,6 +78,7 @@ function makeQl() { return rows ? rows.filter((r) => matches(r, q?.where)) : []; }, async findOne(object: string, q: any) { + assertEngineFindOnePredicate(object, q); const rows = tableFor(object); return rows?.find((r) => matches(r, q?.where)) ?? null; }, diff --git a/packages/plugins/plugin-security/src/permission-set-resolution-memo.test.ts b/packages/plugins/plugin-security/src/permission-set-resolution-memo.test.ts index 35c0a977ee2..8db79d17317 100644 --- a/packages/plugins/plugin-security/src/permission-set-resolution-memo.test.ts +++ b/packages/plugins/plugin-security/src/permission-set-resolution-memo.test.ts @@ -42,6 +42,7 @@ import { describe, it, expect, vi } from 'vitest'; import type { PermissionSet } from '@objectstack/spec/security'; import { SecurityPlugin } from './security-plugin.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** Resolvable from metadata, so only `custom_role` below reaches the db loader. */ const baselineSet: PermissionSet = { @@ -74,7 +75,7 @@ const makeHarness = () => { }, getSchema: () => baseSchema, find, - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), }; const services: Record = { manifest: { register: vi.fn() }, diff --git a/packages/plugins/plugin-security/src/resolve-permission-sets-for-context.pin.test.ts b/packages/plugins/plugin-security/src/resolve-permission-sets-for-context.pin.test.ts index 8c5705e1ec5..d843b19b132 100644 --- a/packages/plugins/plugin-security/src/resolve-permission-sets-for-context.pin.test.ts +++ b/packages/plugins/plugin-security/src/resolve-permission-sets-for-context.pin.test.ts @@ -31,6 +31,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SecurityPlugin } from './security-plugin.js'; import type { PermissionSet } from '@objectstack/spec/security'; import type { ISecurityService } from '@objectstack/spec/contracts'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** A metadata-declared set: the platform baseline every member resolves additively. */ const MEMBER_DEFAULT: PermissionSet = { @@ -61,7 +62,7 @@ function bootPlugin(dbRows: Array> = []) { const ql: any = { registerMiddleware: () => {}, getSchema: (name: string) => (name === 'deal' ? schema : null), - findOne: async () => null, + findOne: async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }, find: async (object: string, query: any) => { if (object !== 'sys_permission_set') return []; const wanted: string[] = query?.where?.name?.$in ?? []; diff --git a/packages/plugins/plugin-security/src/row-write-widener-composition.test.ts b/packages/plugins/plugin-security/src/row-write-widener-composition.test.ts index badc535866c..9e2ed4210b3 100644 --- a/packages/plugins/plugin-security/src/row-write-widener-composition.test.ts +++ b/packages/plugins/plugin-security/src/row-write-widener-composition.test.ts @@ -60,7 +60,7 @@ // Anything read-scope-dependent belongs in the real-stack pin: // `packages/qa/dogfood/test/authored-row-write-scope.dogfood.test.ts`. import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { SharingService, buildSharingMiddleware } from '@objectstack/plugin-sharing'; import { PermissionSetSchema } from '@objectstack/spec/security'; import type { PermissionSet } from '@objectstack/spec/security'; @@ -244,6 +244,7 @@ function makeEngine() { return rows.filter((r) => matches(r, options.filter ?? options.where)).slice(0, options.limit ?? 1000); }, async findOne(object: string, options: any = {}) { + assertEngineFindOnePredicate(object, options); const rows = await this.find(object, { ...options, limit: 1 }); return rows[0] ?? null; }, diff --git a/packages/plugins/plugin-security/src/security-denial-user-copy.test.ts b/packages/plugins/plugin-security/src/security-denial-user-copy.test.ts index e08f8aaa2b4..c2ffc414c45 100644 --- a/packages/plugins/plugin-security/src/security-denial-user-copy.test.ts +++ b/packages/plugins/plugin-security/src/security-denial-user-copy.test.ts @@ -37,7 +37,7 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { matchesFilterCondition } from '@objectstack/formula'; import { FileI18nAdapter } from '@objectstack/service-i18n'; import { PermissionSetSchema } from '@objectstack/spec/security'; @@ -154,6 +154,7 @@ function makeEngine() { return (tables[object] ??= []).filter((r) => matches(r, options?.where ?? options?.filter)); }, async findOne(object: string, options: any = {}) { + assertEngineFindOnePredicate(object, options); return (await this.find(object, options))[0] ?? null; }, async insert(object: string, data: any) { (tables[object] ??= []).push({ ...data }); return data; }, diff --git a/packages/plugins/plugin-security/src/security-plugin.test.ts b/packages/plugins/plugin-security/src/security-plugin.test.ts index 9aaeb70467f..d29f21de478 100644 --- a/packages/plugins/plugin-security/src/security-plugin.test.ts +++ b/packages/plugins/plugin-security/src/security-plugin.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, vi } from 'vitest'; -import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; import { SecurityPlugin } from './security-plugin.js'; import { PermissionEvaluator, crudBucketForOperation } from './permission-evaluator.js'; import { FieldMasker } from './field-masker.js'; @@ -119,7 +119,7 @@ describe('SecurityPlugin', () => { const ql: any = { registerMiddleware: (mw: any) => middlewares.push(mw), find: vi.fn(async () => []), - findOne: vi.fn(async () => null), + findOne: vi.fn(async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }), insert: vi.fn(async (_o: string, d: any) => ({ id: d?.id ?? 'x' })), // Opens with the PRODUCER's own dispatch predicate, never a hand-mirrored // guard (check:engine-double-contract) — same shape as the makeQl double @@ -3551,7 +3551,7 @@ describe('SecurityPlugin — ADR-0066 D3 field-level requiredPermissions', () => const ql: any = { registerMiddleware: (mw: any) => { if (!middleware) middleware = mw; }, getSchema: () => schema, - findOne: async () => null, + findOne: async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }, find: async () => [], }; const metadata = { get: async () => schema, list: async () => sets }; @@ -3655,6 +3655,7 @@ describe('explainAccessForCaller (ADR-0090 D6/D12)', () => { return typeof opts?.limit === 'number' ? rows.slice(0, opts.limit) : rows; }, async findOne(object: string, opts: any) { + assertEngineFindOnePredicate(object, opts); const rows = (tables[object] ?? []).filter((r) => matches(r, opts?.where)); return rows[0] ?? null; }, @@ -3779,6 +3780,7 @@ describe('SecurityPlugin — ADR-0090 D10 agent intersection', () => { return typeof o?.limit === 'number' ? rows.slice(0, o.limit) : rows; }, async findOne(object: string, o: any) { + assertEngineFindOnePredicate(object, o); if (object.startsWith('sys_')) { return (tables[object] ?? []).filter((r) => matches(r, o?.where))[0] ?? null; } @@ -3960,7 +3962,7 @@ describe('managed-object write denies wiring (#3325)', () => { const ql: any = { registerMiddleware: vi.fn(), getSchema: () => undefined, - findOne: async () => null, + findOne: async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return null; }, find: async () => [], count: async () => 0, insert: async (_o: string, d: any) => ({ id: d?.id ?? 'x' }), diff --git a/packages/plugins/plugin-security/src/select-only-write-visibility.test.ts b/packages/plugins/plugin-security/src/select-only-write-visibility.test.ts index ddf606a1a25..a76a8c004bc 100644 --- a/packages/plugins/plugin-security/src/select-only-write-visibility.test.ts +++ b/packages/plugins/plugin-security/src/select-only-write-visibility.test.ts @@ -41,7 +41,7 @@ // posture-permitting object) is not newly narrowed — their readable set // is unbounded, so the readability requirement imposes nothing. import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { SharingService, buildSharingMiddleware } from '@objectstack/plugin-sharing'; import { PermissionSetSchema } from '@objectstack/spec/security'; import type { PermissionSet } from '@objectstack/spec/security'; @@ -269,6 +269,7 @@ function makeEngine() { return rows.filter((r) => matches(r, options.filter ?? options.where)).slice(0, options.limit ?? 1000); }, async findOne(object: string, options: any = {}) { + assertEngineFindOnePredicate(object, options); const rows = await this.find(object, { ...options, limit: 1 }); return rows[0] ?? null; }, diff --git a/packages/plugins/plugin-security/src/store-fault-fail-closed.test.ts b/packages/plugins/plugin-security/src/store-fault-fail-closed.test.ts index 0cee308a457..000c4590f28 100644 --- a/packages/plugins/plugin-security/src/store-fault-fail-closed.test.ts +++ b/packages/plugins/plugin-security/src/store-fault-fail-closed.test.ts @@ -36,6 +36,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SecurityPlugin } from './security-plugin.js'; import type { PermissionSet } from '@objectstack/spec/security'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; const USER = 'usr_admin'; const OTHER = 'usr_other'; @@ -144,6 +145,7 @@ async function boot(options: BootOptions = {}) { getSchema: (object: string) => SCHEMAS[object], find: vi.fn(async (object: string, o: any = {}) => (rows[object] ?? []).filter((r) => matches(r, o?.where))), findOne: vi.fn(async (object: string, o: any = {}) => { + assertEngineFindOnePredicate(object, o); if (options.faultOn && object === options.faultOn) throw datasourceOutage(object); return (rows[object] ?? []).find((r) => matches(r, o?.where)) ?? null; }), diff --git a/packages/plugins/plugin-security/src/vama-write-path-convergence.test.ts b/packages/plugins/plugin-security/src/vama-write-path-convergence.test.ts index c6fb2238126..c08d55d5a4b 100644 --- a/packages/plugins/plugin-security/src/vama-write-path-convergence.test.ts +++ b/packages/plugins/plugin-security/src/vama-write-path-convergence.test.ts @@ -31,7 +31,7 @@ import { assertEngineUpdateDispatch, resolveEngineDeleteDispatch, ENGINE_DELETE_REJECT_MESSAGE, - ENGINE_UPDATE_REJECT_MESSAGE, + ENGINE_UPDATE_REJECT_MESSAGE, assertEngineFindOnePredicate, } from '@objectstack/metadata-core'; import { SharingService, buildSharingMiddleware } from '@objectstack/plugin-sharing'; import { PermissionSetSchema } from '@objectstack/spec/security'; @@ -128,6 +128,7 @@ function makeEngine() { return rows.filter((r) => matches(r, options.filter ?? options.where)).slice(0, options.limit ?? 1000); }, async findOne(object: string, options: any = {}) { + assertEngineFindOnePredicate(object, options); const rows = await this.find(object, { ...options, limit: 1 }); return rows[0] ?? null; }, diff --git a/packages/plugins/plugin-sharing/src/authored-row-write-deferral.test.ts b/packages/plugins/plugin-sharing/src/authored-row-write-deferral.test.ts index 26d2c2fb34e..123318e92c0 100644 --- a/packages/plugins/plugin-sharing/src/authored-row-write-deferral.test.ts +++ b/packages/plugins/plugin-sharing/src/authored-row-write-deferral.test.ts @@ -51,7 +51,7 @@ // what THIS file owns is the consumer half: which outcomes widen, which do not, // and that everything that is not a literal `admit` leaves the refusal intact. import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { SharingService, type SharingSecurityProbe } from './sharing-service.js'; import { buildSharingMiddleware } from './sharing-plugin.js'; @@ -204,6 +204,7 @@ function makeEngine() { return rows.filter((r) => matches(r, options.filter ?? options.where)).slice(0, options.limit ?? 1000); }, async findOne(object: string, options: any = {}) { + assertEngineFindOnePredicate(object, options); const rows = await this.find(object, { ...options, limit: 1 }); return rows[0] ?? null; }, diff --git a/packages/plugins/plugin-sharing/src/share-link-eligibility.test.ts b/packages/plugins/plugin-sharing/src/share-link-eligibility.test.ts index bb7d9799466..f78ad1fc82a 100644 --- a/packages/plugins/plugin-sharing/src/share-link-eligibility.test.ts +++ b/packages/plugins/plugin-sharing/src/share-link-eligibility.test.ts @@ -45,7 +45,7 @@ import type { DriverQuery } from '@objectstack/spec/contracts'; // The producer's OWN dispatch predicate: a double that opens its write verbs // with this cannot accept a call the real engine refuses // (`check:engine-double-contract`). -import { assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { ShareLinkService } from './share-link-service.js'; import { SysShareLink } from './objects/sys-share-link.object.js'; @@ -136,7 +136,7 @@ async function boot(article: any = ARTICLE, options: BootOptions = {}) { if (!options.shapeRow || object !== 'article' || !Array.isArray(rows)) return rows; return rows.map(options.shapeRow); }, - findOne: (object: string, query: any) => driver.findOne(object, query), + findOne: (object: string, query: any) => { assertEngineFindOnePredicate(object, query); return driver.findOne(object, query); }, insert: (object: string, data: any) => driver.create(object, data), // Opened with ObjectQL's OWN dispatch predicate rather than a hand-mirrored // id check, so this facade cannot accept an update the real engine refuses diff --git a/packages/plugins/plugin-webhooks/src/auto-enqueuer.test.ts b/packages/plugins/plugin-webhooks/src/auto-enqueuer.test.ts index 2f005fb2061..af3361bb5b7 100644 --- a/packages/plugins/plugin-webhooks/src/auto-enqueuer.test.ts +++ b/packages/plugins/plugin-webhooks/src/auto-enqueuer.test.ts @@ -27,6 +27,7 @@ import type { } from '@objectstack/spec/contracts'; import type { EnqueueHttpInput } from '@objectstack/service-messaging'; import { AutoEnqueuer, type HttpEnqueueFn } from './auto-enqueuer.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; // --------------------------------------------------------------------------- // Fakes @@ -84,6 +85,7 @@ class FakeEngine implements IDataEngine { return all.filter((r) => Object.entries(q.where).every(([k, v]) => { if (k.startsWith('$')) throw new Error(`fake driver: unsupported operator ${k}`); return r[k] === v; })); } async findOne(name: string, q?: any): Promise { + assertEngineFindOnePredicate(name, q); return (await this.find(name, q))[0] ?? null; } async insert(name: string, data: any): Promise { diff --git a/packages/plugins/plugin-webhooks/src/bootstrap-declared-webhooks.test.ts b/packages/plugins/plugin-webhooks/src/bootstrap-declared-webhooks.test.ts index e1fb59a76cf..4928c2f5976 100644 --- a/packages/plugins/plugin-webhooks/src/bootstrap-declared-webhooks.test.ts +++ b/packages/plugins/plugin-webhooks/src/bootstrap-declared-webhooks.test.ts @@ -13,6 +13,7 @@ import { describe, expect, it, vi } from 'vitest'; import { AutoEnqueuer, type HttpEnqueueFn } from './auto-enqueuer.js'; import { bootstrapDeclaredWebhooks } from './bootstrap-declared-webhooks.js'; import { bindWebhookProvenanceStamp } from './webhook-provenance.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; // --------------------------------------------------------------------------- // Fakes @@ -65,6 +66,7 @@ class FakeEngine { return typeof q?.limit === 'number' ? out.slice(0, q.limit) : out; } async findOne(name: string, q?: any): Promise { + assertEngineFindOnePredicate(name, q); return (await this.find(name, q))[0] ?? null; } async insert(name: string, data: any): Promise { diff --git a/packages/plugins/plugin-webhooks/src/webhook-drop-durable-record.test.ts b/packages/plugins/plugin-webhooks/src/webhook-drop-durable-record.test.ts index 68034daf168..ac8cf7f0c7a 100644 --- a/packages/plugins/plugin-webhooks/src/webhook-drop-durable-record.test.ts +++ b/packages/plugins/plugin-webhooks/src/webhook-drop-durable-record.test.ts @@ -39,7 +39,7 @@ import type { RealtimeEventHandler, RealtimeEventPayload, } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { HttpDispatcher, MemoryHttpOutbox, @@ -92,6 +92,7 @@ function makeEngine( const engine: any = { async find() { return rows; }, async findOne(_n: string, opts?: any) { + assertEngineFindOnePredicate(_n, opts); const id = opts?.where?.id; if (id === undefined) return rows[0] ?? null; return rows.find((r) => r.id === id) ?? null; diff --git a/packages/plugins/plugin-webhooks/src/webhook-signing-secret.test.ts b/packages/plugins/plugin-webhooks/src/webhook-signing-secret.test.ts index 5041041c527..340f01796b4 100644 --- a/packages/plugins/plugin-webhooks/src/webhook-signing-secret.test.ts +++ b/packages/plugins/plugin-webhooks/src/webhook-signing-secret.test.ts @@ -26,7 +26,7 @@ import type { RealtimeEventHandler, RealtimeEventPayload, } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; import { MemoryHttpOutbox, HttpDispatcher, type FetchImpl } from '@objectstack/service-messaging'; import { AutoEnqueuer } from './auto-enqueuer.js'; @@ -65,7 +65,8 @@ class FakeRealtime implements IRealtimeService { function makeEngine(rows: any[]): IDataEngine { return { async find() { return rows; }, - async findOne() { return rows[0] ?? null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return rows[0] ?? null; }, async insert(_n: string, d: any) { return d; }, async update(_n: string, data: any, options?: any) { assertEngineUpdateDispatch(data, options); diff --git a/packages/rest/src/meta-compound-save-force-parity.test.ts b/packages/rest/src/meta-compound-save-force-parity.test.ts index bf023369947..c9d188afbf4 100644 --- a/packages/rest/src/meta-compound-save-force-parity.test.ts +++ b/packages/rest/src/meta-compound-save-force-parity.test.ts @@ -80,7 +80,7 @@ import { describe, it, expect, vi } from 'vitest'; // `.js` on purpose — NodeNext resolution requires the extension (#7248). import { RestServer } from './rest-server.js'; -import { assertEngineUpdateDispatch, assertEngineDeleteDispatch } from '@objectstack/metadata-core'; +import { assertEngineUpdateDispatch, assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; const META = '/api/v1/meta'; @@ -200,6 +200,7 @@ function boot() { return [...rows.values()].filter((r) => match(r, o?.where ?? {})); }, async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); if (table !== 'sys_metadata') return null; for (const r of rows.values()) if (match(r, o?.where ?? {})) return r; return null; diff --git a/packages/rest/src/meta-compound-save-mode-parity.test.ts b/packages/rest/src/meta-compound-save-mode-parity.test.ts index 3c3d6a0d4ae..2a26dbc61e5 100644 --- a/packages/rest/src/meta-compound-save-mode-parity.test.ts +++ b/packages/rest/src/meta-compound-save-mode-parity.test.ts @@ -73,7 +73,7 @@ import { describe, it, expect, vi } from 'vitest'; // `.js` on purpose — NodeNext resolution requires the extension (#7248). import { RestServer } from './rest-server.js'; -import { assertEngineUpdateDispatch, assertEngineDeleteDispatch } from '@objectstack/metadata-core'; +import { assertEngineUpdateDispatch, assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; const META = '/api/v1/meta'; @@ -185,6 +185,7 @@ function boot() { return [...rows.values()].filter((r) => match(r, o?.where ?? {})); }, async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); if (table !== 'sys_metadata') return null; for (const r of rows.values()) if (match(r, o?.where ?? {})) return r; return null; diff --git a/packages/rest/src/meta-object-extension-agreement.test.ts b/packages/rest/src/meta-object-extension-agreement.test.ts index 34b1a98f649..bd1ba89a5a8 100644 --- a/packages/rest/src/meta-object-extension-agreement.test.ts +++ b/packages/rest/src/meta-object-extension-agreement.test.ts @@ -32,7 +32,7 @@ // the anti-vacuity case pins that they ARE discriminated. import { describe, it, expect, vi } from 'vitest'; -import { SchemaRegistry } from '@objectstack/objectql'; +import { SchemaRegistry, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/objectql'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { RestServer } from './rest-server.js'; @@ -152,7 +152,7 @@ async function measure(opts: { // tenant overlay row is a different layer with its own precedence. Both // routes read this store, so it is held constant across every host. find: async () => [], - findOne: async () => undefined, + findOne: async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return undefined; }, }; const services = new Map(); diff --git a/packages/rest/src/meta-object-extension-property-classes.test.ts b/packages/rest/src/meta-object-extension-property-classes.test.ts index c14bcc348b5..c2422193f0c 100644 --- a/packages/rest/src/meta-object-extension-property-classes.test.ts +++ b/packages/rest/src/meta-object-extension-property-classes.test.ts @@ -56,7 +56,7 @@ // `meta-object-overlay-extension-fold.test.ts` (#8045, idempotency). import { describe, it, expect, vi } from 'vitest'; -import { SchemaRegistry } from '@objectstack/objectql'; +import { SchemaRegistry, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { RestServer } from './rest-server.js'; @@ -267,7 +267,7 @@ async function measure(opts: { find: async (table: string, q: { where: Record }) => table === 'sys_metadata' ? rows.filter((r) => matches(r, q.where)) : [], findOne: async (table: string, q: { where: Record }) => - table === 'sys_metadata' ? rows.find((r) => matches(r, q.where)) : undefined, + { assertEngineFindOnePredicate(table, q); return table === 'sys_metadata' ? rows.find((r) => matches(r, q.where)) : undefined; }, }; const services = new Map(); diff --git a/packages/rest/src/meta-object-materialization-agreement.test.ts b/packages/rest/src/meta-object-materialization-agreement.test.ts index ee50af5a1e6..e5d98a79cff 100644 --- a/packages/rest/src/meta-object-materialization-agreement.test.ts +++ b/packages/rest/src/meta-object-materialization-agreement.test.ts @@ -92,7 +92,7 @@ // `SchemaRegistry.materializeServedObjectOnto`. import { describe, it, expect, vi } from 'vitest'; -import { SchemaRegistry } from '@objectstack/objectql'; +import { SchemaRegistry, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/objectql'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { RestServer } from './rest-server.js'; @@ -227,7 +227,7 @@ async function measure(opts: { const engine = { registry, find: async () => [], - findOne: async () => undefined, + findOne: async (object: string, query?: EngineFindOneQueryInput) => { assertEngineFindOnePredicate(object, query); return undefined; }, }; const services = new Map(); diff --git a/packages/rest/src/meta-object-overlay-extension-fold.test.ts b/packages/rest/src/meta-object-overlay-extension-fold.test.ts index 4468f1a2a76..84f12205c47 100644 --- a/packages/rest/src/meta-object-overlay-extension-fold.test.ts +++ b/packages/rest/src/meta-object-overlay-extension-fold.test.ts @@ -39,7 +39,7 @@ // `prefolded` and `bridged` hosts here are what hold that. import { describe, it, expect, vi } from 'vitest'; -import { SchemaRegistry } from '@objectstack/objectql'; +import { SchemaRegistry, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { RestServer } from './rest-server.js'; @@ -243,7 +243,7 @@ async function measure(opts: { find: async (table: string, q: { where: Record }) => table === 'sys_metadata' ? rows.filter((r) => matches(r, q.where)) : [], findOne: async (table: string, q: { where: Record }) => - table === 'sys_metadata' ? rows.find((r) => matches(r, q.where)) : undefined, + { assertEngineFindOnePredicate(table, q); return table === 'sys_metadata' ? rows.find((r) => matches(r, q.where)) : undefined; }, }; const services = new Map(); diff --git a/packages/rest/src/meta-object-search-companion-agreement.test.ts b/packages/rest/src/meta-object-search-companion-agreement.test.ts index af3cf7ea962..f11ac9c4eae 100644 --- a/packages/rest/src/meta-object-search-companion-agreement.test.ts +++ b/packages/rest/src/meta-object-search-companion-agreement.test.ts @@ -65,7 +65,7 @@ // the companion is genuinely DISCRIMINATED rather than always-present. import { describe, it, expect, vi } from 'vitest'; -import { SchemaRegistry } from '@objectstack/objectql'; +import { SchemaRegistry, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { RestServer } from './rest-server.js'; @@ -208,7 +208,7 @@ async function measure(opts: { registry, find: async (_t: string, o?: { where?: Record }) => matchesRow(o?.where), findOne: async (_t: string, o?: { where?: Record }) => - matchesRow(o?.where)[0], + { assertEngineFindOnePredicate(_t, o); return matchesRow(o?.where)[0]; }, }; const services = new Map(); diff --git a/packages/rest/src/meta-published-overlay.test.ts b/packages/rest/src/meta-published-overlay.test.ts index 751b99f6f66..b06920199a2 100644 --- a/packages/rest/src/meta-published-overlay.test.ts +++ b/packages/rest/src/meta-published-overlay.test.ts @@ -42,7 +42,7 @@ import { describe, it, expect, vi } from 'vitest'; // The producer's OWN write-verb dispatch decisions, so the fake engine below // cannot accept a call ObjectQL itself would refuse — a double looser than the // real engine is how a dead route once shipped with its suite green. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { MetadataManager } from '@objectstack/metadata'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { RestServer } from './rest-server.js'; @@ -100,6 +100,7 @@ function makeStubEngine(opts: { failSysMetadataReads?: Error } = {}) { const engine: any = { async findOne(table: string, options: { where: Record }) { + assertEngineFindOnePredicate(table, options); if (table === 'sys_metadata' && opts.failSysMetadataReads) throw opts.failSysMetadataReads; if (table === 'sys_metadata_history') return null; return findRow(options.where)?.row ?? null; diff --git a/packages/rest/src/public-form-lookup-picker.test.ts b/packages/rest/src/public-form-lookup-picker.test.ts index 901f08a2de5..88b6eb478a7 100644 --- a/packages/rest/src/public-form-lookup-picker.test.ts +++ b/packages/rest/src/public-form-lookup-picker.test.ts @@ -29,7 +29,7 @@ import { describe, expect, it, vi } from 'vitest'; // The engine-double contract (#4434 / #5619): a fake engine's update/delete // must be exactly as strict as ObjectQL's dispatch, or a dead route ships with // its suite green. Both predicates live in metadata-core. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { RestServer } from './rest-server.js'; @@ -42,7 +42,8 @@ function stubEngine() { return { rows, engine: { - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async find() { return rows.slice(); }, async insert(table: string, data: Record) { if (table === 'sys_metadata_audit') return { id: 'audit_skip' }; diff --git a/packages/rest/src/public-form-routes.stored-row.test.ts b/packages/rest/src/public-form-routes.stored-row.test.ts index d0d9e7a82a2..73c415dcf3d 100644 --- a/packages/rest/src/public-form-routes.stored-row.test.ts +++ b/packages/rest/src/public-form-routes.stored-row.test.ts @@ -55,7 +55,7 @@ import { describe, expect, it, vi } from 'vitest'; // depends in this direction, and that reverse edge is a cycle turbo refuses. import { assertEngineDeleteDispatch, - assertEngineUpdateDispatch, + assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput, } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; // `.js` extension required under `moduleResolution: nodenext`. Without it the @@ -73,7 +73,8 @@ function stubEngine() { return { rows, engine: { - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async find() { return rows.slice(); }, async insert(table: string, data: Record) { if (table === 'sys_metadata_audit') return { id: 'audit_skip' }; diff --git a/packages/rest/src/rest-server-meta-read-org-scope.test.ts b/packages/rest/src/rest-server-meta-read-org-scope.test.ts index 752c48ca64e..22f0e705ac5 100644 --- a/packages/rest/src/rest-server-meta-read-org-scope.test.ts +++ b/packages/rest/src/rest-server-meta-read-org-scope.test.ts @@ -43,7 +43,7 @@ // org exists here for no other purpose. import { describe, it, expect, beforeEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { RestServer } from './rest-server.js'; @@ -151,6 +151,7 @@ function makeStubEngine() { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') return null; return findRow(opts.where)?.row ?? null; }, diff --git a/packages/runtime/src/action-execution-calldata-batch-retired.test.ts b/packages/runtime/src/action-execution-calldata-batch-retired.test.ts index 8abb67b8587..9db6e41b1e3 100644 --- a/packages/runtime/src/action-execution-calldata-batch-retired.test.ts +++ b/packages/runtime/src/action-execution-calldata-batch-retired.test.ts @@ -61,6 +61,7 @@ import { ApiEndpointSchema } from '@objectstack/spec/api'; import { callData, type ActionExecutionDeps } from './action-execution.js'; import { HttpDispatcher, type HttpProtocolContext } from './http-dispatcher.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; const EC = { userId: 'u1', isSystem: false, positions: [], permissions: [] } as any; /** [#5155] Every service lookup resolves off the REQUEST's kernel. */ @@ -87,7 +88,7 @@ function engine(store = rows()) { const id = bag?.where?.id; return id == null ? [...store] : store.filter((r) => r.id === String(id)); }, - findOne: async (_o: string, opts: any) => store.find((r) => r.id === String(opts?.where?.id)) ?? null, + findOne: async (_o: string, opts: any) => { assertEngineFindOnePredicate(_o, opts); return store.find((r) => r.id === String(opts?.where?.id)) ?? null; }, } as any; } diff --git a/packages/runtime/src/action-execution-calldata-not-found.test.ts b/packages/runtime/src/action-execution-calldata-not-found.test.ts index 1981ee3feac..a95697d0817 100644 --- a/packages/runtime/src/action-execution-calldata-not-found.test.ts +++ b/packages/runtime/src/action-execution-calldata-not-found.test.ts @@ -53,7 +53,7 @@ import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protoco // mirroring it) is what makes that impossible. `@objectstack/objectql` is // already a `dependencies` entry of `@objectstack/runtime`, so no manifest // change is needed to reach it. -import { assertEngineDeleteDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { ApiEndpointSchema, DeleteDataResponseSchema } from '@objectstack/spec/api'; import type { ApiEndpoint } from '@objectstack/spec/api'; @@ -125,7 +125,7 @@ function fallbackHarness(store = rows()) { function protocolHarness(store = rows()) { const engine: any = { registry: { getObject: (n: string) => (n === 'task' ? SCHEMA : undefined) }, - findOne: async (_o: string, opts: any) => store.get(String(opts?.where?.id)) ?? null, + findOne: async (_o: string, opts: any) => { assertEngineFindOnePredicate(_o, opts); return store.get(String(opts?.where?.id)) ?? null; }, find: async () => [...store.values()], update: async (_o: string, data: any, opts: any) => { const id = String(opts?.where?.id); diff --git a/packages/runtime/src/domains/meta-published-runtime-publish.test.ts b/packages/runtime/src/domains/meta-published-runtime-publish.test.ts index 087a66b3fa7..14ad781f07a 100644 --- a/packages/runtime/src/domains/meta-published-runtime-publish.test.ts +++ b/packages/runtime/src/domains/meta-published-runtime-publish.test.ts @@ -33,7 +33,7 @@ import { describe, it, expect } from 'vitest'; // from `@objectstack/metadata-core` rather than `@objectstack/objectql` // (which re-exports it): objectql depends on this side of the graph, so that // import would close a cycle turbo rejects outright. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { MetadataManager } from '@objectstack/metadata'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { HttpDispatcher } from '../http-dispatcher.js'; @@ -89,6 +89,7 @@ function makeStubEngine() { const engine: any = { async findOne(table: string, opts: { where: Record }) { + assertEngineFindOnePredicate(table, opts); if (table === 'sys_metadata_history') return null; return findRow(opts.where)?.row ?? null; }, diff --git a/packages/runtime/src/domains/meta-save-destructive-remedy.test.ts b/packages/runtime/src/domains/meta-save-destructive-remedy.test.ts index 3499504dd82..fcd85cdf7f9 100644 --- a/packages/runtime/src/domains/meta-save-destructive-remedy.test.ts +++ b/packages/runtime/src/domains/meta-save-destructive-remedy.test.ts @@ -69,7 +69,7 @@ */ import { describe, it, expect } from 'vitest'; -import { assertEngineUpdateDispatch, assertEngineDeleteDispatch } from '@objectstack/metadata-core'; +import { assertEngineUpdateDispatch, assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { HttpDispatcher } from '../http-dispatcher.js'; @@ -152,6 +152,7 @@ function boot() { return [...rows.values()].filter((r) => match(r, o?.where ?? {})); }, async findOne(table: string, o: { where: Record }) { + assertEngineFindOnePredicate(table, o); if (table !== 'sys_metadata') return null; for (const r of rows.values()) if (match(r, o?.where ?? {})) return r; return null; diff --git a/packages/runtime/src/meta-compound-arity-mint-door.test.ts b/packages/runtime/src/meta-compound-arity-mint-door.test.ts index 2785baa494a..a249d2af571 100644 --- a/packages/runtime/src/meta-compound-arity-mint-door.test.ts +++ b/packages/runtime/src/meta-compound-arity-mint-door.test.ts @@ -46,7 +46,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; // [#5619] The producer's OWN write-verb dispatch decisions, so this double // cannot accept a call the real ObjectQL engine would refuse. Imported from // `@objectstack/metadata-core` and never `@objectstack/objectql`. -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { HttpDispatcher } from './http-dispatcher.js'; import type { HttpDispatcherResult } from './http-dispatcher.js'; @@ -130,6 +130,7 @@ function makeEngine() { return tableOf(table).filter((r) => matches(r, opts?.where)); }, async findOne(table: string, opts?: { where?: Record }) { + assertEngineFindOnePredicate(table, opts); return tableOf(table).find((r) => matches(r, opts?.where)) ?? null; }, async insert(table: string, data: Record) { diff --git a/packages/runtime/src/meta-field-overlay-lock.test.ts b/packages/runtime/src/meta-field-overlay-lock.test.ts index 590d1c40f0c..9bc3c5be745 100644 --- a/packages/runtime/src/meta-field-overlay-lock.test.ts +++ b/packages/runtime/src/meta-field-overlay-lock.test.ts @@ -98,7 +98,7 @@ */ import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { HttpDispatcher } from './http-dispatcher.js'; import type { HttpDispatcherResult } from './http-dispatcher.js'; @@ -281,6 +281,7 @@ function makeEngine() { return tableOf(table).filter((r) => matches(r, opts?.where)); }, async findOne(table: string, opts?: { where?: Record }) { + assertEngineFindOnePredicate(table, opts); return tableOf(table).find((r) => matches(r, opts?.where)) ?? null; }, async insert(table: string, data: Record) { diff --git a/packages/runtime/src/meta-overlay-read-your-writes.test.ts b/packages/runtime/src/meta-overlay-read-your-writes.test.ts index 92addbca464..13e5f1dd011 100644 --- a/packages/runtime/src/meta-overlay-read-your-writes.test.ts +++ b/packages/runtime/src/meta-overlay-read-your-writes.test.ts @@ -45,7 +45,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { ObjectStackProtocolImplementation, resetEnvWritableMetadataTypes } from '@objectstack/metadata-protocol'; -import { SchemaRegistry, assertEngineUpdateDispatch, assertEngineDeleteDispatch } from '@objectstack/objectql'; +import { SchemaRegistry, assertEngineUpdateDispatch, assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { resolveRouteActionDeclaration, type ActionExecutionDeps } from './action-execution.js'; /** @@ -65,7 +65,7 @@ function makeEngine(registry: SchemaRegistry) { const engine: any = { registry, find: vi.fn(async (_table: string, opts: any) => rows.filter((r) => matches(r, opts?.where ?? {}))), - findOne: vi.fn(async (table: string, opts: any) => (await engine.find(table, opts))[0] ?? null), + findOne: vi.fn(async (table: string, opts: any) => { assertEngineFindOnePredicate(table, opts); return (await engine.find(table, opts))[0] ?? null; }), insert: vi.fn(async (_table: string, data: any) => { const row = { id: data.id ?? `row_${nextId++}`, ...data }; rows.push(row); diff --git a/packages/runtime/src/meta-write-org-scope.test.ts b/packages/runtime/src/meta-write-org-scope.test.ts index 1ee53bded22..54c732a023a 100644 --- a/packages/runtime/src/meta-write-org-scope.test.ts +++ b/packages/runtime/src/meta-write-org-scope.test.ts @@ -68,7 +68,7 @@ import { // REST `/meta` write doors share it. This suite still drives the DISPATCHER // through the real stack — that is why it stays in this package. declaresOrgOverride, - organizationIdForMetaWrite, + organizationIdForMetaWrite, assertEngineFindOnePredicate, } from '@objectstack/metadata-core'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel'; @@ -161,6 +161,7 @@ function makeEngine() { return tableOf(table).filter((r) => matches(r, opts?.where)); }, async findOne(table: string, opts?: { where?: Record }) { + assertEngineFindOnePredicate(table, opts); return tableOf(table).find((r) => matches(r, opts?.where)) ?? null; }, async insert(table: string, data: Record) { diff --git a/packages/runtime/src/seed-loader.test.ts b/packages/runtime/src/seed-loader.test.ts index 6d5ce022f7b..48d49847606 100644 --- a/packages/runtime/src/seed-loader.test.ts +++ b/packages/runtime/src/seed-loader.test.ts @@ -4,7 +4,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; import type { SeedLoaderRequest, SeedLoaderConfig } from '@objectstack/spec/data'; -import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; // ========================================================================== // Mock Helpers @@ -41,6 +41,7 @@ function createMockEngine(data: Record = {}): IDataEngine { return records; }), findOne: vi.fn(async (objectName: string, query?: any) => { + assertEngineFindOnePredicate(objectName, query); const results = await (store[objectName] || []); return results[0] || null; }), diff --git a/packages/services/service-automation/src/builtin/crud-bulk-intent.test.ts b/packages/services/service-automation/src/builtin/crud-bulk-intent.test.ts index 7886b2740a6..10c26eacfc3 100644 --- a/packages/services/service-automation/src/builtin/crud-bulk-intent.test.ts +++ b/packages/services/service-automation/src/builtin/crud-bulk-intent.test.ts @@ -43,7 +43,7 @@ */ import { describe, it, expect, beforeEach } from 'vitest'; -import { assertEngineDeleteDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { AutomationEngine } from '../engine.js'; import { registerCrudNodes } from './crud-nodes.js'; @@ -82,7 +82,7 @@ function pinnedFakeData() { const calls: { update?: any; delete?: any } = {}; const service = { find: async (_object: string, options: any) => rows.filter((r) => matches(r, options?.where)), - findOne: async (_object: string, options: any) => rows.find((r) => matches(r, options?.where)) ?? null, + findOne: async (_object: string, options: any) => { assertEngineFindOnePredicate(_object, options); return rows.find((r) => matches(r, options?.where)) ?? null; }, insert: async (_object: string, data: any) => ({ id: 'new', ...data }), update: async (_object: string, data: any, options: any) => { calls.update = options; diff --git a/packages/services/service-automation/src/builtin/crud-config-aliases.test.ts b/packages/services/service-automation/src/builtin/crud-config-aliases.test.ts index 5716e84afae..3c796fc7d7f 100644 --- a/packages/services/service-automation/src/builtin/crud-config-aliases.test.ts +++ b/packages/services/service-automation/src/builtin/crud-config-aliases.test.ts @@ -23,6 +23,7 @@ import { describe, it, expect } from 'vitest'; import { normalizeStackInput } from '@objectstack/spec'; import { AutomationEngine } from '../engine.js'; import { registerCrudNodes } from './crud-nodes.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; function silentLogger(): any { const l: any = { info() {}, warn() {}, error() {}, debug() {} }; @@ -34,7 +35,8 @@ function fakeData() { const calls: Array<{ op: string; obj: string; opts?: any }> = []; const data: any = { async find(obj: string, opts: any) { calls.push({ op: 'find', obj, opts }); return [{ id: 'r1' }]; }, - async findOne(obj: string, opts: any) { calls.push({ op: 'findOne', obj, opts }); return { id: 'r1' }; }, + async findOne(obj: string, opts: any) { + assertEngineFindOnePredicate(obj, opts); calls.push({ op: 'findOne', obj, opts }); return { id: 'r1' }; }, async insert(obj: string, fields: any) { calls.push({ op: 'insert', obj, opts: { fields } }); return { id: `${obj}_1`, ...fields }; }, async update(obj: string, fields: any, opts: any) { calls.push({ op: 'update', obj, opts: { ...opts, fields } }); return { ok: true }; }, async delete(obj: string, opts: any) { calls.push({ op: 'delete', obj, opts }); return { ok: true }; }, diff --git a/packages/services/service-automation/src/builtin/crud-filter-guard.test.ts b/packages/services/service-automation/src/builtin/crud-filter-guard.test.ts index cfe292cb2b9..509031c8c81 100644 --- a/packages/services/service-automation/src/builtin/crud-filter-guard.test.ts +++ b/packages/services/service-automation/src/builtin/crud-filter-guard.test.ts @@ -4,6 +4,7 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { AutomationEngine } from '../engine.js'; import { registerCrudNodes } from './crud-nodes.js'; import { interpolateFilter } from './template.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * framework#3810 — a flow filter must never silently widen. @@ -30,7 +31,8 @@ function fakeData() { const seen: { find?: any; update?: any; delete?: any } = {}; const service = { find: async (_o: string, q: any) => { seen.find = q.where; return []; }, - findOne: async (_o: string, q: any) => { seen.find = q.where; return null; }, + findOne: async (_o: string, q: any) => { + assertEngineFindOnePredicate(_o, q); seen.find = q.where; return null; }, update: async (_o: string, _d: any, o: any) => { seen.update = o?.where; return { modified: 1 }; }, delete: async (_o: string, o: any) => { seen.delete = o?.where; return { deleted: 1 }; }, getObject: () => ({ name: 'deal', fields: {} }), diff --git a/packages/services/service-automation/src/builtin/crud-output-var.test.ts b/packages/services/service-automation/src/builtin/crud-output-var.test.ts index a8042613600..dd541202d82 100644 --- a/packages/services/service-automation/src/builtin/crud-output-var.test.ts +++ b/packages/services/service-automation/src/builtin/crud-output-var.test.ts @@ -9,6 +9,7 @@ import { describe, it, expect } from 'vitest'; import { AutomationEngine } from '../engine.js'; import { registerCrudNodes } from './crud-nodes.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; function makeLogger(): any { const l: any = { info() {}, warn() {}, error() {}, debug() {} }; @@ -23,7 +24,8 @@ function fakeData() { async insert(obj: string, fields: any) { n += 1; return { id: `${obj}_${n}`, ...fields }; }, async update(obj: string, fields: any, opts: any) { updates.push({ obj, fields, opts }); return { ok: true }; }, async find() { return []; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, }; return { data, updates }; } diff --git a/packages/services/service-automation/src/builtin/crud-runas.test.ts b/packages/services/service-automation/src/builtin/crud-runas.test.ts index e88ec563ba0..ecbc8dfba56 100644 --- a/packages/services/service-automation/src/builtin/crud-runas.test.ts +++ b/packages/services/service-automation/src/builtin/crud-runas.test.ts @@ -21,6 +21,7 @@ import { UnscopedRunDataAccessError, } from '../runtime-identity.js'; import type { AutomationContext } from '@objectstack/spec/contracts'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; function makeLogger(): any { const l: any = { info() {}, warn() {}, error() {}, debug() {} }; @@ -33,7 +34,8 @@ function fakeData() { const calls: Array<{ op: string; obj: string; ctx: any }> = []; const data: any = { async find(obj: string, q: any) { calls.push({ op: 'find', obj, ctx: q?.context }); return [{ id: 'r1' }]; }, - async findOne(obj: string, q: any) { calls.push({ op: 'findOne', obj, ctx: q?.context }); return { id: 'r1' }; }, + async findOne(obj: string, q: any) { + assertEngineFindOnePredicate(obj, q); calls.push({ op: 'findOne', obj, ctx: q?.context }); return { id: 'r1' }; }, async insert(obj: string, _f: any, opts: any) { calls.push({ op: 'insert', obj, ctx: opts?.context }); return { id: `${obj}_1` }; }, async update(obj: string, _f: any, opts: any) { calls.push({ op: 'update', obj, ctx: opts?.context }); return { ok: true }; }, async delete(obj: string, opts: any) { calls.push({ op: 'delete', obj, ctx: opts?.context }); return { ok: true }; }, diff --git a/packages/services/service-automation/src/builtin/notify-organization-stamp.integration.test.ts b/packages/services/service-automation/src/builtin/notify-organization-stamp.integration.test.ts index f404afa4b10..8849129ca80 100644 --- a/packages/services/service-automation/src/builtin/notify-organization-stamp.integration.test.ts +++ b/packages/services/service-automation/src/builtin/notify-organization-stamp.integration.test.ts @@ -12,6 +12,7 @@ import { import { AutomationEngine } from '../engine.js'; import { registerNotifyNode } from './notify-node.js'; import type { MessagingServiceSurface } from './notify-node.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** * [#11303] The `notify` node is the producer that decides whether the whole @@ -76,7 +77,8 @@ function capturingEngine(): { engine: any; written: WrittenRow[] } { return { ...row, id }; }, async find() { return []; }, - async findOne() { return undefined; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return undefined; }, }; return { engine, written }; } diff --git a/packages/services/service-automation/src/record-lookup-expand.integration.test.ts b/packages/services/service-automation/src/record-lookup-expand.integration.test.ts index 184f79daa09..511b37c5332 100644 --- a/packages/services/service-automation/src/record-lookup-expand.integration.test.ts +++ b/packages/services/service-automation/src/record-lookup-expand.integration.test.ts @@ -17,6 +17,7 @@ import { describe, it, expect } from 'vitest'; import { LiteKernel } from '@objectstack/core'; import { AutomationServicePlugin } from './plugin.js'; import { AutomationEngine } from './engine.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; interface CrudCall { op: string; obj: string; ctx: any; expand?: any; fields?: any } @@ -33,6 +34,7 @@ function fakeObjectQl(opts: { throwOnFindOne?: boolean } = {}) { const engine: any = { async find(object: string, o: any) { crud.push({ op: 'find', obj: object, ctx: o?.context }); return []; }, async findOne(object: string, o: any) { + assertEngineFindOnePredicate(object, o); crud.push({ op: 'findOne', obj: object, ctx: o?.context, expand: o?.expand }); if (opts.throwOnFindOne) throw new Error('boom'); return object === 'lead' ? { ...LEAD } : undefined; diff --git a/packages/services/service-automation/src/run-summary.test.ts b/packages/services/service-automation/src/run-summary.test.ts index e6251dbaf8a..62f09791044 100644 --- a/packages/services/service-automation/src/run-summary.test.ts +++ b/packages/services/service-automation/src/run-summary.test.ts @@ -8,7 +8,7 @@ // all read. import { describe, it, expect } from 'vitest'; -import { assertEngineDeleteDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/objectql'; import { AutomationEngine } from './engine.js'; import type { StepLogEntry, NodeExecutor, RunRecord } from './engine.js'; import { summarizeRun, formatRunSummaryLine } from './run-summary.js'; @@ -200,7 +200,8 @@ function sweepEngine(rows: Array>, logger = makeLogger() let seq = 0; const data: any = { async find() { return rows; }, - async findOne() { return rows[0] ?? null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return rows[0] ?? null; }, async insert(obj: string, fields: any) { seq += 1; const r = { id: `${obj}_${seq}`, ...fields }; written.push(r); return r; }, async update() { return 0; }, async delete() { return 0; }, @@ -396,7 +397,8 @@ describe('node executors report what they touched', () => { const logger = makeLogger(); const data: any = { async find() { return []; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async insert(_o: string, f: any) { return { id: 'x', ...f }; }, async update() { return 7; }, // driver.updateMany contract: Promise async delete() { return 0; }, @@ -501,7 +503,8 @@ describe('node executors report what they touched', () => { const written: any[] = []; const data: any = { async find() { return []; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async insert(o: string, f: any) { const r = { id: `${o}_1`, ...f }; written.push(r); return r; }, }; const ctx: any = { logger, getService: (n: string) => (n === 'data' ? data : undefined) }; @@ -544,7 +547,8 @@ describe('map rolls its per-item child runs up', () => { const written: any[] = []; const data: any = { async find() { return []; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async insert(o: string, f: any) { const r = { id: `${o}_${written.length + 1}`, ...f }; written.push(r); return r; }, }; const ctx: any = { logger, getService: (n: string) => (n === 'data' ? data : undefined) }; @@ -594,7 +598,8 @@ describe('a child run that PAUSED still counts toward its parent', () => { const written: any[] = []; const data: any = { async find() { return []; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async insert(o: string, f: any) { const r = { id: `${o}_${written.length + 1}`, ...f }; written.push(r); return r; }, }; const ctx: any = { logger, getService: (n: string) => (n === 'data' ? data : undefined) }; diff --git a/packages/services/service-automation/src/runas-grant-resolution.integration.test.ts b/packages/services/service-automation/src/runas-grant-resolution.integration.test.ts index fc55d8fda25..c0b2c886744 100644 --- a/packages/services/service-automation/src/runas-grant-resolution.integration.test.ts +++ b/packages/services/service-automation/src/runas-grant-resolution.integration.test.ts @@ -18,6 +18,7 @@ import { describe, it, expect } from 'vitest'; import { LiteKernel } from '@objectstack/core'; import { AutomationServicePlugin } from './plugin.js'; import { AutomationEngine } from './engine.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * A fake ObjectQL engine that both serves the authz tables (for grant @@ -35,7 +36,8 @@ function fakeObjectQl(tables: Record) { ); const engine: any = { async find(object: string, opts: any) { crud.push({ op: 'find', obj: object, ctx: opts?.context }); return match(object, opts?.where); }, - async findOne(object: string, opts: any) { crud.push({ op: 'findOne', obj: object, ctx: opts?.context }); return match(object, opts?.where)[0]; }, + async findOne(object: string, opts: any) { + assertEngineFindOnePredicate(object, opts); crud.push({ op: 'findOne', obj: object, ctx: opts?.context }); return match(object, opts?.where)[0]; }, async insert(object: string, _f: any, opts: any) { crud.push({ op: 'insert', obj: object, ctx: opts?.context }); return { id: `${object}_1` }; }, async update(object: string, _f: any, opts: any) { crud.push({ op: 'update', obj: object, ctx: opts?.context }); return { ok: true }; }, async delete(object: string, opts: any) { crud.push({ op: 'delete', obj: object, ctx: opts?.context }); return { ok: true }; }, diff --git a/packages/services/service-datasource/package.json b/packages/services/service-datasource/package.json index a2a42d714e9..b070dde9473 100644 --- a/packages/services/service-datasource/package.json +++ b/packages/services/service-datasource/package.json @@ -36,6 +36,7 @@ "@objectstack/driver-mongodb": "workspace:*", "@objectstack/driver-sql": "workspace:*", "@objectstack/driver-sqlite-wasm": "workspace:*", + "@objectstack/metadata-core": "workspace:*", "@objectstack/plugin-hono-server": "workspace:*", "@types/node": "^26.2.0", "tsup": "^8.5.1", diff --git a/packages/services/service-datasource/src/__tests__/datasource-admin-plugin.test.ts b/packages/services/service-datasource/src/__tests__/datasource-admin-plugin.test.ts index 8d4fab9c7e9..09ed5ff535f 100644 --- a/packages/services/service-datasource/src/__tests__/datasource-admin-plugin.test.ts +++ b/packages/services/service-datasource/src/__tests__/datasource-admin-plugin.test.ts @@ -14,6 +14,7 @@ import { // `scripts/check-test-source-alias.mjs` (the clocked-window rule) and #10115 / PR #10120, // where the same shape cost 30 ejected merge-queue builds in one night. import '@objectstack/spec/kernel'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * Minimal PluginContext + in-memory metadata service. Boots the plugin and @@ -321,6 +322,7 @@ describe('DatasourceAdminServicePlugin: runtime datasource durability', () => { registerDatasourceDef() {}, getDriverByName() { return undefined; }, findOne: async (_o: string, q: { where?: Record }) => { + assertEngineFindOnePredicate(_o, q); const w = q.where ?? {}; return rows.find((r) => Object.entries(w).every(([k, v]) => { if (k.startsWith('$')) throw new Error(`fake driver: unsupported operator ${k}`); return r[k] === v; })); }, diff --git a/packages/services/service-messaging/src/delivery-headers-at-rest.integration.test.ts b/packages/services/service-messaging/src/delivery-headers-at-rest.integration.test.ts index feffb3e028e..0648abb3495 100644 --- a/packages/services/service-messaging/src/delivery-headers-at-rest.integration.test.ts +++ b/packages/services/service-messaging/src/delivery-headers-at-rest.integration.test.ts @@ -47,7 +47,7 @@ import { describe, it, expect, afterEach } from 'vitest'; import { createHmac } from 'node:crypto'; -import { ObjectQL, assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { ObjectQL, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { SqlDriver } from '@objectstack/driver-sql'; import type { IDataEngine } from '@objectstack/spec/contracts'; import { SqlHttpOutbox } from './sql-http-outbox.js'; @@ -288,7 +288,7 @@ describe('sys_http_delivery — authored headers vs the data API (#8118)', () => // its authored configuration. const noAccessor = { find: (o: string, q: unknown) => (eng as any).find(o, q), - findOne: (o: string, q: unknown) => (eng as any).findOne(o, q), + findOne: (o: string, q: unknown) => { assertEngineFindOnePredicate(o, q); return (eng as any).findOne(o, q); }, insert: (o: string, d: unknown) => (eng as any).insert(o, d), update: (o: string, d: unknown, q: unknown) => { // Engine-double contract: this fake's update() must be exactly diff --git a/packages/services/service-messaging/src/email-channel.test.ts b/packages/services/service-messaging/src/email-channel.test.ts index f531e3a2094..284d7fa430f 100644 --- a/packages/services/service-messaging/src/email-channel.test.ts +++ b/packages/services/service-messaging/src/email-channel.test.ts @@ -4,6 +4,7 @@ import { describe, it, expect } from 'vitest'; import { createEmailChannel } from './email-channel.js'; import { NotificationTemplateStore } from './template-renderer.js'; import type { Delivery } from './channel.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; function silentCtx() { return { logger: { info: () => {}, warn: () => {}, error: () => {} } }; @@ -32,6 +33,7 @@ function fakeData(opts: { users?: Record; templates?: any[] } = const templates = opts.templates ?? []; return { async findOne(object: string, query: any) { + assertEngineFindOnePredicate(object, query); const w = query?.where ?? {}; if (object === 'sys_user') { const email = users[String(w.id)]; diff --git a/packages/services/service-messaging/src/inbox-channel.test.ts b/packages/services/service-messaging/src/inbox-channel.test.ts index fcff1912fdb..7390e5dc120 100644 --- a/packages/services/service-messaging/src/inbox-channel.test.ts +++ b/packages/services/service-messaging/src/inbox-channel.test.ts @@ -3,6 +3,7 @@ import { describe, it, expect } from 'vitest'; import { createInboxChannel, INBOX_OBJECT, RECEIPT_OBJECT } from './inbox-channel.js'; import type { Delivery } from './channel.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; function silentCtx() { return { logger: { info: () => {}, warn: () => {}, error: () => {} } }; @@ -41,6 +42,7 @@ function fakeData( }, async find() { return []; }, async findOne(object: string, query: any) { + assertEngineFindOnePredicate(object, query); findOnes.push({ object, query }); return findOneImpl ? findOneImpl(object, query) : null; }, diff --git a/packages/services/service-messaging/src/messaging-service-plugin.test.ts b/packages/services/service-messaging/src/messaging-service-plugin.test.ts index 86f015a49f1..c97371ccd7e 100644 --- a/packages/services/service-messaging/src/messaging-service-plugin.test.ts +++ b/packages/services/service-messaging/src/messaging-service-plugin.test.ts @@ -3,6 +3,7 @@ import { describe, it, expect } from 'vitest'; import { MessagingServicePlugin } from './messaging-service-plugin.js'; import type { MessagingService } from './messaging-service.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; /** * A lightweight fake PluginContext — enough surface for the plugin's init(): @@ -26,7 +27,8 @@ function fakeCtx() { return { id: `row_${inserts.length}`, ...row }; }, async find() { return []; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async update() { return {}; }, async delete() { return {}; }, }); @@ -109,7 +111,8 @@ function provisionCtx() { return [] as unknown[]; }, async insert() { return {}; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async update() { return {}; }, async delete() { return {}; }, }; diff --git a/packages/services/service-messaging/src/messaging-service.test.ts b/packages/services/service-messaging/src/messaging-service.test.ts index 32c22880041..e85f405327e 100644 --- a/packages/services/service-messaging/src/messaging-service.test.ts +++ b/packages/services/service-messaging/src/messaging-service.test.ts @@ -5,6 +5,7 @@ import { MessagingService } from './messaging-service.js'; import { InboxCallerError } from './inbox-caller.js'; import { MemoryNotificationOutbox } from './memory-outbox.js'; import type { Delivery, MessagingChannel, SendResult } from './channel.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; function silentLogger() { return { info: () => {}, warn: () => {}, error: () => {} }; @@ -42,6 +43,7 @@ function fakeData(findOneImpl?: (obj: string, q: any) => any) { }, async find() { return []; }, async findOne(object: string, query: any) { + assertEngineFindOnePredicate(object, query); findOnes.push({ object, query }); return findOneImpl ? findOneImpl(object, query) : null; }, @@ -182,7 +184,8 @@ describe('MessagingService', () => { if (object === 'sys_team_member') return [{ user_id: 'u_sales' }]; return []; }, - async findOne(object: string) { + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return object === 'lead' ? { id: 'l1', owner_id: 'u_owner' } : null; }, async update() { return {}; }, @@ -236,7 +239,8 @@ describe('MessagingService', () => { } return []; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async update() { return {}; }, async delete() { return {}; }, async count() { return 0; }, @@ -390,7 +394,8 @@ describe('MessagingService', () => { return { id: 'row' }; }, async find() { return []; }, - async findOne(object: string) { + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); if (object !== 'sys_notification') return null; // First call = the fast-path miss; second = post-conflict lookup finds the winner. if (firstLookup) { firstLookup = false; return null; } @@ -422,7 +427,8 @@ describe('MessagingService', () => { const engine = { async insert() { throw new Error('disk full'); }, async find() { return []; }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async update() { return {}; }, async delete() { return {}; }, async count() { return 0; }, @@ -465,6 +471,7 @@ function inboxEngine(seed: { inbox?: any[]; receipts?: any[] } = {}) { return typeof query.limit === 'number' ? rows.slice(0, query.limit) : rows; }, async findOne(object: string, query: any = {}) { + assertEngineFindOnePredicate(object, query); return (store[object] ?? []).find((r) => matches(r, query.where)) ?? null; }, async insert(object: string, row: any) { diff --git a/packages/services/service-messaging/src/notification-schema-conformance.test.ts b/packages/services/service-messaging/src/notification-schema-conformance.test.ts index ba56ef30d10..8b699b04b50 100644 --- a/packages/services/service-messaging/src/notification-schema-conformance.test.ts +++ b/packages/services/service-messaging/src/notification-schema-conformance.test.ts @@ -52,7 +52,7 @@ // actually receives in production. import { describe, it, expect } from 'vitest'; -import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; +import { assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core'; import { ListNotificationsResponseSchema, MarkNotificationsReadResponseSchema, @@ -120,6 +120,7 @@ function inboxEngine() { return typeof query.limit === 'number' ? rows.slice(0, query.limit) : rows; }, async findOne(object: string, query: any = {}) { + assertEngineFindOnePredicate(object, query); return (store[object] ?? []).find((r) => matches(r, query.where)) ?? null; }, async insert(object: string, row: any) { diff --git a/packages/services/service-messaging/src/preference-resolver.test.ts b/packages/services/service-messaging/src/preference-resolver.test.ts index f2c3df710b1..451830ee34d 100644 --- a/packages/services/service-messaging/src/preference-resolver.test.ts +++ b/packages/services/service-messaging/src/preference-resolver.test.ts @@ -2,6 +2,7 @@ import { describe, it, expect } from 'vitest'; import { PreferenceResolver, quietHoursDeferral, digestDeferral } from './preference-resolver.js'; +import { assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core'; function silentLogger() { return { info: () => {}, warn: () => {}, error: () => {} }; @@ -26,7 +27,8 @@ function fakeData(rows: any[] = [], opts: { throwOnFind?: boolean } = {}) { (w.organization_id == null || r.organization_id === w.organization_id), ); }, - async findOne() { return null; }, + async findOne(object: string, query?: EngineFindOneQueryInput) { + assertEngineFindOnePredicate(object, query); return null; }, async insert(_o: string, r: any) { return { id: 'x', ...r }; }, async update() { return {}; }, async delete() { return {}; }, diff --git a/packages/services/service-messaging/src/read-receipt-organization.test.ts b/packages/services/service-messaging/src/read-receipt-organization.test.ts index 62e0926b15e..b3e9f500918 100644 --- a/packages/services/service-messaging/src/read-receipt-organization.test.ts +++ b/packages/services/service-messaging/src/read-receipt-organization.test.ts @@ -3,6 +3,7 @@ import { describe, it, expect } from 'vitest'; import { MessagingService, NOTIFICATION_EVENT_OBJECT } from './messaging-service.js'; import { RECEIPT_OBJECT } from './inbox-channel.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * [#11303] The SECOND `sys_notification_receipt` producer. @@ -44,6 +45,7 @@ function engineWithNotification(notificationOrg: string | null) { return { ...row, id: 'rec_1' }; }, async findOne(object: string, opts: any) { + assertEngineFindOnePredicate(object, opts); if (object === NOTIFICATION_EVENT_OBJECT) { return { id: 'evt_pin', organization_id: notificationOrg }; } diff --git a/packages/services/service-messaging/src/recipient-resolver.test.ts b/packages/services/service-messaging/src/recipient-resolver.test.ts index ea7d79fec98..59f69c025cc 100644 --- a/packages/services/service-messaging/src/recipient-resolver.test.ts +++ b/packages/services/service-messaging/src/recipient-resolver.test.ts @@ -2,6 +2,7 @@ import { describe, it, expect } from 'vitest'; import { RecipientResolver } from './recipient-resolver.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; function silentLogger() { return { warn: () => {}, info: () => {} }; @@ -36,6 +37,7 @@ function fakeData(opts: { return []; }, async findOne(object: string, query: any) { + assertEngineFindOnePredicate(object, query); calls.push({ method: 'findOne', object, query }); if (object === opts.throwOn) throw new Error('locked'); if (object === 'sys_user') { diff --git a/packages/services/service-messaging/src/sms-channel.test.ts b/packages/services/service-messaging/src/sms-channel.test.ts index 2ca457054ef..67adb3f2922 100644 --- a/packages/services/service-messaging/src/sms-channel.test.ts +++ b/packages/services/service-messaging/src/sms-channel.test.ts @@ -4,6 +4,7 @@ import { describe, it, expect } from 'vitest'; import { createSmsChannel } from './sms-channel.js'; import { NotificationTemplateStore } from './template-renderer.js'; import type { Delivery } from './channel.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; function silentCtx() { return { logger: { info: () => {}, warn: () => {}, error: () => {} } }; @@ -32,6 +33,7 @@ function fakeData(opts: { users?: Record; templates?: any[] } = const templates = opts.templates ?? []; return { async findOne(object: string, query: any) { + assertEngineFindOnePredicate(object, query); const w = query?.where ?? {}; if (object === 'sys_user') { const phone = users[String(w.id)]; diff --git a/packages/services/service-messaging/src/sql-outbox-audit-columns.test.ts b/packages/services/service-messaging/src/sql-outbox-audit-columns.test.ts index c25802ca701..12072720d2d 100644 --- a/packages/services/service-messaging/src/sql-outbox-audit-columns.test.ts +++ b/packages/services/service-messaging/src/sql-outbox-audit-columns.test.ts @@ -20,6 +20,7 @@ import { describe, it, expect } from 'vitest'; import type { IDataEngine } from '@objectstack/spec/contracts'; import { SqlNotificationOutbox } from './sql-outbox.js'; import { SqlHttpOutbox } from './sql-http-outbox.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; interface RecordedUpdate { object: string; @@ -65,6 +66,7 @@ function makeEngine(findResults: Array>> = []) { return findResults[findCall++] ?? []; }, async findOne(_object: string, opts?: { fields?: string[] }) { + assertEngineFindOnePredicate(_object, opts); // `ack()` reads the row it is completing; `enqueue()` probes for a // dedup winner and must miss so the insert path runs. if (opts?.fields?.includes('attempts')) return { ...row }; diff --git a/packages/services/service-messaging/src/template-renderer.test.ts b/packages/services/service-messaging/src/template-renderer.test.ts index d3feb615344..b8efd1f4487 100644 --- a/packages/services/service-messaging/src/template-renderer.test.ts +++ b/packages/services/service-messaging/src/template-renderer.test.ts @@ -6,6 +6,7 @@ import { renderNotification, NotificationTemplateStore, } from './template-renderer.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; describe('interpolate', () => { it('substitutes {{ path.to.value }} from the context, linearly', () => { @@ -69,6 +70,7 @@ describe('NotificationTemplateStore', () => { queries, engine: { async findOne(object: string, query: any) { + assertEngineFindOnePredicate(object, query); queries.push({ object, where: query?.where }); const w = query?.where ?? {}; return ( diff --git a/packages/services/service-storage/src/attachment-access-hooks.test.ts b/packages/services/service-storage/src/attachment-access-hooks.test.ts index e103447b228..4a3117fe77b 100644 --- a/packages/services/service-storage/src/attachment-access-hooks.test.ts +++ b/packages/services/service-storage/src/attachment-access-hooks.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, vi } from 'vitest'; -import { ObjectQL } from '@objectstack/objectql'; +import { ObjectQL, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { installAttachmentAccessHooks, type AttachmentSharingLike } from './attachment-access-hooks.js'; import type { AttachmentLifecycleEngine } from './attachment-lifecycle.js'; @@ -24,9 +24,9 @@ function install(opts: { return typeof options?.limit === 'number' ? rows.slice(0, options.limit) : rows; }, findOne: async (_object, options: any) => - (opts.attachments ?? []).find((r) => + { assertEngineFindOnePredicate(_object, options); return (opts.attachments ?? []).find((r) => Object.entries(options?.where ?? {}).every(([k, v]) => { if (k.startsWith('$')) throw new Error(`fake driver: unsupported operator ${k}`); return r[k] === v; }), - ) ?? null, + ) ?? null; }, update: async () => ({}), }; installAttachmentAccessHooks(engine, () => opts.sharing, silentLogger()); diff --git a/packages/services/service-storage/src/attachment-lifecycle.test.ts b/packages/services/service-storage/src/attachment-lifecycle.test.ts index cc9d6b6d48c..5113a2b3480 100644 --- a/packages/services/service-storage/src/attachment-lifecycle.test.ts +++ b/packages/services/service-storage/src/attachment-lifecycle.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { describe, it, expect, vi } from 'vitest'; -import { ObjectQL } from '@objectstack/objectql'; +import { ObjectQL, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { installAttachmentLifecycleHooks, createSysFileReapGuard, @@ -51,6 +51,7 @@ function fakeEngine(seed: { return typeof options?.limit === 'number' ? rows.slice(0, options.limit) : rows; }, async findOne(object, options: any) { + assertEngineFindOnePredicate(object, options); return tables[object].find((r) => matches(r, options?.where ?? {})) ?? null; }, async update(object, data: any, _options) { diff --git a/packages/services/service-storage/src/file-reference-lifecycle.test.ts b/packages/services/service-storage/src/file-reference-lifecycle.test.ts index e2526bf9ab9..b10a3ddea09 100644 --- a/packages/services/service-storage/src/file-reference-lifecycle.test.ts +++ b/packages/services/service-storage/src/file-reference-lifecycle.test.ts @@ -8,6 +8,7 @@ import { FileFieldBulkWriteError, type FileReferenceEngine, } from './file-reference-lifecycle.js'; +import { assertEngineFindOnePredicate } from '@objectstack/objectql'; const silentLogger = () => ({ info: vi.fn(), warn: vi.fn(), debug: vi.fn() }); @@ -74,6 +75,7 @@ function fakeEngine(opts: { return typeof options?.limit === 'number' ? rows.slice(0, options.limit) : rows; }, async findOne(object, options: any) { + assertEngineFindOnePredicate(object, options); calls.push({ op: 'findOne', object, arg: options?.where }); return (tables[object] ?? []).find((r) => matches(r, options?.where ?? {})) ?? null; }, diff --git a/packages/services/service-storage/src/lax-deviation-reclamation-gate.test.ts b/packages/services/service-storage/src/lax-deviation-reclamation-gate.test.ts index a023a9457dd..43759159c7a 100644 --- a/packages/services/service-storage/src/lax-deviation-reclamation-gate.test.ts +++ b/packages/services/service-storage/src/lax-deviation-reclamation-gate.test.ts @@ -21,7 +21,7 @@ */ import { describe, it, expect, vi } from 'vitest'; -import { assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { isDataMigrationVerified, mayActIrreversibly, @@ -88,6 +88,7 @@ function reapEngine() { return tables[object].filter((r) => Object.entries(where).every(([k, v]) => { if (k.startsWith('$')) throw new Error(`fake driver: unsupported operator ${k}`); return r[k] === v; })); }, async findOne(object: string, options: any) { + assertEngineFindOnePredicate(object, options); const where = options?.where ?? {}; return tables[object].find((r) => Object.entries(where).every(([k, v]) => { if (k.startsWith('$')) throw new Error(`fake driver: unsupported operator ${k}`); return r[k] === v; })) ?? null; }, diff --git a/packages/services/service-storage/src/metadata-store.test.ts b/packages/services/service-storage/src/metadata-store.test.ts index 80fc683395f..844521a5fc7 100644 --- a/packages/services/service-storage/src/metadata-store.test.ts +++ b/packages/services/service-storage/src/metadata-store.test.ts @@ -17,7 +17,7 @@ // returns `null` rather than throwing. import { describe, it, expect } from 'vitest'; -import { assertEngineDeleteDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import type { IDataEngine } from '@objectstack/spec/contracts'; import { StorageMetadataStore, @@ -65,6 +65,7 @@ function createFakeEngine(opts: { failing?: EngineMethod[] } = {}) { return { ...data }; }, async findOne(object: string, query?: any) { + assertEngineFindOnePredicate(object, query); boom('findOne', object); const id = query?.where?.id; return table(object).get(String(id)) ?? null; diff --git a/packages/services/service-storage/src/storage-routes.metadata-outage.test.ts b/packages/services/service-storage/src/storage-routes.metadata-outage.test.ts index b24b6dbf215..f441ff2f787 100644 --- a/packages/services/service-storage/src/storage-routes.metadata-outage.test.ts +++ b/packages/services/service-storage/src/storage-routes.metadata-outage.test.ts @@ -15,7 +15,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import type { IHttpRequest, IHttpResponse, RouteHandler, IDataEngine } from '@objectstack/spec/contracts'; -import { assertEngineDeleteDispatch } from '@objectstack/objectql'; +import { assertEngineDeleteDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { LocalStorageAdapter } from './local-storage-adapter.js'; import { StorageMetadataStore } from './metadata-store.js'; import { registerStorageRoutes } from './storage-routes.js'; @@ -85,6 +85,7 @@ function createFakeEngine(opts: { failing?: EngineMethod[] } = {}) { return { ...data }; }, async findOne(object: string, query?: any) { + assertEngineFindOnePredicate(object, query); boom('findOne', object); return table(object).get(String(query?.where?.id)) ?? null; }, diff --git a/packages/services/service-storage/src/tombstone-download-live-reference.test.ts b/packages/services/service-storage/src/tombstone-download-live-reference.test.ts index ef50e56b530..f7b45b1d3b6 100644 --- a/packages/services/service-storage/src/tombstone-download-live-reference.test.ts +++ b/packages/services/service-storage/src/tombstone-download-live-reference.test.ts @@ -50,7 +50,7 @@ import type { IHttpRequest, IHttpResponse, RouteHandler } from '@objectstack/spe // (`check:engine-double-contract`, #4550/#5480). It declares no `delete`: this // suite never deletes a row, and a verb a double does not need is a contract // it cannot get wrong. -import { assertEngineUpdateDispatch } from '@objectstack/objectql'; +import { assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/objectql'; import { LocalStorageAdapter } from './local-storage-adapter.js'; import { StorageMetadataStore } from './metadata-store.js'; import { registerStorageRoutes } from './storage-routes.js'; @@ -117,6 +117,7 @@ function fakeEngine(seed: { return typeof options?.limit === 'number' ? rows.slice(0, options.limit) : rows; }, async findOne(object: string, options: any) { + assertEngineFindOnePredicate(object, options); return (tables[object] ?? []).find((r) => matches(r, options?.where ?? {})) ?? null; }, async insert(object: string, data: any) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c92abf8061d..53fff4986bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2336,6 +2336,9 @@ importers: '@objectstack/driver-sqlite-wasm': specifier: workspace:* version: link:../../drivers/driver-sqlite-wasm + '@objectstack/metadata-core': + specifier: workspace:* + version: link:../../metadata-core '@objectstack/plugin-hono-server': specifier: workspace:* version: link:../../plugins/plugin-hono-server From 88784b7b7022078ab4e08ed99c0ceddaeeb249c4 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 26 Aug 2026 09:08:07 +0000 Subject: [PATCH 2/3] wip(engine-doubles): recovered uncommitted gate half from a stalled dispatch NOT REVIEWED. The dispatch that wrote this stalled before committing or pushing; this commit exists only so the work survives the container, and the resuming dev is expected to inspect it, not to trust it. Contents as found on disk: the findOne slice added to check-engine-double-contract's SLICES table (assertEngineFindOnePredicate / resolveEngineFindOnePredicate, origin #4419), plus the regenerated baseline and pinned ledgers. No gate run, no test run, and no ablation was performed against it here. --- scripts/check-engine-double-contract.mjs | 12 + scripts/engine-double-contract.baseline.json | 24 +- scripts/engine-double-contract.pinned.json | 1176 +++++++++++++++++- 3 files changed, 1206 insertions(+), 6 deletions(-) diff --git a/scripts/check-engine-double-contract.mjs b/scripts/check-engine-double-contract.mjs index 05918877e5c..e5dbf928a9c 100644 --- a/scripts/check-engine-double-contract.mjs +++ b/scripts/check-engine-double-contract.mjs @@ -385,6 +385,18 @@ const SLICES = [ pinCall: 'assertEngineUpdateDispatch(data, options)', origin: '#5480', }, + { + verb: 'findOne', + producer: 'ObjectQL.findOne', + symbols: new Set(['assertEngineFindOnePredicate', 'resolveEngineFindOnePredicate']), + modules: [ + /^@objectstack\/objectql$/, + /^@objectstack\/metadata-core$/, + /engine-findone-predicate(\.js)?$/, + ], + pinCall: 'assertEngineFindOnePredicate(object, query)', + origin: '#4419', + }, ]; /** The verbs the ledger may name -- see the DECLARED invariant. */ diff --git a/scripts/engine-double-contract.baseline.json b/scripts/engine-double-contract.baseline.json index 918bfa6f29c..123fafbac4a 100644 --- a/scripts/engine-double-contract.baseline.json +++ b/scripts/engine-double-contract.baseline.json @@ -7,8 +7,8 @@ "— so it may accept a call the real engine refuses, which is exactly how #4434 shipped a dead", "REST route with its suite green.", "", - "`verb` is REQUIRED and must name a slice the checker actually scans (currently `delete` and", - "`update` — the DECLARED invariant). It is not defaulted: an entry that inherited a verb would", + "`verb` is REQUIRED and must name a slice the checker actually scans (currently `delete`,", + "`update` and `findOne` — the DECLARED invariant). It is not defaulted: an entry that inherited a verb would", "be an exemption whose scope nobody could read, and the two verbs genuinely differ — see the", "script header on `data.id`, which `update` takes verbatim and `delete` has no analogue for.", "A file may therefore carry two entries, one per verb, and a fake pinned on `delete` earns", @@ -43,7 +43,9 @@ "in one act — there was no producer-side predicate to route through before #5480, so none of", "them could have been pinned however carefully they were written.", "", - "THE #8639 BATCH WAS A FIRST MEASUREMENT, NOT A RAISED RATCHET — AND IT IS NOW CLOSED (#8651). Until #8639 the checker’s `implOf` returned null for a CALL-EXPRESSION initializer, so every engine double spelling its write verb `vi.fn(async …)` — the spelling a test reaches for whenever it wants to assert call counts — was invisible to discovery: not pinned, not ledgered, absent from BOTH sides of a ledger that reconciles in both directions. Teaching `implOf` to unwrap a call whose sole argument is a function moved discovery from 379 doubles to 435 (+56, 0 lost). Of the 93 verb members the fix newly made readable, 56 are engine-shaped and 37 are correctly vetoed as driver / scoped-repository / non-double shapes. 21 of the 56 were PINNED in #8639’s own PR (every one whose pin was a single call). The remaining 29 were carried here as \"MEASURED (#8639)\" entries, each naming why a one-line pin did not reach it — a signature declaring too few parameters to hand the predicate, a deliberate tripwire double whose body opens by throwing, a concise arrow body, or a package depending on neither home of the predicate. #8651 closed all 29: signatures widened, concise bodies converted to blocks, `@objectstack/metadata-core` added as a devDependency of `@objectstack/mcp`, and the genuine tripwires routed through the predicate AHEAD of their throw — so the assertion each one carries (\"this path performs no write at all\") is unchanged: the body still never runs on a passing suite, and a call that did arrive still fails the test, whichever of the two errors it raises. Their entries were deleted in that same PR, which is what SHRINK-ONLY requires of a pin. No entry below carries \"MEASURED (#8639)\" any more. This paragraph is kept because the discovery history it records is what makes the 379 → 435 jump readable to the next author, and because adding entries here normally reads as weakening while that batch was the opposite — the same act #5629 and #5480 each recorded once before." + "THE #8639 BATCH WAS A FIRST MEASUREMENT, NOT A RAISED RATCHET — AND IT IS NOW CLOSED (#8651). Until #8639 the checker’s `implOf` returned null for a CALL-EXPRESSION initializer, so every engine double spelling its write verb `vi.fn(async …)` — the spelling a test reaches for whenever it wants to assert call counts — was invisible to discovery: not pinned, not ledgered, absent from BOTH sides of a ledger that reconciles in both directions. Teaching `implOf` to unwrap a call whose sole argument is a function moved discovery from 379 doubles to 435 (+56, 0 lost). Of the 93 verb members the fix newly made readable, 56 are engine-shaped and 37 are correctly vetoed as driver / scoped-repository / non-double shapes. 21 of the 56 were PINNED in #8639’s own PR (every one whose pin was a single call). The remaining 29 were carried here as \"MEASURED (#8639)\" entries, each naming why a one-line pin did not reach it — a signature declaring too few parameters to hand the predicate, a deliberate tripwire double whose body opens by throwing, a concise arrow body, or a package depending on neither home of the predicate. #8651 closed all 29: signatures widened, concise bodies converted to blocks, `@objectstack/metadata-core` added as a devDependency of `@objectstack/mcp`, and the genuine tripwires routed through the predicate AHEAD of their throw — so the assertion each one carries (\"this path performs no write at all\") is unchanged: the body still never runs on a passing suite, and a call that did arrive still fails the test, whichever of the two errors it raises. Their entries were deleted in that same PR, which is what SHRINK-ONLY requires of a pin. No entry below carries \"MEASURED (#8639)\" any more. This paragraph is kept because the discovery history it records is what makes the 379 → 435 jump readable to the next author, and because adding entries here normally reads as weakening while that batch was the opposite — the same act #5629 and #5480 each recorded once before.", + "", + "THE `findOne` SLICE'S FIRST MEASUREMENT ADDED EXACTLY ONE ROW, AND THAT IS THE POINT (objectstack#12068, the remainder of #11957). The two paragraphs above record slices whose first measurement entered this ledger wholesale \u2014 116 doubles for `update` (#5480), 29 for the #8639 batch \u2014 because the population was past a reviewable diff. `findOne` was measured the same way and came out LARGER than either, 213 files / 254 doubles on origin/main @ 4045b954d3, and it is NOT ledgered: 211 of the 213 were ADOPTED in the slice's own PR. What made the difference is not effort, it is that the adoption is decidable per double \u2014 `assertEngineFindOnePredicate(object, query)` is one line in front of a member every one of those fakes already declares \u2014 so the batch could be driven from this gate's own reported (file, line) population rather than from a hand list, and every affected package's suite could then answer whether the looseness was load-bearing. TWO rows remain, below, and neither is deferred adoption. `packages/spec/src/contracts/data-engine.test.ts` is EXEMPT for the structural reason that file's two sibling rows already carry: @objectstack/spec cannot import the predicate in principle. `packages/runtime/src/sandbox/quickjs-runner.test.ts` is a MISATTRIBUTION rather than an unguarded fake — an object-BOUND `ctx.api.object(name)` facade with no by-id member for the repository veto to read, so its position 0 holds the query and there is no object-name argument the predicate could be handed. The wrong pin was attempted and measured red before that row was written. Read this as the shape a new slice SHOULD take when its adoption is mechanical \u2014 the wholesale ledger is the concession a slice makes when it cannot be, not the default." ], "entries": [ { @@ -702,6 +704,14 @@ "why": "MEASURED (#5480): the `update` slice of this gate is NEW — `resolveEngineUpdateDispatch` did not exist before #5480, so no double in the repo could route through it and the whole discovered set enters this ledger in one act. Not newly written looseness and not a raised ratchet: it is the first measurement of a contract that had no producer-side predicate to measure against, which is exactly what this script's header used to list under deliberately-not-covered (\"update's twin dispatch ... needs its own producer-side predicate extracted first\"). Discovered at line 3693. The package already depends on @objectstack/objectql (`dependencies`), so this is a one-line pin whenever a batch takes it — deferred here because #5480's slice is the producer-side predicate plus the gate that reads it, and flipping ~100 unmeasured suites red belongs in the per-package batches that follow, exactly as #5629 did for delete. WHAT THIS ENTRY DOES NOT CLAIM: unlike the #5629 delete batch above it carries NO per-file dormancy probe. Nothing here says the looseness is unexercised — only that the double is structurally free to be looser than ObjectQL.update on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate) — a shape the producer refuses in `data.id` too since objectstack#5748 put the payload half through the SAME scalar test, so `data.id` still outranks `where` and `multi`, but only when it IS a scalar id.", "closes": "open the fake's update with assertEngineUpdateDispatch(data, options) and run the package's suite" }, + { + "file": "packages/runtime/src/sandbox/quickjs-runner.test.ts", + "verb": "findOne", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (objectstack#12068): this is NOT an engine double — it is the object-BOUND facade `ctx.api.object(name)` returns, and it is the residual this script's header already names under \"a scoped repository that declares NO repository-only member\", one verb further along. The factory is `const repoFor = (tx) => (name: string) => ({ insert, findOne, count })`: the object name arrives from the CLOSURE, so position 0 of `findOne` holds the QUERY, and `quickjs-runner.ts`'s `installApiMethod` forwards the VM's arguments verbatim (`m.apply(proxy, args)`) — `ctx.api.object('a').findOne({ id: 1 })` reaches this member as `findOne({ id: 1 })`. It is discovered anyway because the repository veto needs a REPOSITORY_ONLY_MEMBER (`updateById`/`deleteById`) and this facade declares neither, while `insert` supplies ENGINE_ONLY_MEMBERS evidence at an arity the parameter test cannot judge. Discovered at line 878. WHY NOT PINNED, and it is not deferral: `assertEngineFindOnePredicate(object, query)` needs the object name, and there is no object-name position in this signature to hand it. Adopting it anyway was TRIED and MEASURED rather than reasoned about — the sweep's codemod widened the signature to `(object, query)` and the suite went red with `findOne('[object Object]') selects no particular record`, the predicate reading the query as the object name. That red is the correct outcome of a wrong pin and it is why this row exists instead. Padding the facade with `updateById`/`deleteById` to buy the veto is the ceremony the #11626 section of this script rejects, and closing it for real is a REPOSITORY_ONLY_MEMBERS measurement (`--census` first, as that constant's own note requires), not a test edit. WHAT THIS ENTRY DOES NOT CLAIM: no dormancy. This `findOne` IS driven — `reads inside the tx also reuse the handle` calls it — so the looseness is live, and the row records a MISATTRIBUTION rather than an unguarded engine fake: there is no `ObjectQL.findOne` contract for an object-bound repository member to be looser than.", + "closes": "either widen REPOSITORY_ONLY_MEMBERS so an object-bound facade with no by-id member leaves scan scope (a `--census` measurement, per that constant's note — it would also retire the sibling residual at packages/runtime/src/action-body-identity.test.ts:71), or restate this fixture as a fake ENGINE the sandbox test drives through `ctx.api.object`. Not closable by a one-line pin: the signature has no object-name position." + }, { "file": "packages/services/service-automation/src/builtin/crud-bulk-intent.test.ts", "verb": "update", @@ -1118,6 +1128,14 @@ "why": "Not a stand-in that code under test drives — it is a TYPE-CONFORMANCE witness that IDataEngine is implementable, asserting only `typeof engine.delete === 'function'`. And it cannot be pinned even in principle: @objectstack/objectql depends on @objectstack/spec, so the import would invert the dependency. Ran clean under the guard anyway (spec: 295/295 files passed with the dispatch guard installed in every engine double). RE-MEASURED (#5629): this entry's count moves 1 -> 5 without a line of test code changing — 4 further doubles in this file (lines 46, 82, 119, 152) became visible when #5629 stopped discarding deletes that declare no parameters. Not a regression and not a raised ratchet: the doubles were always here, the scan could not reach them. The four newly visible doubles are the same kind as the one this entry already records: `const engine: IDataEngine = { … }` type-conformance witnesses inside the contract test for that interface. Each is built to exercise or declare something OTHER than delete — reads through `find`/`findOne`/`count`, the trailing options argument on every read, the optional `execute` and `vectorFind` members — and none of them calls `delete`, which is present only because the interface requires the member. EXEMPT for the reason already stated, which applies to each of them unchanged. Dormant looseness, probed rather than assumed: a `process.stderr.write` marker injected as the first statement of this delete printed NOTHING while the file's suite passed, so no path this suite drives calls it. The control that makes that silence evidence instead of a broken probe: the same injection in `run-summary.test.ts`'s PINNED delete DID print, in the same run of the same harness. Dormant is not harmless — it means the looseness is unexercised today, so a future test that starts deleting through this fake inherits a double that accepts what ObjectQL.delete refuses.", "closes": "nothing — permanent" }, + { + "file": "packages/spec/src/contracts/data-engine.test.ts", + "verb": "findOne", + "unguarded": 5, + "kind": "EXEMPT", + "why": "MEASURED (objectstack#12068, the remainder of #11957): the `findOne` slice of this gate is NEW — `assertEngineFindOnePredicate` did not exist before #12072, so no double in the repo could route through it. Unlike #5480's and #8639's first measurements this slice ledgered almost nothing: of the 213 files it discovered, 212 were adopted in the slice's own PR and this is the one that remains. EXEMPT for the reason this file's `delete` and `update` rows already carry, restated here because a per-verb ledger may not inherit a verdict: @objectstack/spec CANNOT import the predicate even in principle — both of its homes (@objectstack/metadata-core since #5619, and @objectstack/objectql) DEPEND ON @objectstack/spec, so the import would invert that edge and turbo rejects the resulting task graph outright. There is no devDependency route here, which is precisely what separates this row from the `service-datasource` rows above, where the edge WAS available and the `findOne` verb took it in this same PR. Discovered at lines 25, 47, 83, 120, 153 — the five `const engine: IDataEngine = { … }` type-conformance witnesses this file exists to declare. WHAT THIS ENTRY DOES NOT CLAIM, and it is the OPPOSITE of the `delete` row's claim for the same file: this looseness is NOT dormant. The witnesses DRIVE `findOne`, and two of those drives are shapes the real engine REFUSES — `await engine.findOne('users')` (line 66: no `where`, no `orderBy`) and `await engine.findOne('sys_user', { where: {} }, sys)` (line 107: `{}` is the match-every-row shape #4419 rejects). Both are correct as TYPE conformance, which is all this file asserts, and both would throw against ObjectQL. So the exemption is structural, not a clean bill: a reader must not take those two call sites as evidence that a predicate-less `findOne` is a supported shape. Recorded here rather than silently exempted, and handed to the spec seat separately.", + "closes": "nothing — permanent (the import would invert @objectstack/spec's dependency edge). If the two predicate-less call sites at lines 66 and 107 are ever restated to select a particular record, that is a readability fix for the witnesses and does NOT remove this row: the five doubles stay unpinnable." + }, { "file": "packages/spec/src/contracts/data-engine.test.ts", "verb": "update", diff --git a/scripts/engine-double-contract.pinned.json b/scripts/engine-double-contract.pinned.json index 2370f0d3b2b..231f6fc7bcd 100644 --- a/scripts/engine-double-contract.pinned.json +++ b/scripts/engine-double-contract.pinned.json @@ -6,16 +6,31 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/core/src/utils/migration-journal.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/core/src/utils/migration-journal.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/mcp/src/__tests__/plugin.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/mcp/src/mcp-stdio-tools.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/mcp/src/mcp-stdio-tools.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/mcp/src/mcp-stdio-tools.test.ts", "verb": "update", @@ -26,6 +41,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/mcp/src/mcp-write-response-internal-fields.tripwire.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/mcp/src/mcp-write-response-internal-fields.tripwire.test.ts", "verb": "update", @@ -36,16 +56,36 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/mcp/src/plugin.record-resource-exposure.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/mcp/src/plugin.record-resource-exposure.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/mcp/src/stdio-data-bridge.exposure.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/mcp/src/stdio-data-bridge.not-found.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/migrations/recorded-by-sentinel.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/migrations/recorded-by-sentinel.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/migrations/recorded-by-sentinel.test.ts", "verb": "update", @@ -61,6 +101,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol-publish-drafts-advisories.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol-publish-drafts-advisories.test.ts", "verb": "update", @@ -71,6 +116,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol-publish-drafts-closure.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol-publish-drafts-closure.test.ts", "verb": "update", @@ -81,6 +131,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol-publish-drafts-endpoint-gate.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol-publish-drafts-endpoint-gate.test.ts", "verb": "update", @@ -91,6 +146,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol-publish-drafts-org-scope.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol-publish-drafts-org-scope.test.ts", "verb": "update", @@ -101,6 +161,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol-publish-drafts-package-scope.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol-publish-drafts-package-scope.test.ts", "verb": "update", @@ -111,6 +176,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.adr0005-org-override-rollback.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.adr0005-org-override-rollback.test.ts", "verb": "update", @@ -121,6 +191,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.audit-field-governance.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.audit-field-governance.test.ts", "verb": "update", @@ -131,6 +206,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.batch-atomic.test.ts", + "verb": "findOne", + "pinned": 2 + }, { "file": "packages/metadata-protocol/src/protocol.batch-atomic.test.ts", "verb": "update", @@ -141,6 +221,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.batch-not-attempted.test.ts", + "verb": "findOne", + "pinned": 2 + }, { "file": "packages/metadata-protocol/src/protocol.batch-not-attempted.test.ts", "verb": "update", @@ -151,6 +236,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.batch-row-conformance.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.batch-row-conformance.test.ts", "verb": "update", @@ -161,6 +251,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.batch-row-driver-text.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.batch-row-driver-text.test.ts", "verb": "update", @@ -171,6 +266,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.batch-row-http-status.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.batch-row-http-status.test.ts", "verb": "update", @@ -181,6 +281,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.batch-verb-driver-code.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.batch-verb-driver-code.test.ts", "verb": "update", @@ -191,6 +296,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.batch-verb-driver-text.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.batch-verb-driver-text.test.ts", "verb": "update", @@ -201,6 +311,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.bulk-record-not-found.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.bulk-record-not-found.test.ts", "verb": "update", @@ -211,6 +326,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.capability-write-door.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.capability-write-door.test.ts", "verb": "update", @@ -221,6 +341,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.code-only-types.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.code-only-types.test.ts", "verb": "update", @@ -231,6 +356,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.container-issue-descent.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.container-issue-descent.test.ts", "verb": "update", @@ -241,6 +371,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.dashboard-dataset-publish-gate.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.dashboard-dataset-publish-gate.test.ts", "verb": "update", @@ -251,6 +386,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.delete-object-registry-unregister.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.delete-object-registry-unregister.test.ts", "verb": "update", @@ -261,6 +401,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.delete-receipt-wording.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.delete-receipt-wording.test.ts", "verb": "update", @@ -271,21 +416,46 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.delete-rewrap-envelope.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.delete-rewrap-envelope.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.destructive-409-face-inventory.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/metadata-protocol/src/protocol.destructive-gate-reachable-types.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.destructive-gate-reachable-types.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.diagnostics-store-outage.test.ts", + "verb": "findOne", + "pinned": 5 + }, { "file": "packages/metadata-protocol/src/protocol.diff-canonical-type-and-history-outage.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.diff-canonical-type-and-history-outage.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.diff-canonical-type-and-history-outage.test.ts", "verb": "update", @@ -296,6 +466,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.diff-credential-redaction.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.diff-credential-redaction.test.ts", "verb": "update", @@ -306,6 +481,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.diff-dead-history-read.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.diff-dead-history-read.test.ts", "verb": "update", @@ -316,16 +496,31 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.driver-text-disclosure.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.driver-text-disclosure.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.dropped-fields.bulk.test.ts", + "verb": "findOne", + "pinned": 2 + }, { "file": "packages/metadata-protocol/src/protocol.dropped-fields.bulk.test.ts", "verb": "update", "pinned": 2 }, + { + "file": "packages/metadata-protocol/src/protocol.dropped-fields.test.ts", + "verb": "findOne", + "pinned": 3 + }, { "file": "packages/metadata-protocol/src/protocol.dropped-fields.test.ts", "verb": "update", @@ -336,6 +531,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.flow-org-override-closed.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.flow-org-override-closed.test.ts", "verb": "update", @@ -346,16 +546,36 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.graft-folded-form-sections.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.graft-folded-form-sections.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.hydrate-overlay-canonical-type.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/metadata-protocol/src/protocol.i18n-bundle-list-merge.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.injected-system-columns.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.injected-system-columns.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.injected-system-columns.test.ts", "verb": "update", @@ -366,6 +586,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.invalid-metadata-422-face-inventory.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.invalid-metadata-422-face-inventory.test.ts", "verb": "update", @@ -376,6 +601,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.item-name-grammar.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.item-name-grammar.test.ts", "verb": "update", @@ -386,6 +616,11 @@ "verb": "delete", "pinned": 2 }, + { + "file": "packages/metadata-protocol/src/protocol.legacy-overlay-delete.test.ts", + "verb": "findOne", + "pinned": 2 + }, { "file": "packages/metadata-protocol/src/protocol.legacy-overlay-delete.test.ts", "verb": "update", @@ -396,16 +631,31 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.lifecycle-audit-rows.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.lifecycle-audit-rows.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.lock-gate-canonical-type.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.lock-gate-fail-closed.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.lock-gate-fail-closed.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.lock-gate-fail-closed.test.ts", "verb": "update", @@ -416,16 +666,31 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.many-data-atomic.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.many-data-atomic.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.meta-list-runtime-baseline-dedup.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.meta-types-mint-door-agreement.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.meta-types-mint-door-agreement.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.meta-types-mint-door-agreement.test.ts", "verb": "update", @@ -436,16 +701,31 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.metadata-redaction.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.metadata-redaction.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.metadata-store-outage.test.ts", + "verb": "findOne", + "pinned": 2 + }, { "file": "packages/metadata-protocol/src/protocol.migrate-stored-noncanonical-type.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.migrate-stored-noncanonical-type.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.migrate-stored-noncanonical-type.test.ts", "verb": "update", @@ -456,6 +736,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.object-registry-write-through-spelling.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.object-registry-write-through-spelling.test.ts", "verb": "update", @@ -466,6 +751,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit-live-registry.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit-live-registry.test.ts", "verb": "update", @@ -476,6 +766,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.org-scoped-cold-boot-audit.test.ts", "verb": "update", @@ -486,6 +781,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.org-scoped-write-refused.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.org-scoped-write-refused.test.ts", "verb": "update", @@ -496,6 +796,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.package-closure-gate.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.package-closure-gate.test.ts", "verb": "update", @@ -506,6 +811,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.package-publish-audit-rows.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.package-publish-audit-rows.test.ts", "verb": "update", @@ -516,6 +826,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.platform-schedule-org-gate.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.platform-schedule-org-gate.test.ts", "verb": "update", @@ -526,6 +841,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.publish-commit-capture-read-failure.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.publish-commit-capture-read-failure.test.ts", "verb": "update", @@ -536,6 +856,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.publish-item-draft-org-scope.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.publish-item-draft-org-scope.test.ts", "verb": "update", @@ -546,6 +871,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.publish-item-rebind-announce.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.publish-item-rebind-announce.test.ts", "verb": "update", @@ -558,12 +888,22 @@ }, { "file": "packages/metadata-protocol/src/protocol.publish-side-effects-canonical-type.test.ts", - "verb": "update", + "verb": "findOne", "pinned": 1 }, { - "file": "packages/metadata-protocol/src/protocol.publish-stored-type-canonical.test.ts", - "verb": "delete", + "file": "packages/metadata-protocol/src/protocol.publish-side-effects-canonical-type.test.ts", + "verb": "update", + "pinned": 1 + }, + { + "file": "packages/metadata-protocol/src/protocol.publish-stored-type-canonical.test.ts", + "verb": "delete", + "pinned": 1 + }, + { + "file": "packages/metadata-protocol/src/protocol.publish-stored-type-canonical.test.ts", + "verb": "findOne", "pinned": 1 }, { @@ -576,16 +916,36 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.read-decorations.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.read-decorations.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.read-seam-empty-accumulator.test.ts", + "verb": "findOne", + "pinned": 6 + }, + { + "file": "packages/metadata-protocol/src/protocol.read-verb-canonical-fold.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.record-not-found.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.record-not-found.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.record-not-found.test.ts", "verb": "update", @@ -596,16 +956,36 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.record-package-commit-durability.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.record-package-commit-durability.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.reference-derivation.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/metadata-protocol/src/protocol.reference-target-unanswerable.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.revert-stored-type-canonical.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.revert-stored-type-canonical.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.revert-stored-type-canonical.test.ts", "verb": "update", @@ -616,6 +996,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts", "verb": "update", @@ -626,16 +1011,31 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.save-flow-canonicalization.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.save-flow-canonicalization.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.save-meta-missing-item.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.save-receipt-wording.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.save-receipt-wording.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.save-receipt-wording.test.ts", "verb": "update", @@ -646,6 +1046,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.save-union-issues.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.save-union-issues.test.ts", "verb": "update", @@ -656,6 +1061,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.stored-conversions.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.stored-conversions.test.ts", "verb": "update", @@ -666,6 +1076,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.stored-migration.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.stored-migration.test.ts", "verb": "update", @@ -676,6 +1091,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.stored-residue-resave.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.stored-residue-resave.test.ts", "verb": "update", @@ -686,6 +1106,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.unrecognised-meta-type.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.unrecognised-meta-type.test.ts", "verb": "update", @@ -696,11 +1121,21 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.update-path-id-wins.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.update-path-id-wins.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.upsert-existence.test.ts", + "verb": "findOne", + "pinned": 2 + }, { "file": "packages/metadata-protocol/src/protocol.upsert-existence.test.ts", "verb": "update", @@ -721,16 +1156,31 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/protocol.write-response-internal-fields.tripwire.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/protocol.write-response-internal-fields.tripwire.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/search-clone-schema-conformance.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-composite-external-id.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-composite-external-id.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-composite-external-id.test.ts", "verb": "update", @@ -741,6 +1191,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-deferred-dropped.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-deferred-dropped.test.ts", "verb": "update", @@ -751,6 +1206,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-deferred-failure.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-deferred-failure.test.ts", "verb": "update", @@ -761,6 +1221,11 @@ "verb": "delete", "pinned": 2 }, + { + "file": "packages/metadata-protocol/src/seed-loader-driver-text.test.ts", + "verb": "findOne", + "pinned": 2 + }, { "file": "packages/metadata-protocol/src/seed-loader-driver-text.test.ts", "verb": "update", @@ -771,6 +1236,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-engine-schema-fallback.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-engine-schema-fallback.test.ts", "verb": "update", @@ -781,6 +1251,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-env-scope.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-env-scope.test.ts", "verb": "update", @@ -791,6 +1266,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-existing-records-read-failure.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-existing-records-read-failure.test.ts", "verb": "update", @@ -801,6 +1281,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-multi-value-reference.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-multi-value-reference.test.ts", "verb": "update", @@ -811,6 +1296,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-name-probe.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-name-probe.test.ts", "verb": "update", @@ -821,6 +1311,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-pointer-pair.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-pointer-pair.test.ts", "verb": "update", @@ -831,6 +1326,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-replay.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-replay.test.ts", "verb": "update", @@ -841,6 +1341,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-retry.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-retry.test.ts", "verb": "update", @@ -851,6 +1356,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-state-machine-exempt.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-state-machine-exempt.test.ts", "verb": "update", @@ -861,6 +1371,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-summary-stale.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-summary-stale.test.ts", "verb": "update", @@ -871,6 +1386,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/seed-loader-unresolved-drop.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/seed-loader-unresolved-drop.test.ts", "verb": "update", @@ -881,6 +1401,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/sys-metadata-repository.contract.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/sys-metadata-repository.contract.test.ts", "verb": "update", @@ -891,6 +1416,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/sys-metadata-repository.draft-drain.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/sys-metadata-repository.draft-drain.test.ts", "verb": "update", @@ -901,6 +1431,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/sys-metadata-repository.draft-package-inherit.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/sys-metadata-repository.draft-package-inherit.test.ts", "verb": "update", @@ -911,6 +1446,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/sys-metadata-repository.history-counters.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/sys-metadata-repository.history-counters.test.ts", "verb": "update", @@ -921,6 +1461,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/sys-metadata-repository.package-writability.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/sys-metadata-repository.package-writability.test.ts", "verb": "update", @@ -931,6 +1476,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/sys-metadata-repository.recorded-by.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/sys-metadata-repository.recorded-by.test.ts", "verb": "update", @@ -941,6 +1491,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata-protocol/src/view-container-runtime-expansion.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata-protocol/src/view-container-runtime-expansion.test.ts", "verb": "update", @@ -956,6 +1511,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/metadata/src/migrations/migrate-sys-notification-to-event.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/metadata/src/migrations/migrate-sys-notification-to-event.test.ts", "verb": "update", @@ -971,6 +1531,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/layered-overlay-integration.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/layered-overlay-integration.test.ts", "verb": "update", @@ -981,6 +1546,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/meta-object-primary-designation-roundtrip.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/meta-object-primary-designation-roundtrip.test.ts", "verb": "update", @@ -991,6 +1561,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/meta-object-search-companion-roundtrip.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/meta-object-search-companion-roundtrip.test.ts", "verb": "update", @@ -1001,6 +1576,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/meta-object-tenant-index-roundtrip.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/meta-object-tenant-index-roundtrip.test.ts", "verb": "update", @@ -1011,11 +1591,21 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/package-disable-enforcement.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/package-disable-enforcement.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-boot-hydration-scoped.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-boot-hydration-scoped.test.ts", "verb": "update", @@ -1026,6 +1616,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-boot-object-package-binding.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-boot-object-package-binding.test.ts", "verb": "update", @@ -1036,6 +1631,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-commit-history.test.ts", + "verb": "findOne", + "pinned": 3 + }, { "file": "packages/objectql/src/protocol-commit-history.test.ts", "verb": "update", @@ -1046,6 +1646,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-delete-object-registry-heal.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-delete-object-registry-heal.test.ts", "verb": "update", @@ -1056,6 +1661,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-meta-effective-schema.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-meta-effective-schema.test.ts", "verb": "update", @@ -1066,6 +1676,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-meta-type-canonicalization.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-meta-type-canonicalization.test.ts", "verb": "update", @@ -1076,6 +1691,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-object-overlay-layer.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-object-overlay-layer.test.ts", "verb": "update", @@ -1086,6 +1706,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-org-overlay-registry-gate.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-org-overlay-registry-gate.test.ts", "verb": "update", @@ -1096,6 +1721,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-packaged-object-base.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-packaged-object-base.test.ts", "verb": "update", @@ -1111,11 +1741,21 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-publish-rollback.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-publish-rollback.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-registry-shadow.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-registry-shadow.test.ts", "verb": "update", @@ -1126,6 +1766,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-save-meta-repo-path.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-save-meta-repo-path.test.ts", "verb": "update", @@ -1136,6 +1781,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-view-identity-overlay.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-view-identity-overlay.test.ts", "verb": "update", @@ -1146,6 +1796,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/protocol-writepath-object-ownership.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/protocol-writepath-object-ownership.test.ts", "verb": "update", @@ -1156,6 +1811,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/registry-tenant-index-author-declared-column.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/registry-tenant-index-author-declared-column.test.ts", "verb": "update", @@ -1166,6 +1826,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/registry-tenant-index-declaration.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/registry-tenant-index-declaration.test.ts", "verb": "update", @@ -1176,6 +1841,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/registry-tenant-index-follows-wall.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/registry-tenant-index-follows-wall.test.ts", "verb": "update", @@ -1196,6 +1866,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/objectql/src/sys-metadata-repository.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/objectql/src/sys-metadata-repository.test.ts", "verb": "update", @@ -1266,6 +1941,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/accept-invitation-adopt-membership.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/accept-invitation-adopt-membership.test.ts", "verb": "update", @@ -1281,6 +1961,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/admin-revoke-user-session-match-guard.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/admin-revoke-user-session-match-guard.test.ts", "verb": "update", @@ -1291,26 +1976,56 @@ "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/audience-posture-setting.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/audience-posture.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/audience-posture.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/audience-posture.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/auth-contains-filter.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/auth-manager.jwt-eddsa-fallback.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/auth-manager.jwt-eddsa-fallback.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/plugins/plugin-auth/src/auth-manager.optional-plugin-isolation.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/auth-manager.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/auth-manager.test.ts", + "verb": "findOne", + "pinned": 4 + }, { "file": "packages/plugins/plugin-auth/src/auth-manager.test.ts", "verb": "update", @@ -1321,21 +2036,41 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/auth-where-operator-coverage.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/change-email-delete-user-wiring.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/change-email-delete-user-wiring.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/change-email-delete-user-wiring.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/first-session-membership-ordering.test.ts", + "verb": "findOne", + "pinned": 2 + }, { "file": "packages/plugins/plugin-auth/src/impersonation-bearer-rotation.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/impersonation-bearer-rotation.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/impersonation-bearer-rotation.test.ts", "verb": "update", @@ -1346,16 +2081,31 @@ "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/membership-policy-setting.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/org-create-posture-gate.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/org-create-posture-gate.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/organization-add-member.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/organization-add-member.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/organization-add-member.test.ts", "verb": "update", @@ -1366,6 +2116,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/remove-member-permission-guard.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/remove-member-permission-guard.test.ts", "verb": "update", @@ -1376,6 +2131,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/remove-user-atomicity.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/remove-user-atomicity.test.ts", "verb": "update", @@ -1386,21 +2146,41 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/revoke-session-match-guard.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/revoke-session-match-guard.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/scim-case-insensitive-identifier.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/session-of-record.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/session-of-record.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/session-tombstone.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-auth/src/session-tombstone.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-auth/src/session-tombstone.test.ts", "verb": "update", @@ -1446,6 +2226,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/authored-row-write-verdict.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/authored-row-write-verdict.test.ts", "verb": "update", @@ -1466,6 +2251,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/check-only-write-scope.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/check-only-write-scope.test.ts", "verb": "update", @@ -1476,11 +2266,51 @@ "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/controlled-by-parent-chain.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/plugins/plugin-security/src/controlled-by-parent-detail-write-authority.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/plugins/plugin-security/src/controlled-by-parent-master-widener.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/plugins/plugin-security/src/controlled-by-parent-sharing.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/plugins/plugin-security/src/explain-engine.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/plugins/plugin-security/src/field-masking-rule.test.ts", + "verb": "findOne", + "pinned": 2 + }, + { + "file": "packages/plugins/plugin-security/src/invitation-placement.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/packaged-permission-set-lock-gate.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/packaged-permission-set-lock-gate.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/packaged-permission-set-lock-gate.test.ts", "verb": "update", @@ -1491,11 +2321,21 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/packaged-permission-set-lock.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/packaged-permission-set-lock.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/packaged-permission-set-restore-leg.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/packaged-permission-set-restore-leg.test.ts", "verb": "update", @@ -1511,11 +2351,21 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/permission-denied-user-copy.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/permission-denied-user-copy.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/permission-set-active.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/permission-set-drift.test.ts", "verb": "update", @@ -1531,11 +2381,31 @@ "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/permission-set-projection.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/plugins/plugin-security/src/permission-set-resolution-memo.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/plugins/plugin-security/src/resolve-permission-sets-for-context.pin.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/row-write-widener-composition.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/row-write-widener-composition.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/row-write-widener-composition.test.ts", "verb": "update", @@ -1546,11 +2416,21 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/security-denial-user-copy.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/security-denial-user-copy.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/security-plugin.test.ts", + "verb": "findOne", + "pinned": 5 + }, { "file": "packages/plugins/plugin-security/src/security-plugin.test.ts", "verb": "update", @@ -1561,6 +2441,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/select-only-write-visibility.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/select-only-write-visibility.test.ts", "verb": "update", @@ -1576,6 +2461,11 @@ "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/store-fault-fail-closed.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/suggested-audience-bindings-install-path.test.ts", "verb": "delete", @@ -1591,6 +2481,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-security/src/vama-write-path-convergence.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-security/src/vama-write-path-convergence.test.ts", "verb": "update", @@ -1606,6 +2501,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-sharing/src/authored-row-write-deferral.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-sharing/src/authored-row-write-deferral.test.ts", "verb": "update", @@ -1656,6 +2556,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-sharing/src/share-link-eligibility.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-sharing/src/share-link-eligibility.test.ts", "verb": "update", @@ -1706,11 +2611,26 @@ "verb": "update", "pinned": 1 }, + { + "file": "packages/plugins/plugin-webhooks/src/auto-enqueuer.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/plugins/plugin-webhooks/src/bootstrap-declared-webhooks.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-webhooks/src/webhook-drop-durable-record.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-webhooks/src/webhook-drop-durable-record.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-webhooks/src/webhook-drop-durable-record.test.ts", "verb": "update", @@ -1721,6 +2641,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/plugins/plugin-webhooks/src/webhook-signing-secret.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/plugins/plugin-webhooks/src/webhook-signing-secret.test.ts", "verb": "update", @@ -1731,6 +2656,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/rest/src/meta-compound-save-force-parity.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/rest/src/meta-compound-save-force-parity.test.ts", "verb": "update", @@ -1741,16 +2671,51 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/rest/src/meta-compound-save-mode-parity.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/rest/src/meta-compound-save-mode-parity.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/rest/src/meta-object-extension-agreement.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/rest/src/meta-object-extension-property-classes.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/rest/src/meta-object-materialization-agreement.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/rest/src/meta-object-overlay-extension-fold.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/rest/src/meta-object-search-companion-agreement.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/rest/src/meta-published-overlay.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/rest/src/meta-published-overlay.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/rest/src/meta-published-overlay.test.ts", "verb": "update", @@ -1761,6 +2726,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/rest/src/public-form-lookup-picker.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/rest/src/public-form-lookup-picker.test.ts", "verb": "update", @@ -1771,6 +2741,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/rest/src/public-form-routes.stored-row.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/rest/src/public-form-routes.stored-row.test.ts", "verb": "update", @@ -1791,21 +2766,41 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/rest/src/rest-server-meta-read-org-scope.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/rest/src/rest-server-meta-read-org-scope.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/runtime/src/action-execution-calldata-batch-retired.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/runtime/src/action-execution-calldata-not-found.test.ts", "verb": "delete", "pinned": 2 }, + { + "file": "packages/runtime/src/action-execution-calldata-not-found.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/runtime/src/domains/meta-published-runtime-publish.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/runtime/src/domains/meta-published-runtime-publish.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/runtime/src/domains/meta-published-runtime-publish.test.ts", "verb": "update", @@ -1816,6 +2811,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/runtime/src/domains/meta-save-destructive-remedy.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/runtime/src/domains/meta-save-destructive-remedy.test.ts", "verb": "update", @@ -1846,6 +2846,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/runtime/src/meta-compound-arity-mint-door.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/runtime/src/meta-compound-arity-mint-door.test.ts", "verb": "update", @@ -1856,6 +2861,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/runtime/src/meta-field-overlay-lock.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/runtime/src/meta-field-overlay-lock.test.ts", "verb": "update", @@ -1866,6 +2876,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/runtime/src/meta-overlay-read-your-writes.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/runtime/src/meta-overlay-read-your-writes.test.ts", "verb": "update", @@ -1876,6 +2891,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/runtime/src/meta-write-org-scope.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/runtime/src/meta-write-org-scope.test.ts", "verb": "update", @@ -1886,6 +2906,11 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/runtime/src/seed-loader.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/runtime/src/seed-loader.test.ts", "verb": "update", @@ -1896,6 +2921,36 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/services/service-automation/src/builtin/crud-bulk-intent.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-automation/src/builtin/crud-config-aliases.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-automation/src/builtin/crud-filter-guard.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-automation/src/builtin/crud-output-var.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-automation/src/builtin/crud-runas.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-automation/src/builtin/notify-organization-stamp.integration.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/services/service-automation/src/builtin/wait-node-degraded-run.test.ts", "verb": "update", @@ -1906,11 +2961,31 @@ "verb": "update", "pinned": 1 }, + { + "file": "packages/services/service-automation/src/record-lookup-expand.integration.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/services/service-automation/src/run-summary.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/services/service-automation/src/run-summary.test.ts", + "verb": "findOne", + "pinned": 5 + }, + { + "file": "packages/services/service-automation/src/runas-grant-resolution.integration.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-datasource/src/__tests__/datasource-admin-plugin.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/services/service-job/src/db-job-adapter.degraded-outcome.test.ts", "verb": "update", @@ -1926,16 +3001,76 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/services/service-messaging/src/delivery-headers-at-rest.integration.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/services/service-messaging/src/delivery-headers-at-rest.integration.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/services/service-messaging/src/email-channel.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-messaging/src/inbox-channel.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-messaging/src/messaging-service-plugin.test.ts", + "verb": "findOne", + "pinned": 2 + }, + { + "file": "packages/services/service-messaging/src/messaging-service.test.ts", + "verb": "findOne", + "pinned": 6 + }, + { + "file": "packages/services/service-messaging/src/notification-schema-conformance.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/services/service-messaging/src/notification-schema-conformance.test.ts", "verb": "update", "pinned": 1 }, + { + "file": "packages/services/service-messaging/src/preference-resolver.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-messaging/src/read-receipt-organization.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-messaging/src/recipient-resolver.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-messaging/src/sms-channel.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-messaging/src/sql-outbox-audit-columns.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-messaging/src/template-renderer.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/services/service-queue/src/db-queue-adapter.test.ts", "verb": "delete", @@ -1961,6 +3096,26 @@ "verb": "update", "pinned": 1 }, + { + "file": "packages/services/service-storage/src/attachment-access-hooks.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-storage/src/attachment-lifecycle.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-storage/src/file-reference-lifecycle.test.ts", + "verb": "findOne", + "pinned": 1 + }, + { + "file": "packages/services/service-storage/src/lax-deviation-reclamation-gate.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/services/service-storage/src/lax-deviation-reclamation-gate.test.ts", "verb": "update", @@ -1971,16 +3126,31 @@ "verb": "delete", "pinned": 1 }, + { + "file": "packages/services/service-storage/src/metadata-store.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/services/service-storage/src/storage-routes.metadata-outage.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/services/service-storage/src/storage-routes.metadata-outage.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/services/service-storage/src/stranded-orphan-inventory.test.ts", "verb": "delete", "pinned": 1 }, + { + "file": "packages/services/service-storage/src/tombstone-download-live-reference.test.ts", + "verb": "findOne", + "pinned": 1 + }, { "file": "packages/services/service-storage/src/tombstone-download-live-reference.test.ts", "verb": "update", From 4262dda29843495d4cb765ae497ad436db557a66 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 26 Aug 2026 10:33:35 +0000 Subject: [PATCH 3/3] fix(engine-doubles): close the two defects the recovered findOne sweep left, and alias metadata-core in service-datasource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Supersedes the "NOT REVIEWED" disclaimer on 88784b7b70: the gate half and the 211-file adoption below it have now been run, ablated and re-measured. Three things this commit changes, all of them found by running what that commit never ran. 1. TS2345 in service-messaging. `delivery-headers-at-rest.integration.test.ts` passed the fake's `q: unknown` straight into the predicate, whose parameter is `EngineFindOneQueryInput | null | undefined`. vitest never type-checks, so the suite was green and `tsc --noEmit` was red — the one direction a test-only sweep can go wrong invisibly. Cast at the call, matching the sibling `assertEngineUpdateDispatch(d as any, q as any)` pin three lines below it. 2. service-datasource's engine double reached `@objectstack/metadata-core` through `dist/`. `check:test-source-alias` names the repair and refuses the alternative: alias the specifier in the package's own vitest config, never widen the shrink-only registry. A pin resolved through a build artifact is pinned to whatever was last built rather than to the predicate beside it, which is the single failure a contract pin exists to prevent. 3. Import order in that same test file is now load-bearing, and says so. Aliasing metadata-core to source pulls its import graph into the package's resolution domain, which switches on the clocked-window rule for the whole package — and that rule then misreported a file that has paid its `@objectstack/spec/kernel` load at module top since #10120. Cause is a detector defect filed as #12555: the gate's import regex swallows a bare side-effect import whenever an `import … from …` follows it later in the file. Not worked around in the gate — the fix there needs its own `--self-test` cases — so the statement is placed where the detector reads it correctly, with a comment naming the constraint and the card that removes it. --- .../src/__tests__/datasource-admin-plugin.test.ts | 8 +++++++- .../services/service-datasource/vitest.config.ts | 13 ++++++++++++- .../delivery-headers-at-rest.integration.test.ts | 2 +- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/services/service-datasource/src/__tests__/datasource-admin-plugin.test.ts b/packages/services/service-datasource/src/__tests__/datasource-admin-plugin.test.ts index 09ed5ff535f..e6e111eb60c 100644 --- a/packages/services/service-datasource/src/__tests__/datasource-admin-plugin.test.ts +++ b/packages/services/service-datasource/src/__tests__/datasource-admin-plugin.test.ts @@ -8,13 +8,19 @@ import { type DatasourceAdminServicePluginOptions, } from '../datasource-admin-plugin.js'; +import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; + // [#10126] Pay the first transform of these dist-resolved workspace deps at MODULE // LOAD. Each is reached below through a dynamic `import()` inside an `it()` body or a // hook -- both of which vitest clocks, while collection is clocked against nothing. See // `scripts/check-test-source-alias.mjs` (the clocked-window rule) and #10115 / PR #10120, // where the same shape cost 30 ejected merge-queue builds in one night. +// +// ORDER IS LOAD-BEARING until #12555 lands: check-test-source-alias's import regex +// swallows a bare side-effect import whenever an `import … from …` follows it later in +// the file, so this statement must stay BELOW every `from` import or the clocked-window +// rule reports this file as unpaid while the line it asks for is already here. import '@objectstack/spec/kernel'; -import { assertEngineFindOnePredicate } from '@objectstack/metadata-core'; /** * Minimal PluginContext + in-memory metadata service. Boots the plugin and diff --git a/packages/services/service-datasource/vitest.config.ts b/packages/services/service-datasource/vitest.config.ts index 07c958f4cce..bef9273c580 100644 --- a/packages/services/service-datasource/vitest.config.ts +++ b/packages/services/service-datasource/vitest.config.ts @@ -37,6 +37,17 @@ export default defineConfig({ // matches by PREFIX, so a bare `@objectstack/core` entry would also swallow // `@objectstack/core/logger` and resolve it to `core/src/index.ts/logger` // (ENOTDIR). Same shape as `service-storage` and `service-knowledge`. - alias: [{ find: /^@objectstack\/core$/, replacement: path.resolve(__dirname, '../../core/src/index.ts') }], + // `@objectstack/metadata-core` became a VALUE import of this package's TEST + // layer when its engine double adopted `assertEngineFindOnePredicate` + // (objectstack#12068). Same reasoning as the entry above, and the same + // direction of danger: unaliased it would follow the workspace link to + // `packages/metadata-core/dist/index.js`, so the double would be pinned to + // whatever the last build of that predicate emitted rather than to the + // predicate sitting next to it — a green pin over a stale contract, which is + // the one failure a contract pin exists to make impossible. + alias: [ + { find: /^@objectstack\/core$/, replacement: path.resolve(__dirname, '../../core/src/index.ts') }, + { find: /^@objectstack\/metadata-core$/, replacement: path.resolve(__dirname, '../../metadata-core/src/index.ts') }, + ], }, }); diff --git a/packages/services/service-messaging/src/delivery-headers-at-rest.integration.test.ts b/packages/services/service-messaging/src/delivery-headers-at-rest.integration.test.ts index 0648abb3495..45cd2ced109 100644 --- a/packages/services/service-messaging/src/delivery-headers-at-rest.integration.test.ts +++ b/packages/services/service-messaging/src/delivery-headers-at-rest.integration.test.ts @@ -288,7 +288,7 @@ describe('sys_http_delivery — authored headers vs the data API (#8118)', () => // its authored configuration. const noAccessor = { find: (o: string, q: unknown) => (eng as any).find(o, q), - findOne: (o: string, q: unknown) => { assertEngineFindOnePredicate(o, q); return (eng as any).findOne(o, q); }, + findOne: (o: string, q: unknown) => { assertEngineFindOnePredicate(o, q as any); return (eng as any).findOne(o, q); }, insert: (o: string, d: unknown) => (eng as any).insert(o, d), update: (o: string, d: unknown, q: unknown) => { // Engine-double contract: this fake's update() must be exactly