Skip to content

Commit 3572916

Browse files
test(metadata-core,driver-mongodb): shipped case labels and mongod harness text state each case in words instead of a tracker number (stage 5b) (#21139)
Fixes #20513 Clause-②: no **Stage 5b, the last stage of this lane under the maintainer's A / A ruling on the card (5902360492): the `src/`-shipped test strings.** These are the 28 literals (32 occurrences in 6 files) that PR #20924's body inventoried as stage 5b and release 5922539397 restates: shared case labels, a suite title, two contract `why` texts and the mongod test-harness text. After this PR the `domain:engine` packages hold zero rows in `scripts/doc-authoring-prose-id.baseline.json`. Text only: no error `code`, export, HTTP status, case value or control flow moves. ## What this does Each label or harness line sent the reader to a tracker number for the reason behind it. In form D, as stages 1 to 5a applied it, the number goes. Where the sentence already stated the case, only the citation goes (17 literals). Where the sentence leaned on the number, it now says the case in words (11 literals): | Where | Cited | The text now says | |---|---|---| | `driver-mongodb` `test-mongod.ts` skip reason | 5517 | "retired from default test runs because concurrent downloads made green runs exit 1" | | `driver-mongodb` `test-mongod.ts` abandoned-download warning | 5517 | "Ignoring the MongoDB binary download abandoned by a concurrent-download race" | | `ENGINE_DELETE_DISPATCH_CASES`: where.id plus a CAS operator, `multi: false` | 11009 | "refused, the by-id path would drop the CAS guard" | | `ENGINE_FINDONE_PREDICATE_CASES`: an empty `where` object | 3896 | "read as match-every-row, so NOT a predicate" | | `ENGINE_UPDATE_DISPATCH_CASES`: payload id beside a DIFFERENT scalar where.id | 11142, 5748 | "refused; the payload id no longer silently wins over a where.id naming another row" | | same table: payload id beside an `$in` where.id, no multi | 11230 | "refused; the by-id write would silently drop the declared row SET" | | same table: payload id beside a NULL where.id | 11230 | "refused; a declared where.id that is not one primary key is never silently dropped" | | same table: payload id beside a FALSY scalar where.id | 11142, 11230 | "(it is a scalar, so neither the different-row nor the non-scalar refusal applies)" | | same table: where.id plus a CAS operator, `multi: false` | 11009 | "the redeliver shape, refused rather than dropping its CAS guard" | | same table: payload id plus an extra where predicate, no multi | 11009 | "refused; the by-id write would silently drop the predicate, through the payload door" | | `OBJECT_SCHEMA_MASK_CASES` `write-capable-caller/exempt` `why` | 7020, 6603 | "D4 is DERIVED from the schema write gate (`manage_metadata`)" | Citation only: the contract suite's `serialized-form identity` group title; 3 delete, 2 findOne and 9 update labels; the empty-readable-set `why`; the mongod acquisition-timeout message. Each new clause was read against today's code: `resolveEngineUpdateDispatch` (the different-row refusal fires only on a truthy scalar where.id, the non-scalar refusal only on a declared non-scalar), `ObjectQL.requireFindOnePredicate` (absent, null and an empty object are read as match-every-row), and `OBJECT_SCHEMA_WRITE_CAPABILITIES` (`manage_metadata`, the key the D4 exemption is derived from). The `test-mongod.ts` docblock "Names the issue and the switch" now says "Names the reason and the switch", so it stays true. No other comment or docblock moves; code comments still cite ids, as in every earlier stage. **Re-pins (H4).** The two `#5517` number pins in `mongodb-memory-server-gate.test.ts` now assert the text that replaced the number: the skip line contains "retired from default test runs because concurrent downloads made green runs exit 1", and the guard's warning contains "download abandoned by a concurrent-download race". Neither pin was deleted. Both were proven able to fail (below). ## Ledger (`scripts/doc-authoring-prose-id.baseline.json`) Recomputed with `node scripts/check-doc-authoring.mjs --census-ledger` (exit 0: no growth refusal) and copied into place. The diff is 25 deleted lines, nothing added. | File | Before | After | |---|---|---| | `drivers/driver-mongodb/src/test-mongod.ts` | 3 | 0 | | `metadata-core/src/contract-suite.ts` | 1 | 0 | | `metadata-core/src/engine-delete-dispatch.ts` | 4 | 0 | | `metadata-core/src/engine-findone-predicate.ts` | 3 | 0 | | `metadata-core/src/engine-update-dispatch.ts` | 18 | 0 | | `metadata-core/src/object-schema-fls-contract.ts` | 3 | 0 | | **This stage** | **32 in 6 files** | **0** | Whole ledger: files 175 → 169, pairs 441 → 428, occurrences 653 → 621. Gate pinned sites 549 → 521. No other file's row moves. After each of the four merges of `origin/main` (below) the recomputed ledger was byte-identical to the committed one. ## Hypotheses, measured - **H1, held.** At `origin/main` `9c8b65aa2` the six files held exactly the inventory: `#5517` ×3; `#7856` ×1; `#11009` ×4 (delete); `#11767`, `#3896`, `#4346` (findOne); `#11009` ×6, `#11142` ×4, `#11230` ×4, `#5748` ×4 (update); `#3545`, `#6603`, `#7020` (FLS). The gate's census listed 28 literals carrying 32 occurrences. - **H2, held.** The recomputed ledger has 0 rows under `packages/objectql`, `core`, `formula`, `metadata*`, `platform-objects`, `drivers/driver-*` and `plugins/plugin-pinyin-search` (the `domain:engine` path set). The lane's ledger is empty. The whole ledger is not, so the gate's stale-baseline arm keeps its blindness floor. - **H3, nothing keys on the old labels.** Each of the 28 old literals was searched byte for byte across the repo (`dist` excluded). Each was found only in this stage's own source files (two delete labels have update twins), with two exceptions. The tail `download — #5517)` also sits in a comment in `mongodb-pipeline-evaluator.testkit.ts`. `serialized-form identity (#7856)` also titles an independent `describe` in `metadata-core/test/canonicalize.test.ts`, a test file outside the ledger. Both are left alone. No CI workflow, `package.json` script, vitest config, snapshot or skip list carries the labels or a `-t` filter on them. The cited numbers appear elsewhere only in workflow comments, an ADR anchor's invariant prose and a merge-parent sha. The labels reach other code only as test names: objectql's `engine-*-dispatch` / `engine-findone-predicate` parity loops, `service-queue`'s `it.each`, and `assertObjectSchemaMaskCase`'s failure text. Each label stays unique within its table (35 / 19 / 18). - **H4, held.** See Re-pins. ## Changeset `.changeset/20513-metadata-core-case-labels-state-the-case.md`: `patch` for `@objectstack/metadata-core`. Its case tables ship in `dist/index.*`, and the contract suite and FLS table ship in `dist/testing.js` (measured after build: the new labels found in those files). There is **no `@objectstack/driver-mongodb` entry**, because `test-mongod.ts` is not published. The package builds `src/index.ts` only, and only test files import `test-mongod.ts`. Measured after build: `mongodSkipReason`, "retired from default test runs", "concurrent-download race" and "waiting for the MongoDB binary" are each in 0 files under `packages/drivers/driver-mongodb/dist`. The positive control `MongoDBDriver` is in 4. ## Text-only proof A TypeScript-AST skeleton of each changed `.ts` file compares merge base `670680e93` with head `24b72b809`. In the skeleton, every string literal and template text is one placeholder, pure-literal `+` operands collapse, and comments are never read. Result: 7 of 7 SAME, with token and literal-slot counts identical per file. Control: the same tool reports DIFF on `rest` `import-template.ts` across `6f1f1c103`, a real code change. ## Tests (head `24b72b809` unless noted) - Build: `turbo run build` over `./packages/*` and `./packages/*/*` under the verify lock, 71/71, after the last merge. - `@objectstack/metadata-core`: 16 files / 298 tests passed; `typecheck` exit 0. - `@objectstack/driver-mongodb`: 30 files passed and 5 skipped, 675 tests passed and 172 skipped (the skips need a MongoDB server); `typecheck` exit 0, including `check:test-typecheck`. - Consumers of the case tables, against the rebuilt `metadata-core` `dist`: - `objectql`, 7 files / 181 tests: `engine-delete-dispatch`, `engine-update-dispatch`, `engine-findone-predicate`, `engine-update-by-id-payload-id`, `engine-update-multi-payload-id`, `engine-write-not-found-gate` and `validation/operator-object-write-value`; - `service-queue` `db-queue-adapter`, 38; - `rest` `meta-object-fls`, 95; - `runtime` `domains/meta-object-fls`, 85; - `metadata-fs` `contract`, 31; - `metadata-protocol` `sys-metadata-repository.contract` and `protocol.update-path-id-wins`, 64. - A verbose run before the merges showed the parity loops naming the new labels. objectql's tests resolve `metadata-core` through `dist`, so this shows they read the rebuilt build. - Re-pin mutations, one-off, on the committed head (`2729901db`), through `scripts/ablation-replace.mjs` in WRAP mode (restore armed on EXIT/INT/TERM): - Skip-reason anchor ×1 → ×0: `mongodb-memory-server-gate.test.ts` 1 failed / 7 passed. - Warning anchor ×1 → ×0: 1 failed / 7 passed. - Each restore: blob equals HEAD's (`22a95643c8`), and `git diff HEAD` is empty. After both, `git diff HEAD` was 0 bytes and `git status --porcelain` 0 lines. ## Gates `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no paths) at `24b72b809` derived 69 commands. All 69 ran one at a time from the worktree, each exit 0. `--ran` reports "69 derived, 69 run, 0 NOT-MEASURED, 0 UNRUN". Among them: - `check:doc-authoring`: 521 pinned sites across 169 files, no growth, no burn-down unrecorded; - `check:driver-conformance`: 50 covered cells, 0 DEBT, 0 exempt, the same reading as before the change; - `check:engine-double-contract`, `check:dual-build-cjs-loads` (105 require entry points across 66 packages load, read from the post-merge build), `check:nul-bytes`, `check:type-check-coverage` and `check:type-check-debt`. After the first merge (`packages/spec` moved on main): `pnpm --filter @objectstack/spec check:generated` reported all 15 artifacts up to date. Narrowed lint: `eslint --no-inline-config --format json` over the 7 changed `.ts` files reported 7 files, 0 errors and 0 warnings, none ignored (counts from eslint's JSON). The resolved `parserOptions` are `ecmaVersion: latest, sourceType: module`, with no `project` or `projectService`. So no type-aware rule runs, and this diff cannot move an untouched file's verdict. Repo-wide `pnpm lint` is CI's. NOT MEASURED locally (CI's): the live MongoDB cells of `driver-mongodb`, the Test Core shards, Dogfood, and the workspace type-check lanes. ## Acceptance notes - `origin/main` was merged four times while this was open (`1d55ee66e`, `4f1c99822`, `4516a0643`, `24b72b809`; the third brings in #21097). None of the incoming commits touches a file this PR changes. They touch `objectql`, `rest`, `runtime` and `metadata-protocol`, so those consumer suites were re-run at the final head. `main` moved again after the gate union; the queue rebuilds on it. - PR #21105, in `driver-mongodb`'s filter and temporal suites, landed before the first merge and shares no file with this PR. - `metadata-core/test/canonicalize.test.ts` titles its own `describe` `serialized-form identity (#7856)`, and `mongodb-memory-server-gate.test.ts` titles two `describe` blocks `[#5517] …`. Both are `*.test.ts` files, which the ruling's third category (`src/`-shipped test strings) and the ledger do not cover. They are left as they are: noted, not filed. - The lane children #20749, #20751 and #20753 carry `Blocked-by:` lines naming this card. They unlock when it leaves the open state on merge. --- _Generated by [Claude Code](https://claude.ai/code/session_01Ujdtvqs7ree7WyQmEDwEnG)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent db48028 commit 3572916

9 files changed

Lines changed: 58 additions & 57 deletions
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
'@objectstack/metadata-core': patch
3+
---
4+
5+
The shared engine case tables and the published contract suites in metadata-core no longer cite tracker numbers in their case labels; each label states its case in words
6+
7+
Clause-②: no
8+
9+
Several labels these tables and suites ship ended with an issue-tracker number where the case belonged. A
10+
test driven from them printed that number as part of its name, and a failing assertion quoted it as the
11+
reason. The number goes; where the label did not already say what the case is, it now does.
12+
13+
- `ENGINE_DELETE_DISPATCH_CASES`, `ENGINE_UPDATE_DISPATCH_CASES` and `ENGINE_FINDONE_PREDICATE_CASES`:
14+
the `what` labels of 22 rows. Among them, the compare-and-set rows now say the by-id path would drop the
15+
CAS guard; the payload-id rows say which declared `where.id` would be silently dropped; and the falsy
16+
`where.id` boundary says it is a scalar, so neither the different-row refusal nor the non-scalar refusal
17+
applies.
18+
- `@objectstack/metadata-core/testing`: the repository contract suite's `serialized-form identity` group
19+
title, and two `why` texts of `OBJECT_SCHEMA_MASK_CASES` (the empty-readable-set refusal, and the
20+
write-capable exemption, which now names the schema write gate, `manage_metadata`).
21+
22+
Text only: no case is added, removed or re-ordered, and no `options`, `data`, `expect`, `expectId`, `id`,
23+
`readable` or `context` value moves. A suite that selects or skips these cases by their label text (a
24+
`-t` filter, a skip list) needs the new spelling.

‎packages/drivers/driver-mongodb/src/mongodb-memory-server-gate.test.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ describe('[#5517] the mongod opt-in gate', () => {
9797

9898
expect(mongod).toBeUndefined();
9999
expect(warnings).toHaveLength(1);
100-
expect(warnings[0]).toContain('#5517');
100+
expect(warnings[0]).toContain(
101+
'retired from default test runs because concurrent downloads made green runs exit 1',
102+
);
101103
expect(warnings[0]).toContain(MONGOD_TESTS_ENV);
102104
expect(warnings[0]).toContain('SKIP gate probe');
103105
// The property that makes the skip cost nothing: the module that would
@@ -202,7 +204,7 @@ describe('[#5517] the abandoned-download rejection guard', () => {
202204
listeners[0](renameEnoent());
203205
expect(reraised).toEqual([]);
204206
expect(warned).toHaveLength(1);
205-
expect(warned[0]).toContain('#5517');
207+
expect(warned[0]).toContain('download abandoned by a concurrent-download race');
206208

207209
const real = new Error('a genuine unhandled rejection');
208210
listeners[0](real);

‎packages/drivers/driver-mongodb/src/test-mongod.ts‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,16 +152,16 @@ export function printMongodNotice(
152152
write(`${message}\n`);
153153
}
154154

155-
/** The one line a gated-off suite prints. Names the issue and the switch. */
155+
/** The one line a gated-off suite prints. Names the reason and the switch. */
156156
export function mongodSkipReason(suite: string, env: NodeJS.ProcessEnv = process.env): string {
157157
const raw = env[MONGOD_TESTS_ENV];
158158
const misset = raw === undefined || raw === ''
159159
? ''
160160
: ` (${MONGOD_TESTS_ENV} is set to "${raw}", which does NOT enable it — only "1" does)`;
161161
return (
162162
`[driver-mongodb] SKIP ${suite} — needs a real mongod, and mongodb-memory-server would `
163-
+ 'download a ~123 MB binary; retired from default test runs by #5517 (concurrent downloads '
164-
+ `made green runs exit 1). Set ${MONGOD_TESTS_ENV}=1 to run it${misset}.`
163+
+ 'download a ~123 MB binary; retired from default test runs because concurrent downloads '
164+
+ `made green runs exit 1. Set ${MONGOD_TESTS_ENV}=1 to run it${misset}.`
165165
);
166166
}
167167

@@ -246,7 +246,7 @@ export function installAbandonedDownloadGuard(options: RejectionGuardOptions = {
246246
return;
247247
}
248248
warn(
249-
'[driver-mongodb] Ignoring the abandoned MongoDB binary download of #5517 '
249+
'[driver-mongodb] Ignoring the MongoDB binary download abandoned by a concurrent-download race '
250250
+ `(${(reason as Error).message}). Another worker won the race and renamed the archive; `
251251
+ 'the suite that lost it has already degraded to a named skip, and this rejection must '
252252
+ 'not fail an otherwise green run.',
@@ -299,7 +299,7 @@ export async function createTestMongod(suite: string): Promise<MongoMemoryServer
299299
() => reject(new Error(
300300
`timed out after ${ACQUIRE_TIMEOUT_MS / 1000}s waiting for the MongoDB binary `
301301
+ '(fastdl.mongodb.org unreachable or hanging, or another worker holds the '
302-
+ 'download — #5517)',
302+
+ 'download)',
303303
)),
304304
ACQUIRE_TIMEOUT_MS,
305305
);

‎packages/metadata-core/src/contract-suite.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ export function runRepositoryContractTests(
254254
// Asserting only one face would have left the other implementation's
255255
// divergence unpinned, which is the whole reason this lives in the
256256
// shared contract suite rather than beside either bug.
257-
describe('serialized-form identity (#7856)', () => {
257+
describe('serialized-form identity', () => {
258258
for (const shape of SERIALISATION_SHAPES) {
259259
it(`version identifies the stored bytes — ${shape.label}`, async () => {
260260
const repo = await factory();

‎packages/metadata-core/src/engine-delete-dispatch.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,14 @@ export const ENGINE_DELETE_DISPATCH_CASES: readonly EngineDeleteDispatchCase[] =
271271
// there is no predicate the by-id path could drop, and LifecycleService's
272272
// guarded reap relies on this shape for per-record cascade handling
273273
// (`engine-data-events.test.ts` pins the event contract of the same shape).
274-
{ what: 'scalar where.id with multi:true and NOTHING else in where — still one by-id delete (#11009)', options: { where: { id: 'rec_1' }, multi: true }, expect: 'by-id' },
274+
{ what: 'scalar where.id with multi:true and NOTHING else in where — still one by-id delete', options: { where: { id: 'rec_1' }, multi: true }, expect: 'by-id' },
275275
{ what: 'multi with a predicate', options: { where: { rule_id: 'r1' }, multi: true }, expect: 'multi' },
276276
{ what: 'multi with no predicate at all', options: { multi: true }, expect: 'multi' },
277277
{ what: 'multi alongside an $in id set', options: { where: { id: { $in: ['a', 'b'] } }, multi: true }, expect: 'multi' },
278278
// [#11009] The compare-and-set spelling: a scalar `where.id` beside real
279279
// predicate keys WITH a declared `multi` is a predicate call — every key
280280
// rides the AST to `driver.deleteMany`, so the condition is honoured.
281-
{ what: 'scalar where.id + extra predicate keys + multi:true — the predicate path honours ALL of it (#11009)', options: { where: { id: 'rec_1', status: 'stale' }, multi: true }, expect: 'multi' },
281+
{ what: 'scalar where.id + extra predicate keys + multi:true — the predicate path honours ALL of it', options: { where: { id: 'rec_1', status: 'stale' }, multi: true }, expect: 'multi' },
282282
// ── The FALSY scalars (objectstack#5747). `0` and `''` are scalars, so
283283
// `scalarDeleteId` returns them — but the engine's `if (input.id)` is a
284284
// truthiness test, so neither identifies a row. With a declared bulk
@@ -317,6 +317,6 @@ export const ENGINE_DELETE_DISPATCH_CASES: readonly EngineDeleteDispatchCase[] =
317317
// update-side cases. Each used to dispatch `by-id` and silently DISCARD
318318
// every `where` key other than `id`; now the refusal names the dropped
319319
// keys and prescribes the predicate path (`multi: true`).
320-
{ what: 'scalar where.id alongside other predicates, NO multi — the guard would be silently dropped (#11009)', options: { where: { id: 'rec_1', tenant: 't1' } }, expect: 'reject' },
321-
{ what: 'scalar where.id + a CAS operator predicate, multi explicitly false (#11009)', options: { where: { id: 'rec_1', status: { $in: ['done'] } }, multi: false }, expect: 'reject' },
320+
{ what: 'scalar where.id alongside other predicates, NO multi — the guard would be silently dropped', options: { where: { id: 'rec_1', tenant: 't1' } }, expect: 'reject' },
321+
{ what: 'scalar where.id + a CAS operator predicate, multi explicitly false — refused, the by-id path would drop the CAS guard', options: { where: { id: 'rec_1', status: { $in: ['done'] } }, multi: false }, expect: 'reject' },
322322
];

‎packages/metadata-core/src/engine-findone-predicate.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ export const ENGINE_FINDONE_PREDICATE_CASES: readonly EngineFindOnePredicateCase
263263
{ what: 'an operator predicate', query: { where: { id: { $in: ['a', 'b'] } } }, expect: 'selective' },
264264
// The alias the engine folds on every entry point (#4346). Before the fold,
265265
// `findOne({ filter })` matched the first row of the WHOLE table.
266-
{ what: "the 'filter' alias alone — folded into 'where' before the guard (#4346)", query: { filter: { status: 'open' } }, expect: 'selective' },
266+
{ what: "the 'filter' alias alone — folded into 'where' before the guard", query: { filter: { status: 'open' } }, expect: 'selective' },
267267
{ what: "an explicit null 'where' beside a real 'filter' — null is a withdrawal, not a value", query: { where: null, filter: { status: 'open' } }, expect: 'selective' },
268268
// A FilterArray that is a well-formed AST lowers to a condition.
269269
{ what: 'a non-empty FilterArray — lowered to a condition before the guard', query: { where: ['status', '=', 'open'] }, expect: 'selective' },
@@ -274,12 +274,12 @@ export const ENGINE_FINDONE_PREDICATE_CASES: readonly EngineFindOnePredicateCase
274274
// a running server throws on — which is the whole of #11957.
275275
{ what: 'no query at all', query: undefined, expect: 'reject' },
276276
{ what: 'an empty query bag', query: {}, expect: 'reject' },
277-
{ what: "an empty 'where' object — the match-every-row shape (#3896's reading)", query: { where: {} }, expect: 'reject' },
277+
{ what: "an empty 'where' object — read as match-every-row, so NOT a predicate", query: { where: {} }, expect: 'reject' },
278278
{ what: "an explicitly null 'where'", query: { where: null }, expect: 'reject' },
279279
// THE #11767 SHAPE. An empty FilterArray is truthy, so every hand-written
280280
// `if (!query?.where)` copy accepts it; the engine's lowering deletes the key
281281
// and the guard refuses. This one row is what the card was filed for.
282-
{ what: "an empty FilterArray 'where: []' — truthy, and NOT a predicate (#11767)", query: { where: [] }, expect: 'reject' },
282+
{ what: "an empty FilterArray 'where: []' — truthy, and NOT a predicate", query: { where: [] }, expect: 'reject' },
283283
{ what: "a null 'filter' alias — a withdrawal, so nothing folds", query: { filter: null }, expect: 'reject' },
284284
{ what: 'an empty orderBy array', query: { orderBy: [] }, expect: 'reject' },
285285
{ what: 'a projection and a limit but nothing selective', query: { fields: ['id', 'name'], limit: 1 }, expect: 'reject' },

0 commit comments

Comments
 (0)