Skip to content

Commit a06faeb

Browse files
claude[bot]claude
andauthored
fix(driver-mongodb): put the test layer in front of tsc, so the package typecheck reports a pass and not a number (#15465)
* wip: driver-mongodb test-layer typecheck via the #5286 sibling route Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ * fix(driver-mongodb): put the test layer in front of tsc via the #5286 sibling route (#14917) The package's tsconfig.json excluded **/*.test.ts and its typecheck script is tsc --noEmit against that config, so 0 of its 30 test files were in the program while all 10 non-test src files were. The only program reading that layer was the TEST_DEBT ratchet -- an instrument that reports a number and fails when the number moves, not a gate that reports a pass. Adds tsconfig.test.json (module semantics only: esnext / bundler / lib ES2022, matching vitest; strictness inherited and untouched) named by the typecheck script via check:test-typecheck. Measured 10 errors under the ratchet's shape (matching its recorded number and composition class for class) and 0 under the split -- all 10 config-tier, none a defect in a test. The TEST_DEBT entry graduates (deleted, not lowered). No test-typecheck-debt.json is owed: residue is 0, so all 30 files are unledgered and red on arrival. check:type-source-resolution takes the documented #11490 onboarding re-baseline with its numbers stated in place. No test file and no source file is edited. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8a12067 commit a06faeb

6 files changed

Lines changed: 277 additions & 18 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
"@objectstack/driver-mongodb": patch
3+
---
4+
5+
fix(driver-mongodb): put the test layer in front of tsc, so the package's own typecheck reports a PASS and not a NUMBER (#14917)
6+
7+
`packages/drivers/driver-mongodb`'s `tsconfig.json` excluded `**/*.test.ts`, and
8+
its `typecheck` script is `tsc --noEmit` against that very config. Measured at
9+
`6ed4b811af` with the dependency closure built: that program admits **0** of the
10+
package's 30 `src/**/*.test.ts` files while all **10** of its non-test `src/**`
11+
files ARE there, so `pnpm --filter @objectstack/driver-mongodb typecheck`
12+
exiting 0 was a true sentence carrying no information about any test file.
13+
14+
The filing's headline — that a compile-time `Equals` / `IsAny` pin here is
15+
"checked by nothing" — is **false**, and the correction on the card is right: a
16+
second program does compile these files. `check-type-check-coverage.mjs`'s
17+
`remeasureProject` drops only the test glob and compares the result against its
18+
`TEST_DEBT` ledger. Confirmed here by ablation rather than argued: a
19+
deliberately false `Equals` pin added to `mongodb-driver.test.ts` takes that
20+
program from 10 errors to 11, above the ledger's recorded 10, which reddens it.
21+
The pins were never phantoms. What was true is narrower, and is what this change
22+
closes: the only program reading this layer was a **debt ratchet** — an
23+
instrument that reports a number and fails when the number moves, not a gate
24+
that reports a pass.
25+
26+
Gives the package the #5286 sibling shape (`packages/rest`, `runtime`,
27+
`objectql`, `core`): a `tsconfig.test.json` with module semantics only —
28+
`esnext` / `bundler` / `lib: ES2022`, matching how vitest actually executes
29+
these files — strictness inherited and untouched, named by the `typecheck`
30+
script via `check:test-typecheck`.
31+
32+
Measured: **10** errors under the ratchet's shape (matching its recorded number,
33+
and its recorded composition `TS1309 x7, TS2550 x3`, class for class), and **0**
34+
under the split. All 10 were config-tier in full — 7 `TS1309` (`await` at module
35+
scope in a program NodeNext compiles as CJS, because this package has no `"type":
36+
"module"`) and 3 `TS2550` (`Array.prototype.at` against a `lib` older than
37+
es2022). Neither class says anything about a test, and nothing was exposed
38+
behind them: there was no unresolved-import cascade here to collapse, so there
39+
is no `+n` term. `noUnusedLocals` / `noUnusedParameters` are live for this
40+
package (unlike `driver-turso`, which switches both off) and neither fires.
41+
42+
The `TEST_DEBT` entry (10 errors) is **deleted**, not lowered — the graduation
43+
this ratchet's invariant requires. No `test-typecheck-debt.json` is added:
44+
residue is 0, so none is owed (#5286, maintainer-only to open). That leaves all
45+
30 files unledgered, so any error any one of them gains is red on arrival.
46+
47+
`check:type-source-resolution` went red from onboarding the new program (the
48+
documented onboarding-limb case, #11490): a registry entry is added rather than
49+
`paths`, with its numbers stated in place — 123 tsc programs / 309 pairs before,
50+
124 / 310 after. The single new pair is `@objectstack/objectql`, a devDependency
51+
that no non-test file in `src/` imports.
52+
53+
No runtime code changes: not one test file and not one source file is edited, so
54+
no shipped behaviour moves — the suite reports the same 552 passed / 147 skipped
55+
across 30 files as before. The `patch` level reflects the published
56+
`package.json` gaining `typecheck` / `check:test-typecheck` scripts and a `tsx`
57+
devDependency.

packages/drivers/driver-mongodb/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs",
1717
"dev": "tsc -w",
1818
"test": "vitest run",
19-
"typecheck": "tsc --noEmit"
19+
"typecheck": "tsc --noEmit && pnpm check:test-typecheck",
20+
"check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/drivers/driver-mongodb --project tsconfig.test.json"
2021
},
2122
"dependencies": {
2223
"@objectstack/core": "workspace:*",
@@ -29,6 +30,7 @@
2930
"@objectstack/objectql": "workspace:*",
3031
"@types/node": "^26.2.0",
3132
"mongodb-memory-server": "^11.2.0",
33+
"tsx": "^4.23.12",
3234
"typescript": "^6.0.3",
3335
"vitest": "^4.1.10"
3436
},
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// The TEST-layer type-check program (#14917), adopting the mechanism #5286 set
2+
// for `packages/spec` and #5449 generalised — the route `packages/objectql`
3+
// (#13676), `packages/runtime` (#14504) and `packages/core` (#14613) already
4+
// run. `tsconfig.json` beside this file stays exactly as it is: it is the BUILD
5+
// config, and its `**/*.test.ts` exclusion has a reason. This sibling puts the
6+
// excluded layer back in front of tsc, and `package.json`'s `typecheck` script
7+
// NAMES it (via `check:test-typecheck --project`), because a config no script
8+
// invokes is exactly the phantom this whole mechanism is about.
9+
//
10+
// BEFORE THIS FILE, NO tsc PROGRAM COMPILED A SINGLE TEST FILE HERE, and that
11+
// is measured rather than read off the config. At 6ed4b811af with the
12+
// dependency closure built first, `tsc --noEmit --listFiles -p tsconfig.json`
13+
// puts **0** of this package's 30 `src/**/*.test.ts` files in the program —
14+
// while all **10** of its non-test `src/**` files ARE there, so the zero is the
15+
// `exclude` line and not a probe that sees nothing. Under this file the count is
16+
// **30 of 30**, with the same 10 non-test files beside them.
17+
// `pnpm --filter @objectstack/driver-mongodb typecheck` exiting 0 was a true
18+
// sentence carrying no information about any test file in this package.
19+
//
20+
// ⚠️ WHAT THE CARD SAID, AND WHAT WAS ACTUALLY WRONG. The filing's headline —
21+
// that a compile-time `Equals` / `IsAny` pin here is "checked by nothing" — is
22+
// FALSE, and the correction on the card is right: a second program does compile
23+
// these files. `scripts/check-type-check-coverage.mjs`'s `remeasureProject`
24+
// extends this package's tsconfig, drops only the test glob, and compares the
25+
// result against its `TEST_DEBT` ledger. That is how CI caught PR #14914's
26+
// three TS18047 errors, which this package's own `typecheck` could not see. So
27+
// the pins were not phantoms. What was true is narrower and is what this file
28+
// closes: the only program reading this layer was a DEBT RATCHET — an
29+
// instrument that reports a NUMBER and fails when the number MOVES, not a gate
30+
// that reports a pass.
31+
//
32+
// What differs from the build config, and what deliberately does NOT:
33+
// - module semantics ONLY, plus `lib`. The tests are written and executed as
34+
// ESM by vitest (esbuild/vite), while this package has no `"type":
35+
// "module"`, so the build config's NodeNext compiles them as CJS. Measured
36+
// cost of that mismatch here: ALL 10 of the raw diagnostics — TS1309 x7
37+
// ("cannot use `await` at the top level" in a CJS program, one per suite
38+
// that awaits `startMongod()` at module scope) and TS2550 x3 (all three the
39+
// same `Array.prototype.at` message in `mongodb-findone-options.test.ts`,
40+
// against a `lib` older than es2022). Those 10 are about the CHECK, never
41+
// about the code. Matching vitest is fidelity, not laxity. No `DOM` in
42+
// `lib`: nothing in this layer touches a browser global.
43+
// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`,
44+
// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`
45+
// are inherited from the root config, and `types: ["node"]` restates
46+
// `tsconfig.json`'s — load-bearing for the same reason its comment gives,
47+
// since the `.test.ts` files call the `setTimeout` / `console` users in
48+
// `src/test-mongod.ts` and use those globals themselves. Nothing here may
49+
// loosen a type rule; if a test does not compile, that is the finding.
50+
// ⛔ Not one `any` and not one `@ts-expect-error` was added to any test file
51+
// to open this gate — that shape is what turns a real gate into a phantom.
52+
// - ⚠️ `noUnusedLocals` / `noUnusedParameters` are worth naming explicitly:
53+
// they are `true` at the root and `false` in `driver-turso`'s own overrides
54+
// but NOT in this package's, so this layer meets STRICTER settings than the
55+
// sibling driver whose clean state might otherwise be read as a prediction.
56+
// Measured: neither fires here, in either direction. Zero of the 10.
57+
// - `rootDir` is INHERITED as `./src` and deliberately not widened. Like
58+
// `packages/runtime` and unlike `objectql` / `spec`, this layer produces no
59+
// TS6059: measured, every file this program admits is already under `src`
60+
// (all 30 test files sit beside the sources they exercise). Widening it "to
61+
// be safe" would admit files the build config does not and change what the
62+
// gate judges, so it stays as the build config has it.
63+
//
64+
// ⭐ MEASURED at 6ed4b811af, dependency closure built first (an error count
65+
// taken against an unbuilt closure is not a reading — unresolved-import
66+
// cascades inflate it): this program reports **0 errors across 30 files**, from
67+
// a raw 10 under the inherited NodeNext semantics. Every one of the 10 was
68+
// config-tier and none survives; the residue is EMPTY. So unlike `objectql`,
69+
// `runtime`, `spec` and `core`, this package needs **no**
70+
// `test-typecheck-debt.json` at all, and carries none — which is the strongest
71+
// form of this gate: all 30 files are unledgered, so any error any one of them
72+
// ever gains is red on arrival, starting today.
73+
//
74+
// That empty residue is also why the `TEST_DEBT` entry in
75+
// `scripts/check-type-check-coverage.mjs` GRADUATES in the same change rather
76+
// than being paid down. Its recorded 10 and its recorded composition
77+
// ("TS1309 x7, TS2550 x3") match this file's raw reading exactly, which is the
78+
// cleanest possible confirmation that the ledger was measuring the CHECK's
79+
// misconfiguration and never a defect in the tests.
80+
{
81+
"extends": "./tsconfig.json",
82+
"compilerOptions": {
83+
"noEmit": true,
84+
"module": "esnext",
85+
"moduleResolution": "bundler",
86+
"lib": ["ES2022"],
87+
"types": ["node"]
88+
},
89+
"include": ["src/**/*"],
90+
"exclude": ["node_modules", "dist"]
91+
}

pnpm-lock.yaml

Lines changed: 59 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/check-type-check-coverage.mjs

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,48 @@ const TEST_DEBT = {
10261026
// Measured: with `rootDir` inherited, the same program reports 116 additional
10271027
// TS6059 — a config-tier pile that says nothing about any test.
10281028

1029+
// ── #14917: `@objectstack/driver-mongodb` GRADUATED — and this one really is
1030+
// at ZERO, which the six above are not ────────────────────────────────────────
1031+
//
1032+
// `driver-mongodb` (10) left this ledger on 2026-09-04, by the same route as
1033+
// `runtime`, `cli`, `lint` and the three plugins: it now has a
1034+
// `tsconfig.test.json` its `typecheck` script NAMES, so `hidesTests` is false
1035+
// for it and this gate's per-PACKAGE approximation has nothing left to
1036+
// approximate. ⛔ This change repairs no test file and edits none.
1037+
//
1038+
// ⭐ WHAT IS DIFFERENT HERE, and it is the whole reading: those six graduated
1039+
// into a per-file `test-typecheck-debt.json` holding a residue. This one
1040+
// graduates into NO LEDGER AT ALL. Measured at 6ed4b811af with the dependency
1041+
// closure built, `tsc --noEmit -p tsconfig.test.json` reports **0 errors across
1042+
// all 30 test files**. The recorded 10 was config-tier IN FULL — the same
1043+
// dissolution measured for `lint`'s 16, but complete rather than partial.
1044+
//
1045+
// The attribution has no remainder in either direction. RECORDED here was
1046+
// `TS1309 x7, TS2550 x3`; re-measured on the way out at 6ed4b811af by dropping
1047+
// only the test glob (this gate's own `remeasureProject` shape), the raw
1048+
// program reports those same 10, class for class and file for file. All 7
1049+
// TS1309 are "cannot use `await` at the top level" — this package has no
1050+
// `"type": "module"`, so NodeNext compiles as CJS the suites that await
1051+
// `startMongod()` at module scope, which vitest executes as ESM. All 3 TS2550
1052+
// are the same `Array.prototype.at` message in `mongodb-findone-options.test.ts`
1053+
// against a `lib` older than es2022. Both classes are the CHECK being
1054+
// misconfigured; neither is a defect in a test. Under vitest-matching module
1055+
// semantics both dissolve and NOTHING is exposed behind them — there is no
1056+
// `+n` term here, because there was no unresolved-import cascade to collapse.
1057+
//
1058+
// ⚠️ So the shrink-only guarantee did not merely move to a finer instrument
1059+
// here, it STRENGTHENED twice over. All 30 files are unledgered, so any error
1060+
// any one of them gains is red on arrival. And what the package's own
1061+
// `typecheck` script reports about its test layer is now a PASS rather than a
1062+
// NUMBER — which was this card's actual finding, once its false headline (that
1063+
// the `Equals` / `IsAny` pins here were phantoms) had been corrected on the
1064+
// thread. The pins were always real; they were read by THIS ratchet, and a
1065+
// ratchet fails when a number moves, not when a type is wrong.
1066+
//
1067+
// ⚠️ PINS_CHECKED reported nothing for this package in either direction and
1068+
// still does not: measured on the way out, its test layer holds ZERO
1069+
// `@ts-expect-error` directives, so that half had no subject here either.
1070+
10291071
'@objectstack/mcp': {
10301072
errors: 53,
10311073
note: 'TS18046 x51 -- `json` is of type unknown, one `await res.json()` idiom repeated across four '
@@ -1056,21 +1098,6 @@ const TEST_DEBT = {
10561098
+ 're-confirmed at 53 at 62b2655d8, so the next new error in this package goes red on arrival -- '
10571099
+ 're-establishing a margin deliberately remains a maintainer call (#5278 option A).',
10581100
},
1059-
'@objectstack/driver-mongodb': {
1060-
errors: 10,
1061-
note: 'TS1309 x7, TS2550 x3. Was 43 (TS2345 x33 + these 10), measured at 5ab08428 and still exactly '
1062-
+ '43 at d367f03d6^ -- the commit immediately before PR #6210. That PR (#6075) narrowed this '
1063-
+ "driver's six IDataDriver query methods to `DriverQuery`, which is what retired all 33 TS2345: "
1064-
+ "they were this package's OWN test literals failing `Property 'object' is missing in type` "
1065-
+ 'against a `QueryAST` that still required it. The ledger was never ratcheted down, so 33 errors '
1066-
+ 'of slack sat here. #6212 batch C lowers it to the measured 10 because that slack made the batch '
1067-
+ "OWN change unpinnable: this package's tsconfig excludes `*.test.ts`, so `pnpm typecheck` cannot "
1068-
+ "see `aggregate`'s narrowing at all, and its only consumers are those excluded tests. Reverting "
1069-
+ '`aggregate(object, query: DriverQuery)` back to `QueryAST` measures 12 here -- which the old '
1070-
+ '43-ceiling would have swallowed in silence. At 10 it goes red, which is the whole point of a '
1071-
+ 'ratchet. Re-measured 10 at 2bc187641, and the pristine tree at that commit reports the same 10, '
1072-
+ "so none of the -33 is this PR's doing.",
1073-
},
10741101
'@objectstack/formula': {
10751102
errors: 17,
10761103
note: 'TS2591 x6 (`process`), TS2345 x3, TS2352 x3, TS1470 x2, TS2339 x2, TS2739 x1. Re-measured 17 '

0 commit comments

Comments
 (0)