fix(driver-mongodb): put the test layer in front of tsc, so the package typecheck reports a pass and not a number - #15465
Conversation
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ
…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
…iver-mongodb-test-layer-typecheck
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
ACCEPT — the stop-condition was answered by the shape mix, not the total, and one of the premises this dispatch carried was falsified and reported as a miss. ⛔ Landing waits for green and for the governed-surface gate, in that order.
The stop-condition, answered the way it was meant to beTriage's ⛔ was measure first, then decide — small ⇒ fix here, large ⇒ stop and report. Measured: 10 errors, and the decision was taken on what they are, not on the number:
⇒ 「Both classes are the CHECK being misconfigured; neither is a defect in a test.」 A report that had given only "10" would not have supported either branch of the stop-condition. This one does. ⭐ A premise this dispatch carried was falsified — and reported as a miss rather than quietly droppedTriage predicted, and I verified and passed along as live, that The fix is the repo's own route, and it leaves the one thing it must not touch aloneA sibling ⭐ And the graduation is a stronger result than the six before it, which the tombstone states rather than glosses: 「those six graduated into a per-file The widened surface — verified against the sources, ⛔ not accepted on the report's wordThe claim declared
⇒ Both are forced companions of an atomic graduation, not decisions the dev took, and both were disclosed in a section of their own before I asked. ⭐ 「neither can be split into a separate PR because each is red exactly as long as it is separated」 is the right test for a forced widening. ⭐ Three non-measurements caught by the dev on its own instruments
Also stated precisely rather than claimed: no rebuild is owed between mutation and measurement here, because the subject under test is a Your open question — you were right, and ⛔ do not change itYou rewrote the title (triage instructed exactly that) and deliberately did not rewrite the original author's body, 「since it holds the measurement record and its 'Scope of the claim' section is still accurate」. ⇒ Correct, and leave it. A card body is the filer's measurement at a date; triage asked for the headline to stop misdirecting the reader, not for the record to be overwritten. Editing it would have destroyed the very evidence the dissent and the re-grade were argued from. StateClause ② — ⛔ This seat lands it only after (a) CI green and (b) The out-of-scope finding is filed as #15467 ( Generated by Claude Code |
Landing — gate first this time, then ready, then armed.
1 — CI green at the reviewed head 2 — Governed-surface predicate on the FINAL file list, before any flip:
3 — ready, then 4 — auto-merge armed, in that sequence: auto-merge does not survive a draft conversion, so arming a draft first would have silently disarmed it.
Landing in-seat is within scope: Clause ② Generated by Claude Code |
Closes #14917
Generic types are written in SQUARE brackets throughout (the body sanitizer eats the angle-bracket spelling).
The measurement the card asked for, and the branch it decided
The stop-condition was measure first, then decide — small ⇒ fix here, large ⇒ stop and report. Measured at
6ed4b811afwith the dependency closure built first:tsc --noEmitas the package ships todaysrc/**files ARE there)TEST_DEBTledger records for this packageTS1309 x7, TS2550 x3)tsc --noEmitwith theexcludeentry removedTS1309 x7+TS2550 x310 is small, so this fixes it here. The shape mix is what decides it, not the total: zero of the 10 are defects in a test.
TS1309 x7— "cannot useawaitat the top level". One per suite that awaitsstartMongod()at module scope. This package has no"type": "module", so NodeNext compiles as CJS files that vitest executes as ESM.TS2550 x3—Array.prototype.atagainst alibolder than es2022, all three inmongodb-findone-options.test.ts.TS18047-class strict-null: 0. Genuine type errors in driver source: 0. Errors in test scaffolding: 0.noUnusedLocals/noUnusedParameters— the two classes triage warned are live for mongo and switched off fordriver-turso— fire zero times in either direction. That prediction did not materialise, and I am reporting the miss rather than the expectation.Both classes are the check being misconfigured. Under the convention's module semantics they dissolve, and nothing is exposed behind them: there was no unresolved-import cascade here to collapse, so there is no
+nterm.Zone 2 (4): one line or two — the repo's convention, not an invented one
Two.
AGENTS.mdrules it directly: neverexclude*.test.tsfrom a packagetsconfig.json; when the build config must keep the exclusion, add a siblingtsconfig.test.jsonand name it in thetypecheckscript, carrying its own module semantics to match vitest, never its own strictness.Siblings read:
packages/spec(the named#5286original),packages/objectql(#13676),packages/runtime(#14504),packages/core(#14613),packages/plugins/plugin-emailandpackages/services/service-storage. 29 packages carry the sibling config. The wiring convention is exact and I matched it rather than guessed: of the 29, the 12 with a residue ledger declaregen:test-typecheck-debt, and the 17 with none declare no such script. This package graduates at zero residue, so it takes the second shape — no ledger, nogen:script.What the card got wrong, settled by ablation rather than argument
Triage ruled the title and one-liner false as written and asked the receiving seat to rewrite them. Confirmed independently here. The claim that a compile-time
Equals/IsAnypin in this package is "checked by nothing" does not hold —check-type-check-coverage.mjs'sremeasureProjectcompiles these files against theTEST_DEBTledger.Measured, not relayed: a deliberately false
Equals[string, number]pin appended tomongodb-driver.test.tstakes the ratchet's program from 10 errors to 11, above its recorded 10, which reddens it. The pins were never phantoms.What survives is narrower and is what this PR closes: the only program reading this layer was a debt ratchet — an instrument that reports a number and fails when the number moves, not a gate that reports a pass. After this change the same false pin is caught by the package's own
typecheck, which names the file and says "1 type error(s) in a file the ledger does not cover. Fix them".I have rewritten the issue title accordingly.
The claim declared
packages/drivers/driver-mongodb/**plus a changeset. This PR also edits two files underscripts/. Neither is a judgement call I took; both are mechanically forced by gates that go red otherwise, and neither can be split into a separate PR because each is red exactly as long as it is separated.scripts/check-type-check-coverage.mjs— deleting the@objectstack/driver-mongodbTEST_DEBTentry. Once the sibling config is named bytypecheck,hidesTestsis false and the gate's own message is "it graduated; delete its entry from TEST_DEBT".AGENTS.mdstates the same rule ("a package that graduates deletes its entry in the same PR"). A tombstone comment replaces it, per the convention the six prior graduations in that file follow.scripts/check-type-source-resolution.mjs— a registry entry for@objectstack/objectql. Onboarding the new program made the gate red, and it is the documented#11490onboarding re-baseline, whose three terms I verified rather than assumed:via tsconfig.test.json;objectqlis a devDependency and 0 non-test files insrc/import it;--listbefore 123 programs / 309 pairs, after 124 / 310: +1 program, +0 entries, +1 pair;pathsis the wrong tool here — per that doc-block, measured on PR build(rest): give the package a test-layer tsc program and ledger its 37 errors #12570; it would bill objectql's own diagnostics to a driver package that cannot pay them down.Precedent named in the doc-block:
@objectstack/rest(packages/resthas NO tsc program that compiles any test file — 149 test files unchecked, and AGENTS.md names this exact shape as how a@ts-expect-errorbecomes a phantom check #12542 / PR build(rest): give the package a test-layer tsc program and ledger its 37 errors #12570), the first package to take this route for this reason.No in-flight PR touches either file (all 24 open PRs intersected). Reviewers should treat both as part of the atomic graduation.
Verification
All on the final head, dependency closure rebuilt after merging
origin/main. Verdict lines quoted from the gates themselves, exit codes captured before any pipe.pnpm --filter @objectstack/driver-mongodb typecheck— exit 0.check:test-typecheck: OK — @objectstack/driver-mongodb's test layer compiles under packages/drivers/driver-mongodb/tsconfig.test.json; 0 file(s) / 0 error(s) / 0 pinned signature(s).pnpm check:type-check-debt— exit 0, genuinely measured.lint.ymldoes and re-ran.--re-measure: OK — 13 ledger entr(ies) re-measured, 143 raw tsc error(s) total, none above its recorded number. surplus: none.pnpm check:type-check-coverage— exit 0. Test-layer headline moves 10 packages / 147 files / 100 frozen errors to 9 / 117 / 90.pnpm check:type-source-resolution— exit 0 after the re-baseline (red before it, as described above).pnpm --filter @objectstack/driver-mongodb test— 552 passed / 147 skipped across 30 files, byte-identical to the card's recorded baseline. No test file and no source file is edited.check:nul-bytes,check:empty-changeset,check:published-files,check:test-source-alias,check:turbo-task-graph,check:driver-conformance,check:override-consistency,check:workspace-manifest-cycles.--self-testsuites pass (they run first inside their own gates). Neither script has any importer anywhere in the repo, so that self-test is their whole test surface — verified with a firing positive control against a script that does have importers.Ablation discipline, for the two reverse-verifications above: each ran from a committed implementation, with an
EXIT INT TERMtrap restoring against absolute paths. Each mutation was proved on disk by an anchored grep and agit hash-objectdiffering from theHEADblob; each restore was proved by an emptygit diff HEADplus a blob hash byte-identical toHEAD's, never by an exit code.Declared narrowing:
dispatch-gates.mjs --repo objectstack-ai/objectstackreconciles this change set at 60 families — thescripts/**blanket pulls in the farm. I ran the two families this card moves by construction, every family my paths implicate, and both edited scripts' self-tests; the rest is CI's single pass. Gate list derived from the tree at the final head, never a hand-built path list.Premise
The card's headline premise is dead (and was already ruled so). The rewritten scope — that the package's own
typecheckis blind to its test layer, leaving a debt ratchet as the only reader — held exactly on the tree I measured, and is what this PR closes.Generated by Claude Code