|
| 1 | +// The TEST-layer type-check program (#14710), adopting the mechanism #5286 set |
| 2 | +// for `packages/spec` and #5449 generalised. `tsconfig.json` beside this file |
| 3 | +// stays exactly as it is: it is the BUILD config, and its `include: ["src"]` is |
| 4 | +// correct for a build — `tsconfig.build.json` ships `src` and nothing else. |
| 5 | +// This sibling puts the unread layer in front of tsc, and `package.json`'s |
| 6 | +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a |
| 7 | +// config no script invokes is exactly the phantom this whole change is about. |
| 8 | +// |
| 9 | +// ⚠️ THIS PACKAGE REACHED THE HIDDEN STATE BY THE OTHER SPELLING, and that is |
| 10 | +// the part worth carrying to the next package. AGENTS.md forbids `exclude`-ing |
| 11 | +// `*.test.ts` from a package tsconfig. This package has no `exclude` AT ALL — |
| 12 | +// it declares `include: ["src"]`, and its 115 test files live in a sibling |
| 13 | +// `test/` tree the glob simply never reaches. Identical end state, arriving |
| 14 | +// through a door the rule's text does not cover. Whether that gap should be |
| 15 | +// closed in AGENTS.md or in `check:type-check-coverage` itself is deliberately |
| 16 | +// NOT this file's business (the card's triage said so); what IS this file's |
| 17 | +// business is that `hiddenTests` — which walks the whole package rather than |
| 18 | +// the include roots — is the only detector that could ever have seen it. |
| 19 | +// |
| 20 | +// BEFORE THIS FILE, NO tsc PROGRAM COMPILED A SINGLE `test/` FILE HERE, and |
| 21 | +// that is measured rather than read off the config. At 5a5336b399 with the |
| 22 | +// workspace closure built first, `tsc --noEmit --listFiles -p tsconfig.json` |
| 23 | +// puts 1009 files in the program and **0** of the 115 `test/**/*.test.ts` |
| 24 | +// among them — while 119 of 119 non-test `src/**` files AND all 121 of the |
| 25 | +// package's `src/**` test files ARE there. So the zero is the `include` line |
| 26 | +// and not a probe that sees nothing, and the contrast is inside this one |
| 27 | +// package: tests under `src` always compiled, tests under `test/` never did. |
| 28 | +// The directional control is `packages/drivers/driver-memory`, whose tsconfig |
| 29 | +// carries no test exclusion: the same probe puts **40 of its 40** test files in |
| 30 | +// the program. Under this file the count is **115 of 115** (1416 files total). |
| 31 | +// `pnpm --filter @objectstack/cli typecheck` exiting 0 was a true sentence |
| 32 | +// carrying no information about any file in `test/`. |
| 33 | +// |
| 34 | +// THE THREE PACKAGE-ROOT HARNESS MODULES COME IN HERE TOO, deliberately and not |
| 35 | +// as a separate concern: `vitest.config.ts`, `vitest-tiers.ts` and |
| 36 | +// `vitest-tiers.fixtures.ts` were in no tsc program either (#14554 recorded |
| 37 | +// them as NOT MEASURED rather than claiming coverage). They fall out of this |
| 38 | +// same `include`, as does `test/helpers/serve-process.ts` — the one non-test |
| 39 | +// module in the test tree, which had its own `UNCHECKED_SOURCE_DEBT` row in |
| 40 | +// `scripts/check-type-check-coverage.mjs` predicting it would "graduate with |
| 41 | +// the TEST_DEBT one rather than before it". Both graduated in this change. |
| 42 | +// |
| 43 | +// What differs from the build config, and what deliberately does NOT: |
| 44 | +// - module semantics, plus `rootDir`. The tests are written and executed as |
| 45 | +// ESM by vitest (esbuild/vite), and this package IS `"type": "module"`, so |
| 46 | +// the build config's NodeNext compiles them as ESM too — and then demands |
| 47 | +// explicit `.js` extensions on relative imports, which vitest does not. |
| 48 | +// Measured cost of that mismatch here: 120 of the 144 raw diagnostics — |
| 49 | +// TS2835 x56 (extension-less relative import), the TS7006 x59 sitting above |
| 50 | +// them (an import that does not resolve makes every symbol it names `any`), |
| 51 | +// TS2307 x3 and TS18046 x2. Those 120 are about the CHECK, never about the |
| 52 | +// code. Matching vitest is fidelity, not laxity. `lib` keeps the build |
| 53 | +// config's `DOM`/`DOM.Iterable`, restated rather than narrowed: unlike |
| 54 | +// `packages/runtime`, this package's own build config already declares them. |
| 55 | +// - ⚠️ Collapsing that cascade EXPOSES errors as well as removing them, so |
| 56 | +// 144 − 120 is 24 and the real figure is 28: |
| 57 | +// `test/i18n-extract-action-description.test.ts` gains 4 x TS18048 that its |
| 58 | +// two unresolved imports (`../src/utils/i18n-extract`, |
| 59 | +// `../src/utils/i18n-coverage`) had been hiding behind `any`. The 24 TS2339 |
| 60 | +// survive the move unchanged, file for file and count for count. Both |
| 61 | +// directions are attributed in `test-typecheck-debt.json`; there is no |
| 62 | +// unexplained remainder. |
| 63 | +// - `rootDir` IS widened, to `../..`, and this is the one place this file |
| 64 | +// departs from `packages/runtime`'s. Runtime's tests live under `src`, so |
| 65 | +// its `rootDir` could stay inherited. This package's live in a sibling |
| 66 | +// `test/` tree that is NOT under the inherited `rootDir` of `src`, and the |
| 67 | +// measured cost of leaving it alone is 116 x TS6059 — one per file in |
| 68 | +// `test/`, saying nothing about any test. `"."` is not enough either: |
| 69 | +// three of these tests import fixtures from `examples/app-showcase/src/**`, |
| 70 | +// outside this package entirely, and still report 3 x TS6059. `../..` is |
| 71 | +// the repo root and is exactly the shape `packages/client`'s test config |
| 72 | +// already uses for the same reason. ⛔ It widens the ROOT, never the |
| 73 | +// strictness. |
| 74 | +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `esModuleInterop`, |
| 75 | +// `forceConsistentCasingInFileNames` and the rest are inherited from |
| 76 | +// `tsconfig.json`, and `types: ["node"]` restates it. Nothing here may |
| 77 | +// loosen a type rule; if a test does not compile, that is the finding. |
| 78 | +// ⛔ Not one `any` and not one `@ts-expect-error` was added to any test file |
| 79 | +// to open this gate — that shape is what turns a real gate into a phantom. |
| 80 | +// |
| 81 | +// ⚠️ ONE THING THE FILING OVERSTATED, recorded so the next reader does not go |
| 82 | +// looking for it: the card's sharpest line — "a `@ts-expect-error` in any of |
| 83 | +// those 112 files is a phantom check that evaluates never" — is a statement |
| 84 | +// about what WOULD happen, not about an existing pin. Measured here: this layer |
| 85 | +// holds **zero** `@ts-expect-error` directives across all 115 test files and |
| 86 | +// the 3 root harness modules, so no pin was silently dead and none reports |
| 87 | +// TS2578 under this program. What the gap really cost is the other half: 144 |
| 88 | +// real diagnostics that no gate has ever reported, and no way to write a |
| 89 | +// type-level pin in this tree at all. The first half is now ledgered; the |
| 90 | +// second is now possible. |
| 91 | +// |
| 92 | +// MEASURED at 5a5336b399, workspace closure built first (an error count taken |
| 93 | +// against an unbuilt closure is not a reading — unresolved-import cascades |
| 94 | +// inflate it): this program reports **28 errors across 3 files**, from a raw |
| 95 | +// 144 under the inherited NodeNext semantics. That 144 is the same number |
| 96 | +// `scripts/check-type-check-coverage.mjs` recorded for this package in its |
| 97 | +// per-PACKAGE `TEST_DEBT` ledger — reproduced class for class on re-measurement |
| 98 | +// (TS7006 x59, TS2835 x56, TS2339 x24, TS2307 x3, TS18046 x2) — which is why |
| 99 | +// that entry GRADUATES in this change rather than being paid down: the |
| 100 | +// identical population is now held one level finer, per file and per signature, |
| 101 | +// in `test-typecheck-debt.json` beside this config. By code the residue is |
| 102 | +// TS2339 x24 and TS18048 x4; `test/data-model-rules.test.ts` carries 23 of the |
| 103 | +// 28 on its own, all of them property reads off a lint-diagnostic type, so one |
| 104 | +// narrowing helper there is very nearly the whole ledger. |
| 105 | +// |
| 106 | +// Every one of the 28 is PRE-EXISTING: this change edits no test file, and each |
| 107 | +// would have been reported on `origin/main` had this program always existed. |
| 108 | +// They are ledgered per file and per signature in `test-typecheck-debt.json`, |
| 109 | +// EXACT and shrink-only — a file that gains an error is red, one that loses one |
| 110 | +// is red until re-recorded, one that reaches zero is red until its entry is |
| 111 | +// deleted, a signature that arrives or vanishes is red even at a constant |
| 112 | +// total, and a file NOT listed there may have no errors at all. |
| 113 | +// ⛔ The 28 are NOT repaired here, per this card's triage ruling: seeding the |
| 114 | +// ledger and letting the ratchet shrink is the deliverable, and turning the |
| 115 | +// onboarding into a cleanup is how it stops landing at all. |
| 116 | +// |
| 117 | +// ⚠️ 112 of the 115 files carry NO ledger entry, and that is load-bearing rather |
| 118 | +// than incidental: any error any one of them ever gains is red on arrival. That |
| 119 | +// is the half of this gate that starts working today. |
| 120 | +{ |
| 121 | + "extends": "./tsconfig.json", |
| 122 | + "compilerOptions": { |
| 123 | + "noEmit": true, |
| 124 | + "rootDir": "../..", |
| 125 | + "module": "esnext", |
| 126 | + "moduleResolution": "bundler", |
| 127 | + "lib": ["ES2022", "DOM", "DOM.Iterable"], |
| 128 | + "types": ["node"] |
| 129 | + }, |
| 130 | + "include": ["test/**/*", "vitest.config.ts", "vitest-tiers.ts", "vitest-tiers.fixtures.ts"], |
| 131 | + "exclude": ["node_modules", "dist"] |
| 132 | +} |
0 commit comments