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 7a115b266a..ae3ffd9885 100644 --- a/packages/metadata-protocol/src/protocol.batch-row-conformance.test.ts +++ b/packages/metadata-protocol/src/protocol.batch-row-conformance.test.ts @@ -27,6 +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'; const SCHEMA = { name: 'invoice', fields: { title: { name: 'title', type: 'text' } } }; @@ -56,6 +57,7 @@ function makeStoreEngine() { return rec; }), update: vi.fn(async (_object: string, data: any, options?: any) => { + assertEngineUpdateDispatch(data, options); const id = options?.where?.id; const current = rows.get(id); if (!current) throw new Error(`no such record: ${id}`); @@ -66,6 +68,7 @@ function makeStoreEngine() { }), // Contract per #4435: `false` is the positive not-found value. delete: vi.fn(async (_object: string, options?: any) => { + assertEngineDeleteDispatch(options); const id = options?.where?.id; if (!rows.has(id)) return false; rows.delete(id); 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 181a8309e3..d95933ae7d 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 } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; import { resolveThrownHttpError, validationFailureDetails } from '@objectstack/types'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -170,6 +170,7 @@ function makeEngine(throwOn: (verb: string, id: unknown) => unknown | undefined) return rec; }), update: vi.fn(async (_o: string, data: any, opts?: any) => { + assertEngineUpdateDispatch(data, opts); const id = opts?.where?.id; const boom = throwOn('update', 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 b6044eb69b..2cca99bde0 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 } from '@objectstack/metadata-core'; +import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objectstack/metadata-core'; import { resolveThrownHttpError } from '@objectstack/types'; import { ObjectStackProtocolImplementation } from './protocol.js'; @@ -172,6 +172,7 @@ function makeEngine(throwOn: (verb: string, id: unknown) => unknown | undefined) return rec; }), update: vi.fn(async (_o: string, data: any, opts?: any) => { + assertEngineUpdateDispatch(data, opts); const id = opts?.where?.id; const boom = throwOn('update', id); if (boom) throw boom; diff --git a/packages/metadata-protocol/src/protocol.dropped-fields.test.ts b/packages/metadata-protocol/src/protocol.dropped-fields.test.ts index c6be76d1d2..f5eaf98774 100644 --- a/packages/metadata-protocol/src/protocol.dropped-fields.test.ts +++ b/packages/metadata-protocol/src/protocol.dropped-fields.test.ts @@ -14,6 +14,7 @@ import { describe, it, expect, vi } from 'vitest'; import { ObjectStackProtocolImplementation } from './protocol.js'; +import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; const SCHEMA = { name: 'approval_case', @@ -29,6 +30,7 @@ describe('updateData — forwards engine write strips as droppedFields (#3431)', registry: { getObject: () => SCHEMA }, // Stand in for the engine stripping `approval_status` and reporting it. update: vi.fn(async (object: string, data: any, options?: any) => { + assertEngineUpdateDispatch(data, options); options?.onFieldsDropped?.({ object, fields: ['approval_status'], reason: 'readonly' }); return { id: 'rec-1', title: data.title }; }), @@ -55,7 +57,8 @@ describe('updateData — forwards engine write strips as droppedFields (#3431)', it('forwards multiple strip passes in order (readonly_when then readonly)', async () => { const engine = { registry: { getObject: () => SCHEMA }, - update: vi.fn(async (object: string, _data: any, options?: any) => { + update: vi.fn(async (object: string, data: any, options?: any) => { + assertEngineUpdateDispatch(data, options); options?.onFieldsDropped?.({ object, fields: ['locked'], reason: 'readonly_when' }); options?.onFieldsDropped?.({ object, fields: ['approval_status'], reason: 'readonly' }); return { id: 'rec-1' }; 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 a93a85e32e..9ac661903f 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,6 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; +import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; /** * Composite externalId (framework#3434). @@ -57,6 +58,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineUpdateDispatch(data, undefined); const records = store[objectName] || []; const idx = records.findIndex((r) => r.id === data.id); if (idx >= 0) { 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 eab51637cf..2d4ec49653 100644 --- a/packages/metadata-protocol/src/seed-loader-deferred-dropped.test.ts +++ b/packages/metadata-protocol/src/seed-loader-deferred-dropped.test.ts @@ -3,6 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; +import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; /** * #5127 — pass 2 RESOLVES the target and then has no record to write it onto. @@ -66,6 +67,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineUpdateDispatch(data, undefined); const records = store[objectName] || []; const idx = records.findIndex((r) => r.id === data.id); if (idx >= 0) { records[idx] = { ...records[idx], ...data }; return records[idx]; } 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 8e03efcd2b..083783c5e3 100644 --- a/packages/metadata-protocol/src/seed-loader-deferred-failure.test.ts +++ b/packages/metadata-protocol/src/seed-loader-deferred-failure.test.ts @@ -3,6 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; +import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; /** * framework#2805: a pass-2 (deferred) reference back-fill that FAILS must be @@ -51,6 +52,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineUpdateDispatch(data, undefined); const records = store[objectName] || []; const idx = records.findIndex((r) => r.id === data.id); if (idx >= 0) { records[idx] = { ...records[idx], ...data }; return records[idx]; } 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 88ef318475..65accc4e32 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,6 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; +import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; /** * Reference-graph fallback to the ENGINE schema registry. @@ -63,6 +64,7 @@ function createFaithfulEngine(schemas: Record) { return record; }), update: vi.fn(async (objectName: string, data: any) => { + assertEngineUpdateDispatch(data, undefined); const records = store[objectName] || []; const idx = records.findIndex((r) => r.id === data.id); if (idx >= 0) { 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 8dd853789e..b3f4476111 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,6 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; +import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; /** * Multi-value reference resolution (`Field.lookup(..., { multiple: true })`). @@ -58,6 +59,7 @@ function createEngine(schemas: Record) { return record; }), update: vi.fn(async (objectName: string, data: any) => { + assertEngineUpdateDispatch(data, undefined); const records = store[objectName] || []; const idx = records.findIndex((r) => r.id === data.id); if (idx >= 0) { diff --git a/packages/metadata-protocol/src/seed-loader-replay.test.ts b/packages/metadata-protocol/src/seed-loader-replay.test.ts index d1b5598358..ef9c47ebc8 100644 --- a/packages/metadata-protocol/src/seed-loader-replay.test.ts +++ b/packages/metadata-protocol/src/seed-loader-replay.test.ts @@ -3,6 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; +import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; /** * Replay regression: seeds with lookup natural keys must survive a dev-server @@ -54,6 +55,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineUpdateDispatch(data, undefined); const records = store[objectName] || []; const idx = records.findIndex((r) => r.id === data.id); if (idx >= 0) { diff --git a/packages/metadata-protocol/src/seed-loader-retry.test.ts b/packages/metadata-protocol/src/seed-loader-retry.test.ts index d57670755a..59c2eff1f7 100644 --- a/packages/metadata-protocol/src/seed-loader-retry.test.ts +++ b/packages/metadata-protocol/src/seed-loader-retry.test.ts @@ -3,6 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; +import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; /** * framework#3150: the self-referencing seed path (`hasSelfRef`) writes records @@ -47,6 +48,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineUpdateDispatch(data, undefined); const records = store[objectName] || []; const idx = records.findIndex((r) => r.id === data.id); if (idx >= 0) { records[idx] = { ...records[idx], ...data }; return records[idx]; } 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 ab6d161c19..d9f4a563e9 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,6 +3,7 @@ import { describe, it, expect, vi } from 'vitest'; import { SeedLoaderService } from './seed-loader'; import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts'; +import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; /** * #3433 — a curated seed is a snapshot of ESTABLISHED facts (a project already @@ -99,6 +100,7 @@ function createEnforcingEngine(): { engine: IDataEngine; store: Record { + assertEngineUpdateDispatch(data, undefined); const rows = store[objectName] || []; const idx = rows.findIndex((r) => r.id === data.id); if (idx >= 0) { 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 3f714dabc5..a643f27a9e 100644 --- a/packages/metadata-protocol/src/seed-loader-summary-stale.test.ts +++ b/packages/metadata-protocol/src/seed-loader-summary-stale.test.ts @@ -4,6 +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 { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; /** * framework#4998: a roll-up summary recompute that exhausts its retries must be @@ -59,6 +60,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineUpdateDispatch(data, undefined); const records = store[objectName] || []; const idx = records.findIndex((r) => r.id === data.id); if (idx >= 0) { records[idx] = { ...records[idx], ...data }; return records[idx]; } 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 363a02531b..eee5efe911 100644 --- a/packages/metadata-protocol/src/seed-loader-unresolved-drop.test.ts +++ b/packages/metadata-protocol/src/seed-loader-unresolved-drop.test.ts @@ -8,6 +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 { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; /** * framework#4997: a record DROPPED because its reference cannot be resolved — @@ -70,6 +71,7 @@ function createFaithfulEngine(): { engine: IDataEngine; store: Record { + assertEngineUpdateDispatch(data, undefined); const records = store[objectName] || []; const idx = records.findIndex((r) => r.id === data.id); if (idx >= 0) { records[idx] = { ...records[idx], ...data }; return records[idx]; } diff --git a/packages/objectql/src/protocol-meta-type-canonicalization.test.ts b/packages/objectql/src/protocol-meta-type-canonicalization.test.ts index e22cc449aa..cb998632b3 100644 --- a/packages/objectql/src/protocol-meta-type-canonicalization.test.ts +++ b/packages/objectql/src/protocol-meta-type-canonicalization.test.ts @@ -22,6 +22,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol'; import { SchemaRegistry } from './registry.js'; +import { assertEngineDeleteDispatch } from '@objectstack/metadata-core'; /** One env-wide, active overlay row for `rc1_probe`, stored under the canonical type. */ const OVERLAY_ROW = { @@ -66,6 +67,7 @@ describe('#4432 — canonical `/meta` type segment', () => { insert: vi.fn(async () => ({ id: 'new' })), update: vi.fn(async () => ({ id: 'row_1' })), delete: vi.fn(async (_t: string, opts: any) => { + assertEngineDeleteDispatch(opts); const id = opts?.where?.id; rows = rows.filter((r) => r.id !== id); return { deleted: 1 }; diff --git a/packages/plugins/plugin-security/src/claim-seed-ownership.test.ts b/packages/plugins/plugin-security/src/claim-seed-ownership.test.ts index 2fbc8fcc8d..098623f0d4 100644 --- a/packages/plugins/plugin-security/src/claim-seed-ownership.test.ts +++ b/packages/plugins/plugin-security/src/claim-seed-ownership.test.ts @@ -2,6 +2,7 @@ import { describe, it, expect, vi } from 'vitest'; import { claimSeedOwnership } from './claim-seed-ownership.js'; +import { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; const SYSTEM = 'usr_system'; const ADMIN = 'usr_admin_human'; @@ -19,6 +20,7 @@ function makeQL(schemas: any[], rowsByObject: Record) { return all; }), update: vi.fn(async (object: string, data: any) => { + assertEngineUpdateDispatch(data, undefined); updates.push({ object, data }); const row = (rowsByObject[object] ?? []).find((r) => r.id === data.id); if (row) row.owner_id = data.owner_id; 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 2ef2a66668..92addbca46 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 } from '@objectstack/objectql'; +import { SchemaRegistry, assertEngineUpdateDispatch, assertEngineDeleteDispatch } from '@objectstack/objectql'; import { resolveRouteActionDeclaration, type ActionExecutionDeps } from './action-execution.js'; /** @@ -72,11 +72,13 @@ function makeEngine(registry: SchemaRegistry) { return row; }), update: vi.fn(async (_table: string, data: any, opts: any) => { + assertEngineUpdateDispatch(data, opts); const target = rows.find((r) => matches(r, opts?.where ?? {})); if (target) Object.assign(target, data); return target ?? null; }), delete: vi.fn(async (_table: string, opts: any) => { + assertEngineDeleteDispatch(opts); const before = rows.length; rows = rows.filter((r) => !matches(r, opts?.where ?? {})); return { deleted: before - rows.length }; diff --git a/packages/runtime/src/seed-loader.test.ts b/packages/runtime/src/seed-loader.test.ts index 54159054a2..d3331ad30f 100644 --- a/packages/runtime/src/seed-loader.test.ts +++ b/packages/runtime/src/seed-loader.test.ts @@ -4,6 +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 { assertEngineUpdateDispatch } from '@objectstack/metadata-core'; // ========================================================================== // Mock Helpers @@ -56,6 +57,7 @@ function createMockEngine(data: Record = {}): IDataEngine { return record; }), update: vi.fn(async (objectName: string, data: any) => { + assertEngineUpdateDispatch(data, undefined); const records = store[objectName] || []; const idx = records.findIndex(r => r.id === data.id); if (idx >= 0) { diff --git a/scripts/check-engine-double-contract.mjs b/scripts/check-engine-double-contract.mjs index 7811ba73e0..04e121026c 100644 --- a/scripts/check-engine-double-contract.mjs +++ b/scripts/check-engine-double-contract.mjs @@ -350,19 +350,86 @@ function testFiles() { return out.sort(); } +/** + * The implementation a MOCK CONSTRUCTOR wraps, or null (#8639). + * + * `delete: vi.fn(async (o, opts) => …)` is a CallExpression, so the two + * initializer branches of `implOf` below used to answer `null` for it — + * `consider()` then returned before the sibling and shape tests ever ran, and + * the double was discovered by NEITHER side of a ledger that reconciles in both + * directions. Not "declared out of scope": absent. That is the DISCOVERED + * invariant's blind half, one layer down — `DISCOVERED != 0` catches a scan + * that breaks entirely and cannot catch a scan that quietly skips one spelling, + * and `vi.fn` is the spelling a test reaches for precisely when it wants to + * assert call counts on the double it just wrote. + * + * ## How wide to unwrap, measured rather than assumed + * + * Full census of the scanned corpus — every `delete`/`update` member whose + * initializer is a CallExpression, 310 of them, no truncation: + * + * 163 vi.fn() no argument at all + * 89 vi.fn(fn) ← the implementation + * 39 vi.fn().mockResolvedValue(value) a VALUE, not an implementation + * 9 rec('DELETE') local recorder factory, string arg + * 4 vi.fn().mockImplementation(fn) ← the implementation + * 3 record('DELETE') ditto + * 2 on('DELETE') ditto + * 1 vi.fn().mockRejectedValue(ERR()) a value, from a call + * + * So the criterion is STRUCTURAL and callee-agnostic: a call carrying EXACTLY + * ONE argument which is a function expression / arrow function. That admits the + * 93 that hold an implementation (`vi.fn(fn)` and, for free and correctly, the + * chained `.mockImplementation(fn)` — the arrow there IS what the double runs) + * and rejects all 217 that do not, without an allowlist of callee names that + * would go silently blind the day someone writes `vitest.fn` or a local wrapper. + * + * Deliberately NOT widened, both measured at ZERO occurrences on this corpus: + * + * - a function among SEVERAL arguments (`traced('delete', fn)`). The card's + * phrasing is "sole function argument" and the narrow reading is the one + * that cannot mistake a lifecycle callback for the verb's implementation. + * - a function in the chained receiver (`vi.fn(fn).mockResolvedValue(v)`), + * which would need this to recurse into `init.expression`. + * + * Both are measurements, not opinions — re-run that census before widening, + * exactly as the REPOSITORY_ONLY_MEMBERS note above asks. + * + * Note which way the remaining error leans. A `vi.fn()` with no argument stays + * `null` and stays undiscovered, and that is correct rather than a residual + * gap: there is no implementation to read, so there is no function for + * `isEngineVerbShape` to judge and nothing that could be looser than + * `ObjectQL.` — the double's behaviour is `undefined`, not a lax guard. + */ +function unwrapCallImpl(init) { + if (!ts.isCallExpression(init)) return null; + const args = init.arguments ?? []; + if (args.length !== 1) return null; + const only = args[0]; + if (ts.isFunctionExpression(only) || ts.isArrowFunction(only)) return only; + return null; +} + +/** + * One initializer reading, shared by BOTH initializer spellings below. + * + * Shared on purpose: the object-literal (`PropertyAssignment`) and class-field + * (`PropertyDeclaration`) branches carried the same three lines twice and drifted + * apart in exactly the way that produced #8639's sibling half — a fix applied to + * one spelling and not the other reproduces this card at the next reading. With + * one function there is no second copy to forget. + */ +function fnInitializer(init) { + if (!init) return null; + if (ts.isFunctionExpression(init) || ts.isArrowFunction(init)) return init; + return unwrapCallImpl(init); +} + /** A member's function-ish implementation, or null. */ function implOf(member) { if (ts.isMethodDeclaration(member) || ts.isMethodSignature(member)) return member; - if (ts.isPropertyAssignment(member)) { - const init = member.initializer; - if (init && (ts.isFunctionExpression(init) || ts.isArrowFunction(init))) return init; - return null; - } - if (ts.isPropertyDeclaration(member) && member.initializer) { - const init = member.initializer; - if (ts.isFunctionExpression(init) || ts.isArrowFunction(init)) return init; - return null; - } + if (ts.isPropertyAssignment(member)) return fnInitializer(member.initializer); + if (ts.isPropertyDeclaration(member)) return fnInitializer(member.initializer); if (ts.isShorthandPropertyAssignment(member)) return null; return null; } @@ -1507,6 +1574,73 @@ const engine = { d = scanSource('p.test.ts', arrowFake); expect('an arrow-property fake engine is in scope', d.length === 1 && d[0].pinned === false); + // ── The MOCK CONSTRUCTOR spelling (#8639). + // + // `delete: vi.fn(async …)` is a CallExpression, so `implOf` answered null and + // the double was discovered by NEITHER side of the ledger — no output at all, + // the same silence #5629 found behind the arity test. Each fixture below + // drives ONE arm of `unwrapCallImpl`, because this file has already measured + // what an unfixtured arm is worth: "with only the `new Error` fixture above, + // neutering the call-expression arm left the self-test GREEN". + const viFake = (init) => ` +const engine = { + find: vi.fn(async (o: string) => []), + insert: vi.fn(async (o: string, d: any) => d), + update: vi.fn(async (o: string, d: any) => d), + delete: ${init}, +}; +`; + d = scanSource('v.test.ts', viFake('vi.fn(async (o: string, opts?: any) => ({ ok: true }))')); + expect('a vi.fn-wrapped engine delete is in scope', d.length === 1 && d[0].pinned === false); + + d = scanSource('v.test.ts', IMPORT + + viFake('vi.fn(async (o: string, opts?: any) => { assertEngineDeleteDispatch(opts); return 1; })')); + expect('a vi.fn-wrapped delete that calls the predicate is pinned', + d.length === 1 && d[0].pinned === true); + + // `.mockImplementation(fn)` holds the implementation in the SAME position the + // criterion reads, so it is admitted by the same rule rather than a special case. + d = scanSource('v.test.ts', viFake('vi.fn().mockImplementation(async (o: string, opts?: any) => 1)')); + expect('a .mockImplementation-wrapped engine delete is in scope', d.length === 1); + + // The three call shapes that hold NO implementation must stay out: there is no + // function to judge, so there is nothing that could be looser than the producer. + expect('a bare vi.fn() with no argument is not an implementation', + scanSource('v.test.ts', viFake('vi.fn()')).length === 0); + expect('a call whose sole argument is not a function is not an implementation', + scanSource('v.test.ts', viFake("rec('DELETE')")).length === 0); + expect('a mock resolving to a VALUE is not an implementation', + scanSource('v.test.ts', viFake('vi.fn().mockResolvedValue(true)')).length === 0); + + // The CLASS-FIELD spelling of the same thing — `implOf`'s PropertyDeclaration + // branch. Measured at ZERO occurrences in the corpus the fix landed against, + // so this fixture is the only evidence that branch works at all; without it + // the branch would be reachable only by a future test nobody has written yet, + // which is exactly how the object-literal half stayed broken unnoticed. + const viClassFake = ` +class FakeEngine { + find = vi.fn(async (o: string) => []); + insert = vi.fn(async (o: string, d: any) => d); + update = vi.fn(async (o: string, d: any) => d); + delete = vi.fn(async (o: string, opts?: any) => ({ ok: true })); +} +`; + d = scanSource('vc.test.ts', viClassFake); + expect('a vi.fn-wrapped delete on a CLASS FIELD is in scope', d.length === 1 && d[0].pinned === false); + + // Unwrapping must not smuggle a double past the vetoes: the driver evidence + // still outranks, at the new spelling exactly as at every other one. + const viDriverFake = ` +const driver = { + find: vi.fn(async (o: string) => []), + create: vi.fn(async (o: string, d: any) => d), + update: vi.fn(async (o: string, id: string, d: any) => d), + delete: vi.fn(async (o: string, opts?: any) => true), +}; +`; + expect('a vi.fn-wrapped DRIVER delete stays out of scope', + scanSource('vd.test.ts', viDriverFake).length === 0); + // ── Arity: a fake omits the parameters it ignores (#5629). // // `async delete() { return false; }` is the commonest engine-double spelling @@ -2101,6 +2235,9 @@ class Svc { + "engine-vs-driver sibling evidence, accepts only that slice's producer predicate (direct or " + "one helper deep) and never the other slice's, rejects unused imports, hand-mirrored guards " + 'and look-alikes, keeps an engine double in scope however many by-id helpers it declares, ' + + 'reads the implementation a MOCK CONSTRUCTOR wraps on both the object-literal and the ' + + 'class-field spelling while refusing the three call shapes that wrap no implementation and ' + + 'still vetoing a driver at that spelling, ' + 'reports EXACTLY the engine double out of a fixture holding both shapes, and proves ' + 'discovery reaches the real tree for every slice; and, on the CONSUMER SEAMS, admits a ' + 'by-id write only when the id is caller-supplied AND a receipt is answered, reads the ' diff --git a/scripts/engine-double-contract.baseline.json b/scripts/engine-double-contract.baseline.json index 3bc041bfb9..cd01587ba9 100644 --- a/scripts/engine-double-contract.baseline.json +++ b/scripts/engine-double-contract.baseline.json @@ -41,7 +41,9 @@ "than EXEMPT. The `update` entries are weaker still and say so individually: they carry no", "per-file dormancy probe at all, because the update slice landed with 116 unguarded doubles", "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." + "them could have been pinned however carefully they were written.", + "", + "THE #8639 BATCH IS A FIRST MEASUREMENT, NOT A RAISED RATCHET. 29 (file, verb) entries below carry \"MEASURED (#8639)\". 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 the same PR (every one whose pin was a single call, with all four affected suites run green); the 29 entries here are the remainder, and each states individually why a one-line pin does not reach it — a signature that declares too few parameters to hand the predicate, a deliberate tripwire double whose body opens by throwing, a concise arrow body, or a package with no dependency on either home of the predicate. Adding entries here normally reads as weakening; this batch is the opposite, and is the same act #5629 and #5480 each recorded once before." ], "entries": [ { @@ -108,6 +110,206 @@ "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 100. The package does not depend on @objectstack/objectql yet, and the devDependency route is AVAILABLE rather than cyclic. This entry does not re-measure — the delete-slice entries for @objectstack/cloud-connection in this same ledger added the edge, recorded turbo's acceptance and reverted it, and the graph does not depend on which verb the pin is for. 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": "add @objectstack/objectql to this package's devDependencies (verified acyclic — see `why`), then open the fake's update with assertEngineUpdateDispatch(data, options)" }, + { + "file": "packages/mcp/src/mcp-stdio-tools.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 488. WHY NOT PINNED IN THE SAME PASS: `@objectstack/mcp` depends on NEITHER `@objectstack/metadata-core` NOR `@objectstack/objectql`, so a pin here is not one call — it needs a new devDependency on the package first, which is a dependency-graph change this card did not take. The implementation also declares no parameters, so the signature must be widened as well. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/mcp/src/mcp-stdio-tools.test.ts", + "verb": "update", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 488. WHY NOT PINNED IN THE SAME PASS: `@objectstack/mcp` depends on NEITHER `@objectstack/metadata-core` NOR `@objectstack/objectql`, so a pin here is not one call — it needs a new devDependency on the package first, which is a dependency-graph change this card did not take. The implementation also declares no parameters, so the signature must be widened as well. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s update with assertEngineUpdateDispatch(data, options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/mcp/src/mcp-write-response-internal-fields.tripwire.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 81. WHY NOT PINNED IN THE SAME PASS: `@objectstack/mcp` depends on NEITHER `@objectstack/metadata-core` NOR `@objectstack/objectql`, so a pin here is not one call — it needs a new devDependency on the package first, which is a dependency-graph change this card did not take. The implementation also declares no parameters, so the signature must be widened as well. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/mcp/src/mcp-write-response-internal-fields.tripwire.test.ts", + "verb": "update", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 81. WHY NOT PINNED IN THE SAME PASS: `@objectstack/mcp` depends on NEITHER `@objectstack/metadata-core` NOR `@objectstack/objectql`, so a pin here is not one call — it needs a new devDependency on the package first, which is a dependency-graph change this card did not take. The implementation also declares no parameters, so the signature must be widened as well. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s update with assertEngineUpdateDispatch(data, options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/mcp/src/plugin.record-resource-exposure.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 157. WHY NOT PINNED IN THE SAME PASS: `@objectstack/mcp` depends on NEITHER `@objectstack/metadata-core` NOR `@objectstack/objectql`, so a pin here is not one call — it needs a new devDependency on the package first, which is a dependency-graph change this card did not take. The implementation also declares no parameters, so the signature must be widened as well. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/mcp/src/plugin.record-resource-exposure.test.ts", + "verb": "update", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 157. WHY NOT PINNED IN THE SAME PASS: `@objectstack/mcp` depends on NEITHER `@objectstack/metadata-core` NOR `@objectstack/objectql`, so a pin here is not one call — it needs a new devDependency on the package first, which is a dependency-graph change this card did not take. The implementation also declares no parameters, so the signature must be widened as well. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s update with assertEngineUpdateDispatch(data, options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/protocol.dropped-fields.test.ts", + "verb": "update", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 77. WHY NOT PINNED IN THE SAME PASS: the implementation is a concise-bodied arrow (an expression body, no statement list), so there is no first statement to insert the predicate call in front of — a pin must convert the body to a block first. Mechanical, but an edit to the double’s shape rather than a routing change, so it belongs with the per-package batch. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s update with assertEngineUpdateDispatch(data, options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/protocol.lock-gate-fail-closed.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 160. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/protocol.lock-gate-fail-closed.test.ts", + "verb": "update", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 160. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s update with assertEngineUpdateDispatch(data, options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/protocol.validate-data.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 26. WHY NOT PINNED IN THE SAME PASS: this double is a deliberate TRIPWIRE — its body opens by throwing, because the test asserts that the path under test performs no write at all. Routing it through the dispatch predicate would change WHICH error the assertion sees, so pinning it is a change to the test’s meaning and needs the author’s intent read, not a mechanical insert. It also declares too few parameters to hand the predicate anything. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/protocol.validate-data.test.ts", + "verb": "update", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 26. WHY NOT PINNED IN THE SAME PASS: this double is a deliberate TRIPWIRE — its body opens by throwing, because the test asserts that the path under test performs no write at all. Routing it through the dispatch predicate would change WHICH error the assertion sees, so pinning it is a change to the test’s meaning and needs the author’s intent read, not a mechanical insert. It also declares too few parameters to hand the predicate anything. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s update with assertEngineUpdateDispatch(data, options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-composite-external-id.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 34. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-deferred-dropped.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 43. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-deferred-failure.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 28. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-driver-text.test.ts", + "verb": "delete", + "unguarded": 2, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at lines 145, 209. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-driver-text.test.ts", + "verb": "update", + "unguarded": 2, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at lines 145, 209. WHY NOT PINNED IN THE SAME PASS: this double is a deliberate TRIPWIRE — its body opens by throwing, because the test asserts that the path under test performs no write at all. Routing it through the dispatch predicate would change WHICH error the assertion sees, so pinning it is a change to the test’s meaning and needs the author’s intent read, not a mechanical insert. It also declares too few parameters to hand the predicate anything. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s update with assertEngineUpdateDispatch(data, options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-engine-schema-fallback.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 38. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-env-scope.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 41. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-env-scope.test.ts", + "verb": "update", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 41. WHY NOT PINNED IN THE SAME PASS: the implementation is a concise-bodied arrow (an expression body, no statement list), so there is no first statement to insert the predicate call in front of — a pin must convert the body to a block first. Mechanical, but an edit to the double’s shape rather than a routing change, so it belongs with the per-package batch. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s update with assertEngineUpdateDispatch(data, options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-multi-value-reference.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 35. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-replay.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 29. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-retry.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 24. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-state-machine-exempt.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 68. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-summary-stale.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 36. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/metadata-protocol/src/seed-loader-unresolved-drop.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 47. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, { "file": "packages/objectql/src/protocol-boot-hydration-scoped.test.ts", "verb": "delete", @@ -116,6 +318,14 @@ "why": "MEASURED (#5629): newly VISIBLE, not newly written — the fake's `delete` declares no parameters, and the gate's arity test (`params.length < 2` was the first line of `isEngineDeleteShape`) discarded such deletes before any other criterion ran. So this double reached neither PINNED nor this ledger and produced no output at all: the #4868 shape the DISCOVERED invariant above is written against. Discovered at line 59. 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. This IS the producer's own package: `./engine-delete-dispatch.js` is a relative import away, exactly as objectql's already-pinned tests import it. A one-line pin whenever a batch takes it — deferred here because #5629's first batch is the criterion plus the ledger, not adoption.", "closes": "open the fake's delete with assertEngineDeleteDispatch(options) imported from ./engine-delete-dispatch.js, and run the package's suite" }, + { + "file": "packages/objectql/src/protocol-meta-type-canonicalization.test.ts", + "verb": "update", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 53. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s update with assertEngineUpdateDispatch(data, options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, { "file": "packages/objectql/src/protocol-registry-shadow.test.ts", "verb": "delete", @@ -300,6 +510,22 @@ "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 77. The package already depends on @objectstack/objectql (`devDependencies`), 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/plugins/plugin-auth/src/auth-manager.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 895. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, + { + "file": "packages/plugins/plugin-auth/src/auth-manager.test.ts", + "verb": "update", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 895. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s update with assertEngineUpdateDispatch(data, options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, { "file": "packages/plugins/plugin-auth/src/org-create-posture-gate.test.ts", "verb": "update", @@ -700,6 +926,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/seed-loader.test.ts", + "verb": "delete", + "unguarded": 1, + "kind": "DEBT", + "why": "MEASURED (#8639): FIRST MEASUREMENT, NOT A RAISED RATCHET. This (file, verb) is newly VISIBLE, not newly written and not newly loosened. The double spells this verb `vi.fn(async …)`, which is a CallExpression, and `implOf` answered null for a call-expression initializer — so `consider()` returned before the sibling and shape tests ever ran and this double reached NEITHER the `pinned` listing NOR this ledger. It produced no output on either side of a ledger that reconciles in both directions: the #4868 shape the DISCOVERED invariant above is written against, one spelling deep. #8639 taught `implOf` to unwrap a call whose sole argument is a function, and that is the ONLY reason there is an entry here to read. Precisely the act #5629 recorded when it stopped discarding deletes that declare no parameters, and #5480 when the `update` slice first landed — both already in this script’s comments, both saying in as many words that a first measurement is not a raised ratchet. The #8639 batch pinned every double whose pin was ONE CALL (21 of them, across metadata-protocol / objectql / runtime / plugin-security, all four suites green); this entry is one of the remainder, each of which needs more than a one-line pin. Discovered at line 29. WHY NOT PINNED IN THE SAME PASS: the implementation declares fewer than two parameters, so it has no binding to hand the predicate — a pin must first WIDEN THE SIGNATURE (add the options bag / payload the fake currently omits), which changes the double rather than routing it, and is a per-file edit whose suite has not been run under the guard. That is the per-package batch #5629 and #5480 both deferred for the same reason, not a claim that this double is acceptable. WHAT THIS ENTRY DOES NOT CLAIM: 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 the producer on the shape a hand-written guard always drops (`where: { id: { $in: [...] } }` looks like an id and is a multi-row predicate).", + "closes": "open the fake’s delete with assertEngineDeleteDispatch(options) — widening the signature and/or adding the dependency as noted — and run the package’s suite" + }, { "file": "packages/services/service-automation/src/builtin/crud-bulk-intent.test.ts", "verb": "update",