diff --git a/scripts/check-engine-double-contract.mjs b/scripts/check-engine-double-contract.mjs index ac8ab6dc5b..f0bde88e09 100644 --- a/scripts/check-engine-double-contract.mjs +++ b/scripts/check-engine-double-contract.mjs @@ -114,6 +114,35 @@ const ENGINE_SIBLINGS = new Set([ /** Parameter names that mean "this is the DRIVER's delete(object, id, options)". */ const ID_PARAM = /^_*(id|recordId|ids|pk)$/i; +/** + * Members present on `IDataDriver` and on NEITHER `IDataEngine` nor the ObjectQL + * class — so declaring one is positive evidence of the DRIVER contract. + * + * Consulted only when the parameter test cannot answer (see `isEngineDeleteShape`). + * Deliberately excludes every name both contracts share — `find`, `findOne`, + * `update`, `count`, `delete` and `execute` (the engine declares `execute?` too, + * `data-engine.ts`) — because a name on both sides separates nothing. + */ +const DRIVER_ONLY_MEMBERS = new Set([ + 'connect', 'disconnect', 'checkHealth', 'getPoolStats', 'create', 'upsert', + 'bulkCreate', 'bulkUpdate', 'bulkDelete', 'updateMany', 'deleteMany', + 'beginTransaction', 'commit', 'rollback', 'syncSchema', 'syncSchemasBatch', + 'registerExternalObject', 'getSchemaSyncStats', 'dropTable', 'reclaimSpace', + 'explain', 'temporalFilterValue', 'temporalFilterColumnSql', +]); + +/** + * The engine-side half of the same evidence: on `IDataEngine` (`insert`, + * `aggregate`) or on the ObjectQL class itself (`getSchema`, `registry`, + * `insertMany`), and absent from `IDataDriver`. + * + * A subset of ENGINE_SIBLINGS, and the distinction is the whole point: `find` / + * `findOne` / `update` / `count` are engine siblings for DISCOVERY (they mark a + * data-access object) while being useless for ATTRIBUTION (drivers speak all + * four). Only the names here answer "engine, not driver". + */ +const ENGINE_ONLY_MEMBERS = new Set(['insert', 'insertMany', 'aggregate', 'getSchema', 'registry']); + // ── Discovery ─────────────────────────────────────────────────────────────── function walk(dir, out = []) { @@ -169,10 +198,43 @@ function memberName(member) { * The second parameter is the whole question: the engine takes an options bag * there, the driver takes a primary key. Judged on the name first (the repo * writes `id` when it means one) and on a scalar type annotation second. + * + * ## When there IS no second parameter (#5629) + * + * A fake omits the parameters it ignores — `async delete() { return false; }` — + * and this function used to open with `if (params.length < 2) return false`, + * which discarded the double before any other test ran. Not "declared out of + * scope": unreachable. Those deletes reached neither PINNED nor the ledger and + * produced no output at all, which is the #4868 shape this script's own + * DISCOVERED invariant is written against. Measured on this branch: 92 such + * deletes behind that one line, 0 of them pinned. + * + * So when arity cannot answer, the SIBLING SET answers instead — and it has to + * be a real test, not a waved-through `return true`. #5629's premise for a + * blanket admit ("a zero-parameter delete cannot be the driver's, since the + * driver's signature has a primary-key position") does not survive measurement: + * fake DRIVERS drop their unused parameters exactly like fake engines do, so 43 + * of those 92 are driver doubles — `spec/src/contracts/data-driver.test.ts` + * itself, and `objectql/src/engine-aggregate-having.test.ts`'s self-described + * "driver WITH native aggregate()". Admitting them unconditionally would have + * pointed this gate at the wrong contract 43 times. + * + * The evidence that does separate them is which members the object declares + * ALONGSIDE delete: it must show a member only the engine has, and none that + * only the driver has. Both halves are load-bearing — `aggregate` alone admits + * the native-aggregate driver above, and "no driver members" alone admits any + * `{ find, findOne, update, delete }` store mock that is neither contract. */ -function isEngineDeleteShape(fn) { +function isEngineDeleteShape(fn, memberNames = new Set()) { const params = fn.parameters ?? []; - if (params.length < 2) return false; + if (params.length < 2) { + let engineEvidence = false; + for (const n of memberNames) { + if (DRIVER_ONLY_MEMBERS.has(n)) return false; + if (ENGINE_ONLY_MEMBERS.has(n)) engineEvidence = true; + } + return engineEvidence; + } const second = params[1]; const name = ts.isIdentifier(second.name) ? second.name.text : ''; if (ID_PARAM.test(name)) return false; @@ -279,7 +341,7 @@ function scanSource(fileName, text) { if (!del) return; const siblings = [...names].filter((n) => ENGINE_SIBLINGS.has(n)); if (siblings.length < 2) return; - if (!isEngineDeleteShape(del)) return; + if (!isEngineDeleteShape(del, names)) return; const line = sf.getLineAndCharacterOfPosition(node.getStart(sf)).line + 1; doubles.push({ line, siblings: siblings.sort(), pinned: bodyIsPinned(del) }); }; @@ -508,6 +570,82 @@ const engine = { d = scanSource('p.test.ts', arrowFake); expect('an arrow-property fake engine is in scope', d.length === 1 && d[0].pinned === false); + // ── Arity: a fake omits the parameters it ignores (#5629). + // + // `async delete() { return false; }` is the commonest engine-double spelling + // in this repo, and it used to leave the scan before any other test ran — 92 + // deletes, none of them pinned, none of them in the ledger, no output. These + // cases drive both halves of the sibling evidence that admits them now, + // because the obvious cheap fix (admit every short-arity delete) is WRONG: + // fake drivers drop their unused parameters exactly like fake engines do. + const zeroArityEngine = ` +const engine = { + async find(o: string) { return []; }, + async findOne(o: string) { return null; }, + async insert(o: string, d: any) { return d; }, + async update(o: string, d: any) { return d; }, + async delete() { return false; }, +}; +`; + d = scanSource('z.test.ts', zeroArityEngine); + expect('a zero-parameter engine delete is in scope', d.length === 1 && d[0].pinned === false); + + // Same shape, one parameter — `action-body-identity.test.ts`'s scoped facade. + const oneArityEngine = ` +const engine = { + find: async (o: string) => [], + insert: async (o: string, d: any) => d, + update: async (o: string, d: any) => d, + delete: async (opts?: any) => ({ ok: true }), +}; +`; + d = scanSource('y.test.ts', oneArityEngine); + expect('a single-parameter engine delete is in scope', d.length === 1 && d[0].pinned === false); + + // A fake DRIVER with the same zero-parameter delete must stay out: driver-only + // members veto. `spec/src/contracts/data-driver.test.ts` is this shape. + const zeroArityDriver = ` +const driver = { + async find(o: string) { return []; }, + async findOne(o: string) { return null; }, + async update(o: string, id: string, d: any) { return d; }, + async create(o: string, d: any) { return d; }, + async checkHealth() { return true; }, + async delete() { return true; }, +}; +`; + expect('a zero-parameter DRIVER delete stays out of scope', + scanSource('zd.test.ts', zeroArityDriver).length === 0); + + // The veto has to outrank engine-looking evidence, or `engine-aggregate- + // having.test.ts`'s self-described "driver WITH native aggregate()" is read as + // an engine: drivers may implement `aggregate` for pushdown. + const nativeAggregateDriver = ` +const driver = { + async find() { return []; }, + async count() { return 0; }, + async create(o: string, d: any) { return d; }, + async bulkCreate(o: string, rows: any[]) { return rows; }, + async aggregate(o: string, ast: any) { return []; }, + async delete() { return true; }, +}; +`; + expect('a zero-parameter driver that implements aggregate() stays out of scope', + scanSource('zn.test.ts', nativeAggregateDriver).length === 0); + + // And the positive half must be required too, or every `{ find, findOne, + // update, delete }` store mock — neither contract — becomes a finding. + const zeroArityStoreMock = ` +const store = { + async find(k: string) { return []; }, + async findOne(k: string) { return null; }, + async update(k: string, v: any) { return v; }, + async delete() { return true; }, +}; +`; + expect('a zero-parameter mock with no engine-only member stays out of scope', + scanSource('zs.test.ts', zeroArityStoreMock).length === 0); + // The import must come from the producer. A same-named local function is not // the contract — the whole point is that ONE predicate answers. d = scanSource('q.test.ts', engineFake('assertEngineDeleteDispatch(opts); return 1;', @@ -547,9 +685,10 @@ const engine = { process.exit(1); } console.log( - 'OK self-test: separates engine doubles from driver doubles, accepts only the producer\'s ' - + 'predicate (direct or one helper deep), rejects unused imports, hand-mirrored guards and ' - + 'look-alikes, and proves discovery reaches the real tree.', + 'OK self-test: separates engine doubles from driver doubles, admits a delete that declares ' + + 'fewer than two parameters only on engine-vs-driver sibling evidence, accepts only the ' + + 'producer\'s predicate (direct or one helper deep), rejects unused imports, hand-mirrored ' + + 'guards and look-alikes, and proves discovery reaches the real tree.', ); } diff --git a/scripts/engine-double-contract.baseline.json b/scripts/engine-double-contract.baseline.json index af52f9afcd..3c593a135c 100644 --- a/scripts/engine-double-contract.baseline.json +++ b/scripts/engine-double-contract.baseline.json @@ -24,6 +24,48 @@ "than EXEMPT." ], "entries": [ + { + "file": "packages/cli/src/commands/serve-email-appname-precedence.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 164. 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. The package DOES depend on @objectstack/objectql, so this is a one-line pin whenever a batch takes it — deferred here because #5629's first batch is the criterion plus the ledger, and flipping ~three dozen unmeasured suites red belongs in the per-package batches that follow.", + "closes": "open the fake's delete with assertEngineDeleteDispatch(options) and run the package's suite" + }, + { + "file": "packages/cli/src/commands/serve-email-persist.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 121. 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. The package DOES depend on @objectstack/objectql, so this is a one-line pin whenever a batch takes it — deferred here because #5629's first batch is the criterion plus the ledger, and flipping ~three dozen unmeasured suites red belongs in the per-package batches that follow.", + "closes": "open the fake's delete with assertEngineDeleteDispatch(options) and run the package's suite" + }, + { + "file": "packages/cloud-connection/src/marketplace-install-local-seed-lookup.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 81. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/cloud-connection --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/cloud-connection/src/marketplace-install-local-state-machine-exempt.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 100. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/cloud-connection --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/core/src/utils/migration-journal.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 34. 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. The devDependency route DOES NOT EXIST for this package: @objectstack/objectql depends on it (@objectstack/objectql -> @objectstack/core, both `dependencies`), so any reverse edge closes a cycle by construction. Measured on this branch: the edge was added to @objectstack/core's devDependencies and turbo 2.10.7 refused the graph outright — `WARNING Circular package dependency detected: @objectstack/driver-sql, @objectstack/driver-sqlite-wasm, @objectstack/metadata, @objectstack/metadata-protocol, @objectstack/objectql, @objectstack/core` and `x Cyclic dependency detected:` from `turbo run build --filter=@objectstack/core --dry` — then the edge was reverted. Same route, same refusal the #4987 and #5206 entries in this ledger already record for metadata-protocol.", + "closes": "sink assertEngineDeleteDispatch into a package BOTH sides already depend on — tracked as #5619 — then open the fake's delete with it. The devDependency route is closed by the cycle recorded in `why`, exactly as for the metadata-protocol entries in this ledger." + }, + { + "file": "packages/metadata-protocol/src/migrations/recorded-by-sentinel.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 35. 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. The devDependency route DOES NOT EXIST for this package: @objectstack/objectql depends on it (@objectstack/objectql -> @objectstack/metadata-protocol, both `dependencies`), so any reverse edge closes a cycle by construction. Measured twice already, and this entry does not re-measure: the #4987 and #5206 entries in this ledger added the edge to @objectstack/metadata-protocol's devDependencies and recorded turbo's outright refusal. This package is also named in the cycle turbo printed on THIS branch when the same edge was added to @objectstack/core.", + "closes": "sink assertEngineDeleteDispatch into a package BOTH sides already depend on — tracked as #5619 — then open the fake's delete with it. The devDependency route is closed by the cycle recorded in `why`, exactly as for the metadata-protocol entries in this ledger." + }, { "file": "packages/metadata-protocol/src/protocol-publish-drafts-endpoint-gate.test.ts", "unguarded": 1, @@ -38,6 +80,20 @@ "why": "MEASURED (#4987): the devDependency route this entry used to prescribe DOES NOT EXIST — it is cyclic, not merely unreviewed. @objectstack/objectql depends on @objectstack/metadata-protocol in `dependencies` (`workspace:*`), so any reverse edge closes a cycle by construction. Re-measured on #4987's branch rather than cited: the edge was added to metadata-protocol's devDependencies and turbo 2.10.7 refused BOTH task graphs outright — `WARNING Circular package dependency detected: @objectstack/objectql, @objectstack/metadata-protocol` / `x Cyclic dependency detected: @objectstack/objectql#build, @objectstack/metadata-protocol#build`, exit 1 from `turbo run build --filter=@objectstack/metadata-protocol --dry` and from the same command with `test` — then the edge was reverted. This is exactly the criterion the `packages/spec/src/contracts/data-engine.test.ts` EXEMPT entry below already states ('it cannot be pinned even in principle ... the import would invert the dependency'); it was simply never applied to the metadata-protocol entries. The entry stays DEBT and not EXEMPT because what cannot exist is the devDependency ROUTE, while the entry itself is closable by sinking the predicate — see `closes`. Whether this file's own fake delete is currently exercised was NOT probed: #4987's file face is this ledger's text only. Per this ledger's own rule that changes nothing, since it would be an argument about this file rather than about the contract.", "closes": "sink assertEngineDeleteDispatch into a package BOTH sides already depend on — tracked as #5619 — then open the fake's delete with it. Verified available on #4987's branch: @objectstack/objectql and @objectstack/metadata-protocol both already depend on @objectstack/metadata-core (`workspace:*`), whose own `dependencies` are just @objectstack/spec + zod and do NOT include objectql, so the sink adds no new edge; the producer `packages/objectql/src/engine-delete-dispatch.ts` has zero imports, so this is a move and not a refactor. @objectstack/spec/contracts is the other candidate, but only if the predicate belongs to the contract layer — do not pick it by default. The devDependency route is closed by the cycle recorded in `why`, for this file and for every other metadata-protocol entry in this ledger alike." }, + { + "file": "packages/metadata-protocol/src/protocol.code-only-types.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 88. 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. The devDependency route DOES NOT EXIST for this package: @objectstack/objectql depends on it (@objectstack/objectql -> @objectstack/metadata-protocol, both `dependencies`), so any reverse edge closes a cycle by construction. Measured twice already, and this entry does not re-measure: the #4987 and #5206 entries in this ledger added the edge to @objectstack/metadata-protocol's devDependencies and recorded turbo's outright refusal. This package is also named in the cycle turbo printed on THIS branch when the same edge was added to @objectstack/core.", + "closes": "sink assertEngineDeleteDispatch into a package BOTH sides already depend on — tracked as #5619 — then open the fake's delete with it. The devDependency route is closed by the cycle recorded in `why`, exactly as for the metadata-protocol entries in this ledger." + }, + { + "file": "packages/metadata-protocol/src/protocol.read-decorations.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 60. 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. The devDependency route DOES NOT EXIST for this package: @objectstack/objectql depends on it (@objectstack/objectql -> @objectstack/metadata-protocol, both `dependencies`), so any reverse edge closes a cycle by construction. Measured twice already, and this entry does not re-measure: the #4987 and #5206 entries in this ledger added the edge to @objectstack/metadata-protocol's devDependencies and recorded turbo's outright refusal. This package is also named in the cycle turbo printed on THIS branch when the same edge was added to @objectstack/core.", + "closes": "sink assertEngineDeleteDispatch into a package BOTH sides already depend on — tracked as #5619 — then open the fake's delete with it. The devDependency route is closed by the cycle recorded in `why`, exactly as for the metadata-protocol entries in this ledger." + }, { "file": "packages/metadata-protocol/src/protocol.runtime-authoring-gate.test.ts", "unguarded": 1, @@ -52,6 +108,27 @@ "why": "MEASURED (#4987): the devDependency route this entry used to prescribe DOES NOT EXIST — it is cyclic, not merely unreviewed. @objectstack/objectql depends on @objectstack/metadata-protocol in `dependencies` (`workspace:*`), so any reverse edge closes a cycle by construction. Re-measured on #4987's branch rather than cited: the edge was added to metadata-protocol's devDependencies and turbo 2.10.7 refused BOTH task graphs outright — `WARNING Circular package dependency detected: @objectstack/objectql, @objectstack/metadata-protocol` / `x Cyclic dependency detected: @objectstack/objectql#build, @objectstack/metadata-protocol#build`, exit 1 from `turbo run build --filter=@objectstack/metadata-protocol --dry` and from the same command with `test` — then the edge was reverted. This is exactly the criterion the `packages/spec/src/contracts/data-engine.test.ts` EXEMPT entry below already states ('it cannot be pinned even in principle ... the import would invert the dependency'); it was simply never applied to the metadata-protocol entries. The entry stays DEBT and not EXEMPT because what cannot exist is the devDependency ROUTE, while the entry itself is closable by sinking the predicate — see `closes`. Whether this file's own fake delete is currently exercised was NOT probed: #4987's file face is this ledger's text only. Per this ledger's own rule that changes nothing, since it would be an argument about this file rather than about the contract.", "closes": "sink assertEngineDeleteDispatch into a package BOTH sides already depend on — tracked as #5619 — then open the fake's delete with it. Verified available on #4987's branch: @objectstack/objectql and @objectstack/metadata-protocol both already depend on @objectstack/metadata-core (`workspace:*`), whose own `dependencies` are just @objectstack/spec + zod and do NOT include objectql, so the sink adds no new edge; the producer `packages/objectql/src/engine-delete-dispatch.ts` has zero imports, so this is a move and not a refactor. @objectstack/spec/contracts is the other candidate, but only if the predicate belongs to the contract layer — do not pick it by default. The devDependency route is closed by the cycle recorded in `why`, for this file and for every other metadata-protocol entry in this ledger alike." }, + { + "file": "packages/metadata-protocol/src/protocol.save-union-issues.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 45. 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. The devDependency route DOES NOT EXIST for this package: @objectstack/objectql depends on it (@objectstack/objectql -> @objectstack/metadata-protocol, both `dependencies`), so any reverse edge closes a cycle by construction. Measured twice already, and this entry does not re-measure: the #4987 and #5206 entries in this ledger added the edge to @objectstack/metadata-protocol's devDependencies and recorded turbo's outright refusal. This package is also named in the cycle turbo printed on THIS branch when the same edge was added to @objectstack/core.", + "closes": "sink assertEngineDeleteDispatch into a package BOTH sides already depend on — tracked as #5619 — then open the fake's delete with it. The devDependency route is closed by the cycle recorded in `why`, exactly as for the metadata-protocol entries in this ledger." + }, + { + "file": "packages/metadata-protocol/src/protocol.stored-conversions.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 51. 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. The devDependency route DOES NOT EXIST for this package: @objectstack/objectql depends on it (@objectstack/objectql -> @objectstack/metadata-protocol, both `dependencies`), so any reverse edge closes a cycle by construction. Measured twice already, and this entry does not re-measure: the #4987 and #5206 entries in this ledger added the edge to @objectstack/metadata-protocol's devDependencies and recorded turbo's outright refusal. This package is also named in the cycle turbo printed on THIS branch when the same edge was added to @objectstack/core.", + "closes": "sink assertEngineDeleteDispatch into a package BOTH sides already depend on — tracked as #5619 — then open the fake's delete with it. The devDependency route is closed by the cycle recorded in `why`, exactly as for the metadata-protocol entries in this ledger." + }, + { + "file": "packages/metadata-protocol/src/protocol.stored-migration.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 73. 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. The devDependency route DOES NOT EXIST for this package: @objectstack/objectql depends on it (@objectstack/objectql -> @objectstack/metadata-protocol, both `dependencies`), so any reverse edge closes a cycle by construction. Measured twice already, and this entry does not re-measure: the #4987 and #5206 entries in this ledger added the edge to @objectstack/metadata-protocol's devDependencies and recorded turbo's outright refusal. This package is also named in the cycle turbo printed on THIS branch when the same edge was added to @objectstack/core.", + "closes": "sink assertEngineDeleteDispatch into a package BOTH sides already depend on — tracked as #5619 — then open the fake's delete with it. The devDependency route is closed by the cycle recorded in `why`, exactly as for the metadata-protocol entries in this ledger." + }, { "file": "packages/metadata-protocol/src/sys-metadata-repository.draft-drain.test.ts", "unguarded": 1, @@ -73,6 +150,27 @@ "why": "MEASURED (#4987): the devDependency route this entry used to prescribe DOES NOT EXIST — it is cyclic, not merely unreviewed. @objectstack/objectql depends on @objectstack/metadata-protocol in `dependencies` (`workspace:*`), so any reverse edge closes a cycle by construction. Re-measured on #4987's branch rather than cited: the edge was added to metadata-protocol's devDependencies and turbo 2.10.7 refused BOTH task graphs outright — `WARNING Circular package dependency detected: @objectstack/objectql, @objectstack/metadata-protocol` / `x Cyclic dependency detected: @objectstack/objectql#build, @objectstack/metadata-protocol#build`, exit 1 from `turbo run build --filter=@objectstack/metadata-protocol --dry` and from the same command with `test` — then the edge was reverted. This is exactly the criterion the `packages/spec/src/contracts/data-engine.test.ts` EXEMPT entry below already states ('it cannot be pinned even in principle ... the import would invert the dependency'); it was simply never applied to the metadata-protocol entries. The entry stays DEBT and not EXEMPT because what cannot exist is the devDependency ROUTE, while the entry itself is closable by sinking the predicate — see `closes`. Whether this file's own fake delete is currently exercised was NOT probed: #4987's file face is this ledger's text only. Per this ledger's own rule that changes nothing, since it would be an argument about this file rather than about the contract.", "closes": "sink assertEngineDeleteDispatch into a package BOTH sides already depend on — tracked as #5619 — then open the fake's delete with it. Verified available on #4987's branch: @objectstack/objectql and @objectstack/metadata-protocol both already depend on @objectstack/metadata-core (`workspace:*`), whose own `dependencies` are just @objectstack/spec + zod and do NOT include objectql, so the sink adds no new edge; the producer `packages/objectql/src/engine-delete-dispatch.ts` has zero imports, so this is a move and not a refactor. @objectstack/spec/contracts is the other candidate, but only if the predicate belongs to the contract layer — do not pick it by default. The devDependency route is closed by the cycle recorded in `why`, for this file and for every other metadata-protocol entry in this ledger alike." }, + { + "file": "packages/metadata/src/migrations/migrate-sys-notification-to-event.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 40. 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. The devDependency route DOES NOT EXIST for this package: @objectstack/objectql depends on it (@objectstack/objectql -> @objectstack/metadata-protocol -> @objectstack/metadata, every edge `dependencies`), so any reverse edge closes a cycle by construction. This package's own edge was NOT probed separately on this branch, and does not need to be: @objectstack/metadata is named IN the cycle turbo 2.10.7 printed when the same edge was added to @objectstack/core here — `@objectstack/driver-sql, @objectstack/driver-sqlite-wasm, @objectstack/metadata, @objectstack/metadata-protocol, @objectstack/objectql, @objectstack/core`. Stated plainly so the next reader knows which measurement this rests on.", + "closes": "sink assertEngineDeleteDispatch into a package BOTH sides already depend on — tracked as #5619 — then open the fake's delete with it. The devDependency route is closed by the cycle recorded in `why`, exactly as for the metadata-protocol entries in this ledger." + }, + { + "file": "packages/objectql/src/protocol-boot-hydration-scoped.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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-registry-shadow.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 255. 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/plugins/plugin-approvals/src/approval-actor-impersonation.test.ts", "unguarded": 1, @@ -80,6 +178,13 @@ "why": "The package DOES depend on @objectstack/objectql, so this is a one-line pin — deferred only because this PR's slice is the gate plus the package #4434 came from, and an unmeasured suite flipping red belongs in its own PR.", "closes": "open the fake's delete with assertEngineDeleteDispatch(opts) and run the package's suite" }, + { + "file": "packages/plugins/plugin-approvals/src/approval-node-degradation.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 24. 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. @objectstack/objectql is already in this package's devDependencies (added when an earlier double in the same package was pinned), so this is 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) and run the package's suite — the devDependency is already declared" + }, { "file": "packages/plugins/plugin-approvals/src/approval-node.test.ts", "unguarded": 1, @@ -115,6 +220,20 @@ "why": "The package DOES depend on @objectstack/objectql, so this is a one-line pin — deferred only because this PR's slice is the gate plus the package #4434 came from, and an unmeasured suite flipping red belongs in its own PR.", "closes": "open the fake's delete with assertEngineDeleteDispatch(opts) and run the package's suite" }, + { + "file": "packages/plugins/plugin-approvals/src/approver-cross-org.integration.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 45. 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. @objectstack/objectql is already in this package's devDependencies (added when an earlier double in the same package was pinned), so this is 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) and run the package's suite — the devDependency is already declared" + }, + { + "file": "packages/plugins/plugin-approvals/src/stranded-request-inspection.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 42. 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. @objectstack/objectql is already in this package's devDependencies (added when an earlier double in the same package was pinned), so this is 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) and run the package's suite — the devDependency is already declared" + }, { "file": "packages/plugins/plugin-auth/src/auth-manager.optional-plugin-isolation.test.ts", "unguarded": 1, @@ -157,6 +276,13 @@ "why": "@objectstack/plugin-security does not depend on @objectstack/objectql. Pinning needs a devDependency + lockfile change, which is a separate reviewable act.", "closes": "add @objectstack/objectql to devDependencies, then open the fake's delete with assertEngineDeleteDispatch(opts)" }, + { + "file": "packages/plugins/plugin-sharing/src/share-link-service.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 20. 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. The package DOES depend on @objectstack/objectql, so this is a one-line pin whenever a batch takes it — deferred here because #5629's first batch is the criterion plus the ledger, and flipping ~three dozen unmeasured suites red belongs in the per-package batches that follow.", + "closes": "open the fake's delete with assertEngineDeleteDispatch(options) and run the package's suite" + }, { "file": "packages/plugins/plugin-webhooks/src/auto-enqueuer.test.ts", "unguarded": 1, @@ -165,12 +291,54 @@ "closes": "add @objectstack/objectql to devDependencies, then open the fake's delete with assertEngineDeleteDispatch(opts)" }, { - "file": "packages/runtime/src/action-body-identity.test.ts", + "file": "packages/plugins/plugin-webhooks/src/bootstrap-declared-webhooks.test.ts", "unguarded": 1, "kind": "DEBT", - "why": "The package DOES depend on @objectstack/objectql, so this is a one-line pin — deferred only because this PR's slice is the gate plus the package #4434 came from, and an unmeasured suite flipping red belongs in its own PR.", + "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 34. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/plugin-webhooks --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/runtime/src/action-body-identity.test.ts", + "unguarded": 2, + "kind": "DEBT", + "why": "The package DOES depend on @objectstack/objectql, so this is a one-line pin — deferred only because this PR's slice is the gate plus the package #4434 came from, and an unmeasured suite flipping red belongs in its own PR. RE-MEASURED (#5629): this entry's count moves 1 -> 2 without a line of test code changing — 1 further double in this file (line 71) became visible when #5629 stopped discarding deletes that declare no parameters. Not a regression and not a raised ratchet: the doubles were always here, the scan could not reach them. The second double is not an independent fake: it is the `createContext().object(name)` scoped facade whose `delete` forwards to the SAME fake engine already recorded by this entry. Pinning the outer fake closes both, so this count returning to 1 and then 0 is the expected shape. Dormant looseness, probed rather than assumed: a `process.stderr.write` marker injected as the first statement of this delete printed NOTHING while the file's suite passed, so no path this suite drives calls it. The control that makes that silence evidence instead of a broken probe: the same injection in `run-summary.test.ts`'s PINNED delete DID print, in the same run of the same harness. Dormant is not harmless — it means the looseness is unexercised today, so a future test that starts deleting through this fake inherits a double that accepts what ObjectQL.delete refuses.", "closes": "open the fake's delete with assertEngineDeleteDispatch(opts) and run the package's suite" }, + { + "file": "packages/runtime/src/dispatcher-plugin.anonymous-gate.integration.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 65. 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. The package DOES depend on @objectstack/objectql, so this is a one-line pin whenever a batch takes it — deferred here because #5629's first batch is the criterion plus the ledger, and flipping ~three dozen unmeasured suites red belongs in the per-package batches that follow.", + "closes": "open the fake's delete with assertEngineDeleteDispatch(options) and run the package's suite" + }, + { + "file": "packages/runtime/src/http-dispatcher.keys.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 18. 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. The package DOES depend on @objectstack/objectql, so this is a one-line pin whenever a batch takes it — deferred here because #5629's first batch is the criterion plus the ledger, and flipping ~three dozen unmeasured suites red belongs in the per-package batches that follow.", + "closes": "open the fake's delete with assertEngineDeleteDispatch(options) and run the package's suite" + }, + { + "file": "packages/runtime/src/http-dispatcher.mcp-oauth.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 44. 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. The package DOES depend on @objectstack/objectql, so this is a one-line pin whenever a batch takes it — deferred here because #5629's first batch is the criterion plus the ledger, and flipping ~three dozen unmeasured suites red belongs in the per-package batches that follow.", + "closes": "open the fake's delete with assertEngineDeleteDispatch(options) and run the package's suite" + }, + { + "file": "packages/runtime/src/http-dispatcher.mcp.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 34. 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. The package DOES depend on @objectstack/objectql, so this is a one-line pin whenever a batch takes it — deferred here because #5629's first batch is the criterion plus the ledger, and flipping ~three dozen unmeasured suites red belongs in the per-package batches that follow.", + "closes": "open the fake's delete with assertEngineDeleteDispatch(options) and run the package's suite" + }, + { + "file": "packages/runtime/src/http-dispatcher.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 3693. 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. The package DOES depend on @objectstack/objectql, so this is a one-line pin whenever a batch takes it — deferred here because #5629's first batch is the criterion plus the ledger, and flipping ~three dozen unmeasured suites red belongs in the per-package batches that follow.", + "closes": "open the fake's delete with assertEngineDeleteDispatch(options) and run the package's suite" + }, { "file": "packages/services/service-automation/src/builtin/crud-config-aliases.test.ts", "unguarded": 1, @@ -213,6 +381,13 @@ "why": "MEASURED (#5393): the devDependency this entry used to cite as the blocker now EXISTS — @objectstack/objectql was added to @objectstack/service-automation's devDependencies when the sibling `builtin/crud-bulk-intent.test.ts` was pinned. It is not cyclic: objectql's transitive dependency closure (12 packages) does not contain service-automation, and `turbo run build --filter=@objectstack/service-automation --dry` (turbo 2.10.7) resolved the graph without complaint. So what is left here is a one-line pin, deferred only because #5393's PR is a spec/executor change and flipping an unmeasured suite red belongs in its own PR.", "closes": "open the fake's delete with assertEngineDeleteDispatch(opts) and run the package's suite — the devDependency is already declared" }, + { + "file": "packages/services/service-automation/src/run-summary.test.ts", + "unguarded": 5, + "kind": "DEBT", + "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 lines 188, 332, 360, 384, 793. This is #5629's origin specimen. #5197 pinned the ONE double in this file whose delete is actually driven (the sweep behind #5225's `showcase_inquiry_purge`, which answered `acted: 0` in production while this suite stayed green); these are the remaining zero-parameter siblings, which #5197 correctly left alone because nothing calls them. They are also the control for every dormancy claim in this batch: the pinned delete printed its marker, these five did not. 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. @objectstack/objectql is already in this package's devDependencies (added when an earlier double in the same package was pinned), so this is 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) and run the package's suite — the devDependency is already declared" + }, { "file": "packages/services/service-automation/src/runas-grant-resolution.integration.test.ts", "unguarded": 1, @@ -242,10 +417,73 @@ "closes": "add @objectstack/objectql to devDependencies, then open the fake's delete with assertEngineDeleteDispatch(opts)" }, { - "file": "packages/spec/src/contracts/data-engine.test.ts", + "file": "packages/services/service-messaging/src/email-channel.test.ts", "unguarded": 1, + "kind": "DEBT", + "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 33. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/service-messaging --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/services/service-messaging/src/inbox-channel.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 37. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/service-messaging --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/services/service-messaging/src/messaging-service-plugin.test.ts", + "unguarded": 2, + "kind": "DEBT", + "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 lines 23, 105. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/service-messaging --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/services/service-messaging/src/messaging-service.test.ts", + "unguarded": 6, + "kind": "DEBT", + "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 lines 37, 173, 226, 375, 410, 442. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/service-messaging --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/services/service-messaging/src/preference-resolver.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 18. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/service-messaging --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/services/service-messaging/src/recipient-resolver.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 24. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/service-messaging --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/services/service-messaging/src/sms-channel.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 33. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/service-messaging --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/services/service-messaging/src/sql-outbox-audit-columns.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 39. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/service-messaging --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/services/service-messaging/src/template-renderer.test.ts", + "unguarded": 1, + "kind": "DEBT", + "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 70. 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. The package does not depend on @objectstack/objectql yet, and — unlike the metadata-protocol family in this ledger — the devDependency route is AVAILABLE here rather than cyclic. Measured on this branch, not cited: the edge was added to this package's devDependencies and turbo 2.10.7 accepted the graph (`turbo run build --filter=@objectstack/service-messaging --dry`, no circular-dependency warning), then the edge was reverted.", + "closes": "add @objectstack/objectql to this package's devDependencies (verified acyclic on this branch — see `why`), then open the fake's delete with assertEngineDeleteDispatch(options)" + }, + { + "file": "packages/spec/src/contracts/data-engine.test.ts", + "unguarded": 5, "kind": "EXEMPT", - "why": "Not a stand-in that code under test drives — it is a TYPE-CONFORMANCE witness that IDataEngine is implementable, asserting only `typeof engine.delete === 'function'`. And it cannot be pinned even in principle: @objectstack/objectql depends on @objectstack/spec, so the import would invert the dependency. Ran clean under the guard anyway (spec: 295/295 files passed with the dispatch guard installed in every engine double).", + "why": "Not a stand-in that code under test drives — it is a TYPE-CONFORMANCE witness that IDataEngine is implementable, asserting only `typeof engine.delete === 'function'`. And it cannot be pinned even in principle: @objectstack/objectql depends on @objectstack/spec, so the import would invert the dependency. Ran clean under the guard anyway (spec: 295/295 files passed with the dispatch guard installed in every engine double). RE-MEASURED (#5629): this entry's count moves 1 -> 5 without a line of test code changing — 4 further doubles in this file (lines 46, 82, 119, 152) became visible when #5629 stopped discarding deletes that declare no parameters. Not a regression and not a raised ratchet: the doubles were always here, the scan could not reach them. The four newly visible doubles are the same kind as the one this entry already records: `const engine: IDataEngine = { … }` type-conformance witnesses inside the contract test for that interface. Each is built to exercise or declare something OTHER than delete — reads through `find`/`findOne`/`count`, the trailing options argument on every read, the optional `execute` and `vectorFind` members — and none of them calls `delete`, which is present only because the interface requires the member. EXEMPT for the reason already stated, which applies to each of them unchanged. Dormant looseness, probed rather than assumed: a `process.stderr.write` marker injected as the first statement of this delete printed NOTHING while the file's suite passed, so no path this suite drives calls it. The control that makes that silence evidence instead of a broken probe: the same injection in `run-summary.test.ts`'s PINNED delete DID print, in the same run of the same harness. Dormant is not harmless — it means the looseness is unexercised today, so a future test that starts deleting through this fake inherits a double that accepts what ObjectQL.delete refuses.", "closes": "nothing — permanent" } ]