diff --git a/.changeset/plugins-test-typecheck-onboarding.md b/.changeset/plugins-test-typecheck-onboarding.md new file mode 100644 index 0000000000..8d551c9afd --- /dev/null +++ b/.changeset/plugins-test-typecheck-onboarding.md @@ -0,0 +1,55 @@ +--- +"@objectstack/embedder-openai": patch +"@objectstack/knowledge-memory": patch +"@objectstack/knowledge-ragflow": patch +"@objectstack/plugin-approvals": patch +"@objectstack/plugin-audit": patch +"@objectstack/plugin-auth": patch +"@objectstack/plugin-dev": patch +"@objectstack/plugin-email": patch +"@objectstack/plugin-hono-server": patch +"@objectstack/plugin-pinyin-search": patch +"@objectstack/plugin-reports": patch +"@objectstack/plugin-security": patch +"@objectstack/plugin-sharing": patch +"@objectstack/plugin-webhooks": patch +--- + +feat(tooling): onboard all 14 `packages/plugins/**` packages into `check:test-typecheck` (#14062) + +Every plugin package now has a `tsconfig.test.json` compiled by the shared +`check:test-typecheck` gate, and its `typecheck` script names it. Before this, +the shrink-only `test-typecheck-debt.json` ratchet said **nothing** about a +third of the repo's runtime surface: 14 packages, 1 `tsconfig.test.json` +(`plugin-security`, wired directly to `tsc` rather than to the instrument), and +0 `check:test-typecheck` scripts. + +Onboarded as a family by the director ruling of 2026-09-01 on #14062 +(maintainer verbatim: 「同意」), which also carries the #5286 maintainer +authority the starting ledgers need. The smaller branch triage recommended — +declare the instrument's scope and re-site the two compile-time pins — was +recorded as considered and not taken: an instrument silent over a third of the +runtime surface is a hole readers generalise across, and that costs more than +fourteen tsconfigs. + +**Measured, not assumed** (at `e80889095`, workspace closure built first). Four +packages carry residue and therefore a starting ledger — plugin-approvals 324 +over 8 files, plugin-auth 94 over 10, plugin-sharing 3 over 2, +knowledge-ragflow 3 over 1. The other ten measure **zero** and deliberately get +no ledger file at all: the gate reads a missing ledger as `{ entries: {} }`, so +any error there is red immediately with no entry to be added to — strictly +stronger than a ledger holding nothing, and the call `plugin-security` had +already recorded for itself. + +⛔ **This does not repair 345 type errors.** Per ruling item 3 it makes the +ratchet able to *see* them; paydown follows the ratchet's own shrink-only +discipline on its own cards. No test file is edited here. + +Two corrections to the finding's own prose, both measured: the exclusion is +narrower than "no plugin package compiles its tests" — 9 of the 14 already +compiled their tests inside the `typecheck`-invoked build config, at zero +errors — and `exec-context-annotation.pin.ts` is a `.pin.ts`, which +`**/*.test.ts` never excluded, so its directives were already live. The pin +this change genuinely makes real is +`plugin-approvals/src/manager-org-screen-parity.contract.test.ts`, which no tsc +program had ever read. diff --git a/packages/plugins/embedder-openai/package.json b/packages/plugins/embedder-openai/package.json index 231aeb3396..5785f9e36f 100644 --- a/packages/plugins/embedder-openai/package.json +++ b/packages/plugins/embedder-openai/package.json @@ -16,13 +16,15 @@ "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", "dev": "tsc -w", "test": "vitest run", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/embedder-openai --project tsconfig.test.json" }, "dependencies": { "@objectstack/spec": "workspace:*" }, "devDependencies": { "@types/node": "^26.2.0", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/embedder-openai/tsconfig.test.json b/packages/plugins/embedder-openai/tsconfig.test.json new file mode 100644 index 0000000000..8267b21d6c --- /dev/null +++ b/packages/plugins/embedder-openai/tsconfig.test.json @@ -0,0 +1,70 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 371 +// own `src/**/*.test.ts` in it 1 +// errors under BUILD semantics 0 +// errors under THIS config 0 +// +// The two readings agree, so this package carried no config-tier pile at all. +// +// BEFORE THIS FILE: the build config does NOT exclude tests, so `tsc +// --noEmit` already read this one file. This program is the family's +// uniform instrument over the same file, not a new reader of it. +// +// There is NO `test-typecheck-debt.json` beside this config, and its ABSENCE is the +// zero: `check:test-typecheck` reads a missing ledger as `{ entries: {} }`, under which +// ANY error in ANY file here is red immediately, with no entry to be added to. That is +// strictly stronger than a ledger holding nothing, and it is the same call +// `plugin-security` recorded for itself in #13176. If this package ever acquires +// residue that cannot be fixed in the PR that causes it, THAT is when a ledger and a +// `gen:test-typecheck-debt` script are owed — and adding one is maintainer-only +// (#5286), exactly as the gate says when it refuses. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/knowledge-memory/package.json b/packages/plugins/knowledge-memory/package.json index 9dc25205a0..d6a10ecda3 100644 --- a/packages/plugins/knowledge-memory/package.json +++ b/packages/plugins/knowledge-memory/package.json @@ -16,7 +16,8 @@ "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", "dev": "tsc -w", "test": "vitest run", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/knowledge-memory --project tsconfig.test.json" }, "dependencies": { "@objectstack/core": "workspace:*", @@ -25,6 +26,7 @@ }, "devDependencies": { "@types/node": "^26.2.0", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/knowledge-memory/tsconfig.test.json b/packages/plugins/knowledge-memory/tsconfig.test.json new file mode 100644 index 0000000000..0a39b916f2 --- /dev/null +++ b/packages/plugins/knowledge-memory/tsconfig.test.json @@ -0,0 +1,70 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 388 +// own `src/**/*.test.ts` in it 1 +// errors under BUILD semantics 0 +// errors under THIS config 0 +// +// The two readings agree, so this package carried no config-tier pile at all. +// +// BEFORE THIS FILE: the build config does NOT exclude tests, so `tsc +// --noEmit` already read this one file. This program is the family's +// uniform instrument over the same file, not a new reader of it. +// +// There is NO `test-typecheck-debt.json` beside this config, and its ABSENCE is the +// zero: `check:test-typecheck` reads a missing ledger as `{ entries: {} }`, under which +// ANY error in ANY file here is red immediately, with no entry to be added to. That is +// strictly stronger than a ledger holding nothing, and it is the same call +// `plugin-security` recorded for itself in #13176. If this package ever acquires +// residue that cannot be fixed in the PR that causes it, THAT is when a ledger and a +// `gen:test-typecheck-debt` script are owed — and adding one is maintainer-only +// (#5286), exactly as the gate says when it refuses. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/knowledge-ragflow/package.json b/packages/plugins/knowledge-ragflow/package.json index 2e2df76042..8ddea4a067 100644 --- a/packages/plugins/knowledge-ragflow/package.json +++ b/packages/plugins/knowledge-ragflow/package.json @@ -15,7 +15,10 @@ "scripts": { "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", "dev": "tsc -w", - "test": "vitest run" + "test": "vitest run", + "typecheck": "tsc --noEmit && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/knowledge-ragflow --project tsconfig.test.json", + "gen:test-typecheck-debt": "tsx ../../../scripts/check-test-typecheck.mts --update --package packages/plugins/knowledge-ragflow --project tsconfig.test.json" }, "dependencies": { "@objectstack/core": "workspace:*", @@ -24,6 +27,7 @@ }, "devDependencies": { "@types/node": "^26.2.0", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/knowledge-ragflow/test-typecheck-debt.json b/packages/plugins/knowledge-ragflow/test-typecheck-debt.json new file mode 100644 index 0000000000..8d6dbc1fdf --- /dev/null +++ b/packages/plugins/knowledge-ragflow/test-typecheck-debt.json @@ -0,0 +1,9 @@ +{ + "_comment": "Per-file tsc error debt of the @objectstack/knowledge-ragflow TEST layer (#5286). `tsconfig.test.json` compiles `src/**/*.test.ts` — which `tsconfig.json` excludes and therefore no gate ever read — and every file below still carries errors from before that gate existed. THIS FIELD IS GENERATED: every regeneration rewrites it from scripts/check-test-typecheck.mts, and the EXACT ratchet below requires a regeneration on every repair — so an edit made here is gone by the next one. Anything true of THIS package goes in the sibling `_note` field, which is authored, is preserved verbatim, and is never written by the generator (#12624). This comment states NO cause for the errors, deliberately: the classes differ per package and per file, they move as the debt is paid down, and a cause written here is rewritten verbatim into every ledger by every regeneration — so it outlives its own repair and cannot be corrected in the file where it is read. Measure instead, before repairing anything: `tsc --noEmit --pretty false -p tsconfig.test.json` in the package prints the real classes with their TS codes. Each entry maps a file to its per-SIGNATURE error counts, never to a bare total (#13470): a signature is the TS code plus the diagnostic message with structural type blobs collapsed, and it carries NO line or column — so the pin survives edits that move code around, and only stops matching when the error itself becomes a different error. EXACT ratchet, judged by re-running tsc: a file that gains errors is red, a file that loses them is red until its number is re-recorded, a file that reaches zero is red until its entry is deleted, a signature that ARRIVES or VANISHES is red even when the file total is unchanged, and a file NOT listed here may have no errors at all. Regenerate with: pnpm --filter @objectstack/knowledge-ragflow gen:test-typecheck-debt", + "_note": "STARTING LEDGER, opened by #14062 under the director ruling of 2026-09-01 (maintainer verbatim: 「同意」), which carries the #5286 maintainer authority for it. 3 errors in 1 file, all PRE-EXISTING — and this package was silent for a DIFFERENT reason than its siblings: its `tsconfig.json` never excluded tests, so a tsc program would have read them, but the package declared NO `typecheck` script at all, and `turbo run typecheck` cannot run a script that does not exist. #14062 added one naming this gate. ⛔ That is not the repo-wide 'packages missing a `typecheck` script' carry-over, which the same ruling holds separate (item 5): this is the one invocation path #14062's own instrument needs in order to run here at all.", + "entries": { + "src/__tests__/ragflow-adapter.test.ts": { + "TS2353: Object literal may only specify known properties, and 'options' does not exist in type '…'.": 3 + } + } +} diff --git a/packages/plugins/knowledge-ragflow/tsconfig.json b/packages/plugins/knowledge-ragflow/tsconfig.json index 5bb764a0d7..4fde07cb0e 100644 --- a/packages/plugins/knowledge-ragflow/tsconfig.json +++ b/packages/plugins/knowledge-ragflow/tsconfig.json @@ -16,5 +16,24 @@ "rootDir": "./src" }, "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] + // [#14062] `**/*.test.ts` moved OUT of this program and INTO the sibling + // `tsconfig.test.json`, which `typecheck` names via `check:test-typecheck`. + // Read the direction carefully — this is not a package hiding its tests: + // + // This package declared NO `typecheck` script at all until #14062, so the + // fact that its tests were inside the BUILD program bought nothing; no tsc + // program was ever RUN over them, and the 3 errors they carry sat there + // unseen. Adding the script is what makes the program real, and it must + // invoke tsc (`check:type-check-coverage` refuses a `typecheck` that never + // type-checks). With the tests still here, that first limb would be red on + // arrival at debt this card is explicitly NOT chartered to repair — the + // ruling of 2026-09-01 says the job is to let the ratchet SEE the errors, and + // that repair follows the ratchet's own shrink-only discipline afterwards. + // + // So the split is the family's shape, not an exemption: `tsc --noEmit` here + // judges the shipped source, and every test file is judged one command later + // by `check:test-typecheck` against an EXACT, shrink-only per-signature + // ledger. Nothing stops being compiled; the two halves are named separately + // so each can be true about its own layer. + "exclude": ["node_modules", "dist", "**/*.test.ts"] } diff --git a/packages/plugins/knowledge-ragflow/tsconfig.test.json b/packages/plugins/knowledge-ragflow/tsconfig.test.json new file mode 100644 index 0000000000..52d24d99d7 --- /dev/null +++ b/packages/plugins/knowledge-ragflow/tsconfig.test.json @@ -0,0 +1,75 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 388 +// own `src/**/*.test.ts` in it 1 +// errors under BUILD semantics 4 +// errors under THIS config 3 +// +// The difference is exactly the config tier — 1 x TS2550 +// (`Array.prototype.at` against the root config's `lib: ES2020`) — and not +// one line of test code. Fixing the CHECK first and reading the residue +// afterwards is the #4311 discipline this repo already writes down. +// +// BEFORE THIS FILE: the build config does not exclude tests EITHER, but +// this package declared NO `typecheck` script at all — so no tsc program +// was ever RUN over them. Same silence, reached the other way, and the 3 +// residual errors below are what it was hiding. +// +// The 3 residual error(s) are PRE-EXISTING — this change edits no test file, and +// every one of them would have been reported on `origin/main` had this program always +// existed. They are ledgered per file in `test-typecheck-debt.json` beside this config, +// EXACT and shrink-only: a file that gains an error is red, one that loses an error is +// red until re-recorded, one that reaches zero is red until its entry is deleted, a +// signature that ARRIVES or VANISHES is red even at an unchanged file total, and a file +// NOT listed there may have no errors at all. ⛔ The ruling is explicit that this PR +// does not REPAIR them — it makes the ratchet able to see them; paydown follows the +// ratchet's own shrink-only discipline, on its own cards. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/plugin-approvals/package.json b/packages/plugins/plugin-approvals/package.json index a1e68fe728..2ed4568d02 100644 --- a/packages/plugins/plugin-approvals/package.json +++ b/packages/plugins/plugin-approvals/package.json @@ -14,8 +14,10 @@ }, "scripts": { "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", - "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json", - "test": "vitest run --passWithNoTests" + "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json && pnpm check:test-typecheck", + "test": "vitest run --passWithNoTests", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-approvals --project tsconfig.test.json", + "gen:test-typecheck-debt": "tsx ../../../scripts/check-test-typecheck.mts --update --package packages/plugins/plugin-approvals --project tsconfig.test.json" }, "dependencies": { "@objectstack/core": "workspace:*", @@ -32,6 +34,7 @@ "@objectstack/service-automation": "workspace:*", "@objectstack/trigger-record-change": "workspace:*", "@types/node": "^26.2.0", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/plugin-approvals/test-typecheck-debt.json b/packages/plugins/plugin-approvals/test-typecheck-debt.json new file mode 100644 index 0000000000..130e603a02 --- /dev/null +++ b/packages/plugins/plugin-approvals/test-typecheck-debt.json @@ -0,0 +1,49 @@ +{ + "_comment": "Per-file tsc error debt of the @objectstack/plugin-approvals TEST layer (#5286). `tsconfig.test.json` compiles `src/**/*.test.ts` — which `tsconfig.json` excludes and therefore no gate ever read — and every file below still carries errors from before that gate existed. THIS FIELD IS GENERATED: every regeneration rewrites it from scripts/check-test-typecheck.mts, and the EXACT ratchet below requires a regeneration on every repair — so an edit made here is gone by the next one. Anything true of THIS package goes in the sibling `_note` field, which is authored, is preserved verbatim, and is never written by the generator (#12624). This comment states NO cause for the errors, deliberately: the classes differ per package and per file, they move as the debt is paid down, and a cause written here is rewritten verbatim into every ledger by every regeneration — so it outlives its own repair and cannot be corrected in the file where it is read. Measure instead, before repairing anything: `tsc --noEmit --pretty false -p tsconfig.test.json` in the package prints the real classes with their TS codes. Each entry maps a file to its per-SIGNATURE error counts, never to a bare total (#13470): a signature is the TS code plus the diagnostic message with structural type blobs collapsed, and it carries NO line or column — so the pin survives edits that move code around, and only stops matching when the error itself becomes a different error. EXACT ratchet, judged by re-running tsc: a file that gains errors is red, a file that loses them is red until its number is re-recorded, a file that reaches zero is red until its entry is deleted, a signature that ARRIVES or VANISHES is red even when the file total is unchanged, and a file NOT listed here may have no errors at all. Regenerate with: pnpm --filter @objectstack/plugin-approvals gen:test-typecheck-debt", + "_note": "STARTING LEDGER, opened by #14062 under the director ruling of 2026-09-01 (maintainer verbatim: 「同意」), which carries the #5286 maintainer authority for it. 324 errors over 8 files, every one PRE-EXISTING: that PR added `tsconfig.test.json` and edited no test file, so each of these would have been reported on `origin/main` had a tsc program ever compiled this layer. The finding measured 345 by the same recipe minus the vitest module semantics; the 21 difference is the config tier (20 x TS2550 from `lib: ES2021`, 1 x TS1470 `import.meta` in a CommonJS program) and not one line of test code. 263 of the 324 sit in `src/approval-service.test.ts` and are overwhelmingly one shape — `openNodeRequest` returns `ApprovalRequestRow | ApprovalNodeAutoOutcome` and callers read members off the union without narrowing. ⛔ The ruling is explicit that opening the ratchet is NOT the same job as paying it down: paydown follows this ledger's own shrink-only discipline, on its own cards.", + "entries": { + "src/admin-exemption-retired.test.ts": { + "TS2339: Property 'id' does not exist on type '…'.": 11, + "TS2339: Property 'pending_approvers' does not exist on type '…'.": 3 + }, + "src/approval-actor-impersonation.test.ts": { + "TS18048: 'row' is possibly 'undefined'.": 2, + "TS2339: Property 'id' does not exist on type '…'.": 18 + }, + "src/approval-override-audit.test.ts": { + "TS2339: Property 'id' does not exist on type '…'.": 17, + "TS2339: Property 'pending_approvers' does not exist on type '…'.": 2 + }, + "src/approval-revise.test.ts": { + "TS6133: 'APPROVALS_HOOK_PACKAGE' is declared but its value is never read.": 1 + }, + "src/approval-service.test.ts": { + "TS18048: 'act' is possibly 'undefined'.": 1, + "TS18048: 'action' is possibly 'undefined'.": 3, + "TS18048: 'row' is possibly 'undefined'.": 2, + "TS18048: 'sub' is possibly 'undefined'.": 2, + "TS2339: Property 'created_at' does not exist on type '…'.": 2, + "TS2339: Property 'flow_node_id' does not exist on type '…'.": 1, + "TS2339: Property 'flow_run_id' does not exist on type '…'.": 1, + "TS2339: Property 'id' does not exist on type '…'.": 182, + "TS2339: Property 'lock_record' does not exist on type '…'.": 3, + "TS2339: Property 'pending_approvers' does not exist on type '…'.": 40, + "TS2339: Property 'process_label' does not exist on type '…'.": 2, + "TS2339: Property 'process_name' does not exist on type '…'.": 1, + "TS2339: Property 'sla_due_at' does not exist on type '…'.": 2, + "TS2339: Property 'status' does not exist on type '…'.": 1, + "TS2339: Property 'step_label' does not exist on type '…'.": 2, + "TS2339: Property 'submitted_at' does not exist on type '…'.": 2, + "TS2345: Argument of type '…' is not assignable to parameter of type '…'.": 16 + }, + "src/approver-cross-org.integration.test.ts": { + "TS2339: Property 'pending_approvers' does not exist on type '…'.": 5 + }, + "src/record-lock-schedule-run.integration.test.ts": { + "TS2352: Conversion of type 'RunDataContext | undefined' to type '…' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.": 1 + }, + "src/status-mirror-cascade.integration.test.ts": { + "TS2339: Property 'id' does not exist on type '…'.": 1 + } + } +} diff --git a/packages/plugins/plugin-approvals/tsconfig.test.json b/packages/plugins/plugin-approvals/tsconfig.test.json new file mode 100644 index 0000000000..e8743981c6 --- /dev/null +++ b/packages/plugins/plugin-approvals/tsconfig.test.json @@ -0,0 +1,76 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 540 +// own `src/**/*.test.ts` in it 35 +// errors under BUILD semantics 345 +// errors under THIS config 324 +// +// The difference is exactly the config tier — 20 x TS2550 (`lib: ES2021` +// older than es2022) + 1 x TS1470 (`import.meta` in a CommonJS program) — +// and not one line of test code. Fixing the CHECK first and reading the +// residue afterwards is the #4311 discipline this repo already writes down. +// +// BEFORE THIS FILE: the build config's `exclude` NAMED `**/*.test.ts` and +// `typecheck` was `tsc --noEmit` against that very config — so `pnpm +// --filter @objectstack/plugin-approvals typecheck` exiting 0 was a true +// sentence carrying no information about any of the 35 test files here +// (#14062). +// +// The 324 residual error(s) are PRE-EXISTING — this change edits no test file, and +// every one of them would have been reported on `origin/main` had this program always +// existed. They are ledgered per file in `test-typecheck-debt.json` beside this config, +// EXACT and shrink-only: a file that gains an error is red, one that loses an error is +// red until re-recorded, one that reaches zero is red until its entry is deleted, a +// signature that ARRIVES or VANISHES is red even at an unchanged file total, and a file +// NOT listed there may have no errors at all. ⛔ The ruling is explicit that this PR +// does not REPAIR them — it makes the ratchet able to see them; paydown follows the +// ratchet's own shrink-only discipline, on its own cards. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/plugin-audit/package.json b/packages/plugins/plugin-audit/package.json index c186a0fe70..ef8dd9bd58 100644 --- a/packages/plugins/plugin-audit/package.json +++ b/packages/plugins/plugin-audit/package.json @@ -15,7 +15,8 @@ "scripts": { "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", "test": "vitest run --passWithNoTests", - "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json" + "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-audit --project tsconfig.test.json" }, "dependencies": { "@objectstack/core": "workspace:*", @@ -26,6 +27,7 @@ }, "devDependencies": { "@types/node": "^26.2.0", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/plugin-audit/tsconfig.test.json b/packages/plugins/plugin-audit/tsconfig.test.json new file mode 100644 index 0000000000..e71268bfd6 --- /dev/null +++ b/packages/plugins/plugin-audit/tsconfig.test.json @@ -0,0 +1,70 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 496 +// own `src/**/*.test.ts` in it 22 +// errors under BUILD semantics 0 +// errors under THIS config 0 +// +// The two readings agree, so this package carried no config-tier pile at all. +// +// BEFORE THIS FILE: the build config does NOT exclude tests, so `tsc +// --noEmit` already read all 22. This program is the family's uniform +// instrument over the same files, not a new reader of them. +// +// There is NO `test-typecheck-debt.json` beside this config, and its ABSENCE is the +// zero: `check:test-typecheck` reads a missing ledger as `{ entries: {} }`, under which +// ANY error in ANY file here is red immediately, with no entry to be added to. That is +// strictly stronger than a ledger holding nothing, and it is the same call +// `plugin-security` recorded for itself in #13176. If this package ever acquires +// residue that cannot be fixed in the PR that causes it, THAT is when a ledger and a +// `gen:test-typecheck-debt` script are owed — and adding one is maintainer-only +// (#5286), exactly as the gate says when it refuses. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/plugin-auth/package.json b/packages/plugins/plugin-auth/package.json index 74e92d14c9..ccf440f822 100644 --- a/packages/plugins/plugin-auth/package.json +++ b/packages/plugins/plugin-auth/package.json @@ -21,7 +21,9 @@ "scripts": { "build": "tsup && node ../../../scripts/check-dts-emitted.mjs", "test": "vitest run", - "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.examples.json" + "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.examples.json && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-auth --project tsconfig.test.json", + "gen:test-typecheck-debt": "tsx ../../../scripts/check-test-typecheck.mts --update --package packages/plugins/plugin-auth --project tsconfig.test.json" }, "dependencies": { "@better-auth/core": "^1.7.2", @@ -44,6 +46,7 @@ "@objectstack/plugin-security": "workspace:*", "@types/node": "^26.2.0", "hono": "^4.13.2", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/plugin-auth/test-typecheck-debt.json b/packages/plugins/plugin-auth/test-typecheck-debt.json new file mode 100644 index 0000000000..11f8f4ea43 --- /dev/null +++ b/packages/plugins/plugin-auth/test-typecheck-debt.json @@ -0,0 +1,49 @@ +{ + "_comment": "Per-file tsc error debt of the @objectstack/plugin-auth TEST layer (#5286). `tsconfig.test.json` compiles `src/**/*.test.ts` — which `tsconfig.json` excludes and therefore no gate ever read — and every file below still carries errors from before that gate existed. THIS FIELD IS GENERATED: every regeneration rewrites it from scripts/check-test-typecheck.mts, and the EXACT ratchet below requires a regeneration on every repair — so an edit made here is gone by the next one. Anything true of THIS package goes in the sibling `_note` field, which is authored, is preserved verbatim, and is never written by the generator (#12624). This comment states NO cause for the errors, deliberately: the classes differ per package and per file, they move as the debt is paid down, and a cause written here is rewritten verbatim into every ledger by every regeneration — so it outlives its own repair and cannot be corrected in the file where it is read. Measure instead, before repairing anything: `tsc --noEmit --pretty false -p tsconfig.test.json` in the package prints the real classes with their TS codes. Each entry maps a file to its per-SIGNATURE error counts, never to a bare total (#13470): a signature is the TS code plus the diagnostic message with structural type blobs collapsed, and it carries NO line or column — so the pin survives edits that move code around, and only stops matching when the error itself becomes a different error. EXACT ratchet, judged by re-running tsc: a file that gains errors is red, a file that loses them is red until its number is re-recorded, a file that reaches zero is red until its entry is deleted, a signature that ARRIVES or VANISHES is red even when the file total is unchanged, and a file NOT listed here may have no errors at all. Regenerate with: pnpm --filter @objectstack/plugin-auth gen:test-typecheck-debt", + "_note": "STARTING LEDGER, opened by #14062 under the director ruling of 2026-09-01 (maintainer verbatim: 「同意」), which carries the #5286 maintainer authority for it. 94 errors over 10 files, every one PRE-EXISTING — the build config's `exclude` named `**/*.test.ts`, so no tsc program this package's `typecheck` runs had ever read any of its 87 test files. Measured identically with and without the vitest module semantics: this package carried no config-tier pile at all. The largest class is TS2493 x36 (tuple index out of bounds, from indexing fixed-length mock call tuples). ⛔ Opening the ratchet is not paying it down; paydown follows this ledger's own shrink-only discipline, on its own cards.", + "entries": { + "src/admin-import-users.test.ts": { + "TS2493: Tuple type '…' of length '0' has no element at index '0'.": 6, + "TS2493: Tuple type '…' of length '0' has no element at index '1'.": 1, + "TS2532: Object is possibly 'undefined'.": 4 + }, + "src/admin-user-endpoints.test.ts": { + "TS18048: 'auditRow' is possibly 'undefined'.": 5, + "TS2345: Argument of type 'null' is not assignable to parameter of type '…'.": 1, + "TS2345: Argument of type '…' is not assignable to parameter of type '…'.": 1, + "TS2493: Tuple type '…' of length '0' has no element at index '0'.": 7, + "TS2493: Tuple type '…' of length '0' has no element at index '1'.": 4 + }, + "src/auth-manager.jwt-eddsa-fallback.test.ts": { + "TS7006: Parameter 'call' implicitly has an 'any' type.": 2 + }, + "src/auth-manager.test.ts": { + "TS18048: 'arg' is possibly 'undefined'.": 3, + "TS18048: 'patch' is possibly 'undefined'.": 15, + "TS18048: 'wrote' is possibly 'undefined'.": 1, + "TS2339: Property 'data' does not exist on type 'undefined'.": 3, + "TS2493: Tuple type '…' of length '0' has no element at index '0'.": 3, + "TS2493: Tuple type '…' of length '0' has no element at index '1'.": 13, + "TS2532: Object is possibly 'undefined'.": 5 + }, + "src/auth-plugin.test.ts": { + "TS2322: Type '…' is not assignable to type '…'.": 11, + "TS2769: No overload matches this call.": 1 + }, + "src/better-auth-schema-parity.test.ts": { + "TS2345: Argument of type '…' is not assignable to parameter of type 'PhoneNumberOptions'.": 1 + }, + "src/oauth-provider-schema-parity.test.ts": { + "TS2345: Argument of type '…' is not assignable to parameter of type '…'.": 1 + }, + "src/objectql-adapter.test.ts": { + "TS2741: Property 'mode' is missing in type '…' but required in type '…'.": 3 + }, + "src/reconcile-membership.test.ts": { + "TS2493: Tuple type '…' of length '2' has no element at index '2'.": 2 + }, + "src/sso-client-secret-at-rest.test.ts": { + "TS6133: 'Field' is declared but its value is never read.": 1 + } + } +} diff --git a/packages/plugins/plugin-auth/tsconfig.test.json b/packages/plugins/plugin-auth/tsconfig.test.json new file mode 100644 index 0000000000..0754b7bce0 --- /dev/null +++ b/packages/plugins/plugin-auth/tsconfig.test.json @@ -0,0 +1,71 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 1177 +// own `src/**/*.test.ts` in it 87 +// errors under BUILD semantics 94 +// errors under THIS config 94 +// +// The two readings agree, so this package carried no config-tier pile at all. +// +// BEFORE THIS FILE: the build config's `exclude` NAMED `**/*.test.ts`, so +// none of the 87 test files here reached any tsc program the `typecheck` +// script runs (#14062). +// +// The 94 residual error(s) are PRE-EXISTING — this change edits no test file, and +// every one of them would have been reported on `origin/main` had this program always +// existed. They are ledgered per file in `test-typecheck-debt.json` beside this config, +// EXACT and shrink-only: a file that gains an error is red, one that loses an error is +// red until re-recorded, one that reaches zero is red until its entry is deleted, a +// signature that ARRIVES or VANISHES is red even at an unchanged file total, and a file +// NOT listed there may have no errors at all. ⛔ The ruling is explicit that this PR +// does not REPAIR them — it makes the ratchet able to see them; paydown follows the +// ratchet's own shrink-only discipline, on its own cards. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/plugin-dev/package.json b/packages/plugins/plugin-dev/package.json index e5157d8395..f047cfffd2 100644 --- a/packages/plugins/plugin-dev/package.json +++ b/packages/plugins/plugin-dev/package.json @@ -15,7 +15,8 @@ "scripts": { "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", "test": "vitest run", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-dev --project tsconfig.test.json" }, "dependencies": { "@objectstack/account": "workspace:^", @@ -36,6 +37,7 @@ }, "devDependencies": { "@types/node": "^26.2.0", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/plugin-dev/tsconfig.test.json b/packages/plugins/plugin-dev/tsconfig.test.json new file mode 100644 index 0000000000..ea553400b2 --- /dev/null +++ b/packages/plugins/plugin-dev/tsconfig.test.json @@ -0,0 +1,70 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 914 +// own `src/**/*.test.ts` in it 6 +// errors under BUILD semantics 0 +// errors under THIS config 0 +// +// The two readings agree, so this package carried no config-tier pile at all. +// +// BEFORE THIS FILE: the build config does NOT exclude tests, so `tsc +// --noEmit` already read all 6. This program is the family's uniform +// instrument over the same files, not a new reader of them. +// +// There is NO `test-typecheck-debt.json` beside this config, and its ABSENCE is the +// zero: `check:test-typecheck` reads a missing ledger as `{ entries: {} }`, under which +// ANY error in ANY file here is red immediately, with no entry to be added to. That is +// strictly stronger than a ledger holding nothing, and it is the same call +// `plugin-security` recorded for itself in #13176. If this package ever acquires +// residue that cannot be fixed in the PR that causes it, THAT is when a ledger and a +// `gen:test-typecheck-debt` script are owed — and adding one is maintainer-only +// (#5286), exactly as the gate says when it refuses. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/plugin-email/package.json b/packages/plugins/plugin-email/package.json index 01c9a88251..a5e64aa0b8 100644 --- a/packages/plugins/plugin-email/package.json +++ b/packages/plugins/plugin-email/package.json @@ -15,7 +15,8 @@ "scripts": { "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", "test": "vitest run --passWithNoTests", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-email --project tsconfig.test.json" }, "dependencies": { "@objectstack/core": "workspace:*", @@ -30,6 +31,7 @@ "@objectstack/service-settings": "workspace:*", "@types/node": "^26.2.0", "@types/nodemailer": "^8.0.1", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/plugin-email/tsconfig.test.json b/packages/plugins/plugin-email/tsconfig.test.json new file mode 100644 index 0000000000..5023e4b19e --- /dev/null +++ b/packages/plugins/plugin-email/tsconfig.test.json @@ -0,0 +1,72 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 469 +// own `src/**/*.test.ts` in it 28 +// errors under BUILD semantics 0 +// errors under THIS config 0 +// +// The two readings agree, so this package carried no config-tier pile at all. +// +// BEFORE THIS FILE: the build config does NOT exclude tests, so `tsc +// --noEmit` already read all 28 — including the `@ts-expect-error` in +// `src/outbox-sweep.test.ts`, which was therefore already live. This +// program is the family's uniform instrument over the same files, not a new +// reader of them. +// +// There is NO `test-typecheck-debt.json` beside this config, and its ABSENCE is the +// zero: `check:test-typecheck` reads a missing ledger as `{ entries: {} }`, under which +// ANY error in ANY file here is red immediately, with no entry to be added to. That is +// strictly stronger than a ledger holding nothing, and it is the same call +// `plugin-security` recorded for itself in #13176. If this package ever acquires +// residue that cannot be fixed in the PR that causes it, THAT is when a ledger and a +// `gen:test-typecheck-debt` script are owed — and adding one is maintainer-only +// (#5286), exactly as the gate says when it refuses. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/plugin-hono-server/package.json b/packages/plugins/plugin-hono-server/package.json index ccb8740bf1..6273798eea 100644 --- a/packages/plugins/plugin-hono-server/package.json +++ b/packages/plugins/plugin-hono-server/package.json @@ -15,7 +15,8 @@ "scripts": { "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", "test": "vitest run", - "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.typecheck.json" + "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.typecheck.json && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-hono-server --project tsconfig.test.json" }, "dependencies": { "@hono/node-server": "^2.1.1", @@ -27,6 +28,7 @@ }, "devDependencies": { "@types/node": "^26.2.0", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/plugin-hono-server/tsconfig.test.json b/packages/plugins/plugin-hono-server/tsconfig.test.json new file mode 100644 index 0000000000..57ef71a9bb --- /dev/null +++ b/packages/plugins/plugin-hono-server/tsconfig.test.json @@ -0,0 +1,74 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - ⛔ NO `lib` OVERRIDE HERE, unlike the sibling configs in this family, and +// that is measured rather than stylistic: this package's `tsconfig.json` +// does NOT extend the root config and declares no `lib`, so tsc supplies +// the default for `target: ES2022` — which INCLUDES `DOM`. Pinning +// `lib: ["ES2022"]` the way the siblings do STRIPS it, and this program +// then reports 34 errors that do not exist: 26 of them inside +// `node_modules` .d.ts files (`ai`, `hono`, `@ai-sdk/provider-utils` — +// TS2304 for `ReadableStream` and friends), which this package cannot +// even reach to fix. Measured both ways; 0 errors without the override. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 438 +// own `src/**/*.test.ts` in it 20 +// errors under BUILD semantics 0 +// errors under THIS config 0 +// +// The two readings agree, so this package carried no config-tier pile at all. +// +// BEFORE THIS FILE: the build config does NOT exclude tests, so `tsc +// --noEmit` already read all 20. This program is the family's uniform +// instrument over the same files, not a new reader of them. +// +// There is NO `test-typecheck-debt.json` beside this config, and its ABSENCE is the +// zero: `check:test-typecheck` reads a missing ledger as `{ entries: {} }`, under which +// ANY error in ANY file here is red immediately, with no entry to be added to. That is +// strictly stronger than a ledger holding nothing, and it is the same call +// `plugin-security` recorded for itself in #13176. If this package ever acquires +// residue that cannot be fixed in the PR that causes it, THAT is when a ledger and a +// `gen:test-typecheck-debt` script are owed — and adding one is maintainer-only +// (#5286), exactly as the gate says when it refuses. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/plugin-pinyin-search/package.json b/packages/plugins/plugin-pinyin-search/package.json index a4cec2237e..8cbe9aa372 100644 --- a/packages/plugins/plugin-pinyin-search/package.json +++ b/packages/plugins/plugin-pinyin-search/package.json @@ -15,7 +15,8 @@ "scripts": { "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", "test": "vitest run --passWithNoTests", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-pinyin-search --project tsconfig.test.json" }, "dependencies": { "@objectstack/core": "workspace:*", @@ -25,6 +26,7 @@ }, "devDependencies": { "@types/node": "^26.2.0", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/plugin-pinyin-search/tsconfig.test.json b/packages/plugins/plugin-pinyin-search/tsconfig.test.json new file mode 100644 index 0000000000..1db36dd97c --- /dev/null +++ b/packages/plugins/plugin-pinyin-search/tsconfig.test.json @@ -0,0 +1,70 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 424 +// own `src/**/*.test.ts` in it 2 +// errors under BUILD semantics 0 +// errors under THIS config 0 +// +// The two readings agree, so this package carried no config-tier pile at all. +// +// BEFORE THIS FILE: the build config does NOT exclude tests, so `tsc +// --noEmit` already read both. This program is the family's uniform +// instrument over the same files, not a new reader of them. +// +// There is NO `test-typecheck-debt.json` beside this config, and its ABSENCE is the +// zero: `check:test-typecheck` reads a missing ledger as `{ entries: {} }`, under which +// ANY error in ANY file here is red immediately, with no entry to be added to. That is +// strictly stronger than a ledger holding nothing, and it is the same call +// `plugin-security` recorded for itself in #13176. If this package ever acquires +// residue that cannot be fixed in the PR that causes it, THAT is when a ledger and a +// `gen:test-typecheck-debt` script are owed — and adding one is maintainer-only +// (#5286), exactly as the gate says when it refuses. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/plugin-reports/package.json b/packages/plugins/plugin-reports/package.json index 330ebcc98d..abc78ed297 100644 --- a/packages/plugins/plugin-reports/package.json +++ b/packages/plugins/plugin-reports/package.json @@ -15,7 +15,8 @@ "scripts": { "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", "test": "vitest run --passWithNoTests", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-reports --project tsconfig.test.json" }, "dependencies": { "@objectstack/core": "workspace:*", @@ -27,6 +28,7 @@ "@objectstack/driver-sql": "workspace:*", "@objectstack/objectql": "workspace:*", "@types/node": "^26.2.0", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/plugin-reports/tsconfig.test.json b/packages/plugins/plugin-reports/tsconfig.test.json new file mode 100644 index 0000000000..54404ad59d --- /dev/null +++ b/packages/plugins/plugin-reports/tsconfig.test.json @@ -0,0 +1,72 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 424 +// own `src/**/*.test.ts` in it 5 +// errors under BUILD semantics 0 +// errors under THIS config 0 +// +// The two readings agree, so this package carried no config-tier pile at all. +// +// BEFORE THIS FILE: the build config does NOT exclude tests, so `tsc +// --noEmit` already read all 5 — including the `@ts-expect-error` +// directives in `src/exec-context-annotation.pin.ts`, which were therefore +// already live. This program is the family's uniform instrument over the +// same files. +// +// There is NO `test-typecheck-debt.json` beside this config, and its ABSENCE is the +// zero: `check:test-typecheck` reads a missing ledger as `{ entries: {} }`, under which +// ANY error in ANY file here is red immediately, with no entry to be added to. That is +// strictly stronger than a ledger holding nothing, and it is the same call +// `plugin-security` recorded for itself in #13176. If this package ever acquires +// residue that cannot be fixed in the PR that causes it, THAT is when a ledger and a +// `gen:test-typecheck-debt` script are owed — and adding one is maintainer-only +// (#5286), exactly as the gate says when it refuses. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/plugin-security/package.json b/packages/plugins/plugin-security/package.json index 431649545f..e5d900527b 100644 --- a/packages/plugins/plugin-security/package.json +++ b/packages/plugins/plugin-security/package.json @@ -2,7 +2,7 @@ "name": "@objectstack/plugin-security", "version": "17.2.0", "license": "Apache-2.0", - "description": "Security Plugin for ObjectStack \u2014 RBAC, RLS, and Field-Level Security Runtime", + "description": "Security Plugin for ObjectStack — RBAC, RLS, and Field-Level Security Runtime", "main": "dist/index.js", "types": "dist/index.d.ts", "exports": { @@ -15,7 +15,8 @@ "scripts": { "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", "test": "vitest run", - "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json && tsc --noEmit -p tsconfig.test.json" + "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-security --project tsconfig.test.json" }, "dependencies": { "@objectstack/core": "workspace:*", @@ -32,6 +33,7 @@ "@objectstack/plugin-sharing": "workspace:*", "@objectstack/service-i18n": "workspace:*", "@types/node": "^26.2.0", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/plugin-security/tsconfig.test.json b/packages/plugins/plugin-security/tsconfig.test.json index 5bf0599b83..6c27644ff4 100644 --- a/packages/plugins/plugin-security/tsconfig.test.json +++ b/packages/plugins/plugin-security/tsconfig.test.json @@ -76,8 +76,24 @@ // costing this package a `tsx` dependency and two more scripts; a bare // `tsc --noEmit -p tsconfig.test.json` is the strictly stronger gate at zero // residue, because ANY error here is red immediately with no ledger to be added -// to. If this package ever acquires residue that cannot be fixed in its own PR, -// that is the moment to wire `scripts/check-test-typecheck.mts` — not before. +// to. +// +// ⚠️ THE LAST SENTENCE OF THAT PARAGRAPH USED TO READ "if this package ever +// acquires residue that cannot be fixed in its own PR, that is the moment to +// wire `scripts/check-test-typecheck.mts` — not before". #14062 SUPERSEDED it, +// and the reason is not this package: the director ruling of 2026-09-01 +// (maintainer verbatim: 「同意」) onboarded all fourteen `packages/plugins/**` +// packages into the `check:test-typecheck` instrument family AS A FAMILY, +// because an instrument that is silent over a third of the runtime surface +// reads as covering it. So `typecheck` now names the SHARED gate rather than +// invoking tsc directly, and the ledger judgement above is UNCHANGED and still +// this package's own: there is still no `test-typecheck-debt.json` here, and +// `check:test-typecheck` reads a missing ledger as `{ entries: {} }` — under +// which any error in any file here is red immediately, with no entry to be +// added to. Same strength, one instrument. The `gen:test-typecheck-debt` +// script is deliberately NOT wired for the same reason it was not before: at +// zero residue it would only ever write an empty ledger, and adding a real one +// is maintainer-only (#5286), exactly as the gate says when it refuses. { "extends": "./tsconfig.json", "compilerOptions": { diff --git a/packages/plugins/plugin-sharing/package.json b/packages/plugins/plugin-sharing/package.json index 8fd0d866f9..95f5911a35 100644 --- a/packages/plugins/plugin-sharing/package.json +++ b/packages/plugins/plugin-sharing/package.json @@ -15,7 +15,9 @@ "scripts": { "build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs", "test": "vitest run --passWithNoTests", - "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json" + "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-sharing --project tsconfig.test.json", + "gen:test-typecheck-debt": "tsx ../../../scripts/check-test-typecheck.mts --update --package packages/plugins/plugin-sharing --project tsconfig.test.json" }, "dependencies": { "@objectstack/core": "workspace:*", @@ -30,6 +32,7 @@ "@objectstack/driver-sql": "workspace:*", "@types/node": "^26.2.0", "better-sqlite3": "^13.0.3", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/plugin-sharing/test-typecheck-debt.json b/packages/plugins/plugin-sharing/test-typecheck-debt.json new file mode 100644 index 0000000000..6d46319524 --- /dev/null +++ b/packages/plugins/plugin-sharing/test-typecheck-debt.json @@ -0,0 +1,13 @@ +{ + "_comment": "Per-file tsc error debt of the @objectstack/plugin-sharing TEST layer (#5286). `tsconfig.test.json` compiles `src/**/*.test.ts` — which `tsconfig.json` excludes and therefore no gate ever read — and every file below still carries errors from before that gate existed. THIS FIELD IS GENERATED: every regeneration rewrites it from scripts/check-test-typecheck.mts, and the EXACT ratchet below requires a regeneration on every repair — so an edit made here is gone by the next one. Anything true of THIS package goes in the sibling `_note` field, which is authored, is preserved verbatim, and is never written by the generator (#12624). This comment states NO cause for the errors, deliberately: the classes differ per package and per file, they move as the debt is paid down, and a cause written here is rewritten verbatim into every ledger by every regeneration — so it outlives its own repair and cannot be corrected in the file where it is read. Measure instead, before repairing anything: `tsc --noEmit --pretty false -p tsconfig.test.json` in the package prints the real classes with their TS codes. Each entry maps a file to its per-SIGNATURE error counts, never to a bare total (#13470): a signature is the TS code plus the diagnostic message with structural type blobs collapsed, and it carries NO line or column — so the pin survives edits that move code around, and only stops matching when the error itself becomes a different error. EXACT ratchet, judged by re-running tsc: a file that gains errors is red, a file that loses them is red until its number is re-recorded, a file that reaches zero is red until its entry is deleted, a signature that ARRIVES or VANISHES is red even when the file total is unchanged, and a file NOT listed here may have no errors at all. Regenerate with: pnpm --filter @objectstack/plugin-sharing gen:test-typecheck-debt", + "_note": "STARTING LEDGER, opened by #14062 under the director ruling of 2026-09-01 (maintainer verbatim: 「同意」), which carries the #5286 maintainer authority for it. 3 errors over 2 files, every one PRE-EXISTING — the build config's `exclude` named `**/*.test.ts`, so none of this package's 30 test files reached a tsc program its `typecheck` runs. ⚠️ The residue is small enough to look like something this PR should simply have fixed; it was ledgered instead because the ruling onboards the family UNIFORMLY and states that repair follows the ratchet's own shrink-only discipline rather than riding along with the instrument that first sees it. Three entries is a cheap paydown card, and the ratchet reddens if anyone re-records them upward instead.", + "entries": { + "src/position-graph.test.ts": { + "TS6133: 'options' is declared but its value is never read.": 1 + }, + "src/sharing-rule.test.ts": { + "TS18048: 'foreign' is possibly 'undefined'.": 1, + "TS6133: 'r' is declared but its value is never read.": 1 + } + } +} diff --git a/packages/plugins/plugin-sharing/tsconfig.test.json b/packages/plugins/plugin-sharing/tsconfig.test.json new file mode 100644 index 0000000000..0f7c7502c4 --- /dev/null +++ b/packages/plugins/plugin-sharing/tsconfig.test.json @@ -0,0 +1,74 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 488 +// own `src/**/*.test.ts` in it 30 +// errors under BUILD semantics 3 +// errors under THIS config 3 +// +// The two readings agree, so this package carried no config-tier pile at all. +// +// BEFORE THIS FILE: the build config's `exclude` NAMED `**/*.test.ts`, so +// none of the 30 test files here reached any tsc program the `typecheck` +// script runs. The two `.pin.ts` files (`exec-context-annotation.pin.ts`, +// `logger-required-warn.pin.ts`) do NOT match that pattern and were already +// in the build program — their directives were live before this file +// (#14062). +// +// The 3 residual error(s) are PRE-EXISTING — this change edits no test file, and +// every one of them would have been reported on `origin/main` had this program always +// existed. They are ledgered per file in `test-typecheck-debt.json` beside this config, +// EXACT and shrink-only: a file that gains an error is red, one that loses an error is +// red until re-recorded, one that reaches zero is red until its entry is deleted, a +// signature that ARRIVES or VANISHES is red even at an unchanged file total, and a file +// NOT listed there may have no errors at all. ⛔ The ruling is explicit that this PR +// does not REPAIR them — it makes the ratchet able to see them; paydown follows the +// ratchet's own shrink-only discipline, on its own cards. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/plugins/plugin-webhooks/package.json b/packages/plugins/plugin-webhooks/package.json index ecb90ce9a7..102e279b23 100644 --- a/packages/plugins/plugin-webhooks/package.json +++ b/packages/plugins/plugin-webhooks/package.json @@ -31,7 +31,8 @@ "scripts": { "build": "tsup && node ../../../scripts/check-dts-emitted.mjs", "test": "vitest run", - "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json" + "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json && pnpm check:test-typecheck", + "check:test-typecheck": "tsx ../../../scripts/check-test-typecheck.mts --self-test && tsx ../../../scripts/check-test-typecheck.mts --package packages/plugins/plugin-webhooks --project tsconfig.test.json" }, "dependencies": { "@objectstack/core": "workspace:*", @@ -43,6 +44,7 @@ "@objectstack/metadata-core": "workspace:*", "@objectstack/objectql": "workspace:*", "@types/node": "^26.2.0", + "tsx": "^4.23.12", "typescript": "^6.0.3", "vitest": "^4.1.10" }, diff --git a/packages/plugins/plugin-webhooks/tsconfig.test.json b/packages/plugins/plugin-webhooks/tsconfig.test.json new file mode 100644 index 0000000000..1a65321de4 --- /dev/null +++ b/packages/plugins/plugin-webhooks/tsconfig.test.json @@ -0,0 +1,70 @@ +// The TEST-layer type-check program (#14062 — the `packages/plugins/**` family +// adopting the mechanism #5286 set for `packages/spec`, #5449 generalised, +// #12542 carried to `packages/rest` and #13176 to `packages/plugins/ +// plugin-security`). `tsconfig.json` beside this one stays exactly as it is: it +// is the BUILD config. This sibling puts the test layer in front of tsc under +// the module semantics vitest really executes it with, and `package.json`'s +// `typecheck` script NAMES it (via `check:test-typecheck --project`), because a +// config no script invokes is exactly the phantom this whole change is about. +// +// The family was onboarded as a family by the director ruling of 2026-09-01 on +// #14062 (maintainer verbatim: 「同意」), which also carries the #5286 +// maintainer authority for the starting ledgers. The reason it is a family and +// not one package: the ledger's shrink-only guarantee said NOTHING about a +// third of the repo's runtime surface, and a guarantee with a silent hole is +// worse than a narrower one honestly drawn, because readers generalise it. +// +// What differs from the build config, and what deliberately does NOT: +// - MODULE SEMANTICS ONLY, plus `lib`. The tests are written and executed as +// ESM by vitest (esbuild/vite). Matching that is FIDELITY, not laxity: it is the +// same subtraction `packages/spec`, `packages/rest` and `plugin-security` +// each made, and it removes a config-tier error pile that says nothing +// about the tests. +// - ⛔ STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, +// `noUnusedParameters`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, +// `rootDir`, `paths` and `types` are all INHERITED from `tsconfig.json` +// (and through it the root config), and none of them is re-declared here. +// ⚠️ A child that declared its own `paths` would REPLACE the parent map +// rather than merge into it, silently sending a source-resolved specifier +// back to `dist/` — a BUILD ARTIFACT — so this file declares none. +// Nothing here may loosen a type rule; if a test does not compile, that is +// the finding. +// +// - `lib: ["ES2022"]`, for the same reason `packages/rest` states: the root +// config's `lib` is ES2020 and vitest runs on a Node that has es2022 +// builtins, so the gap is reported as TS2550 about the CHECK. No `DOM`: +// nothing in this layer touches a browser global. +// +// MEASURED at e80889095, workspace closure built first (`tsc --noEmit --pretty false +// --listFiles -p tsconfig.test.json`, and the same command without `--listFiles`): +// +// files in this program 433 +// own `src/**/*.test.ts` in it 11 +// errors under BUILD semantics 0 +// errors under THIS config 0 +// +// The two readings agree, so this package carried no config-tier pile at all. +// +// BEFORE THIS FILE: the build config does NOT exclude tests, so `tsc +// --noEmit` already read all 11. This program is the family's uniform +// instrument over the same files, not a new reader of them. +// +// There is NO `test-typecheck-debt.json` beside this config, and its ABSENCE is the +// zero: `check:test-typecheck` reads a missing ledger as `{ entries: {} }`, under which +// ANY error in ANY file here is red immediately, with no entry to be added to. That is +// strictly stronger than a ledger holding nothing, and it is the same call +// `plugin-security` recorded for itself in #13176. If this package ever acquires +// residue that cannot be fixed in the PR that causes it, THAT is when a ledger and a +// `gen:test-typecheck-debt` script are owed — and adding one is maintainer-only +// (#5286), exactly as the gate says when it refuses. +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true, + "module": "esnext", + "moduleResolution": "bundler", + "lib": ["ES2022"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3a146440b1..bbcbaf470d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1387,6 +1387,9 @@ importers: '@types/node': specifier: ^26.2.0 version: 26.2.0 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1409,6 +1412,9 @@ importers: '@types/node': specifier: ^26.2.0 version: 26.2.0 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1431,6 +1437,9 @@ importers: '@types/node': specifier: ^26.2.0 version: 26.2.0 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1477,6 +1486,9 @@ importers: '@types/node': specifier: ^26.2.0 version: 26.2.0 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1505,6 +1517,9 @@ importers: '@types/node': specifier: ^26.2.0 version: 26.2.0 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1569,6 +1584,9 @@ importers: hono: specifier: ^4.12.34 version: 4.13.2 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1627,6 +1645,9 @@ importers: '@types/node': specifier: ^26.2.0 version: 26.2.0 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1667,6 +1688,9 @@ importers: '@types/nodemailer': specifier: ^8.0.1 version: 8.0.1 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1698,6 +1722,9 @@ importers: '@types/node': specifier: ^26.2.0 version: 26.2.0 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1723,6 +1750,9 @@ importers: '@types/node': specifier: ^26.2.0 version: 26.2.0 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1754,6 +1784,9 @@ importers: '@types/node': specifier: ^26.2.0 version: 26.2.0 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1800,6 +1833,9 @@ importers: '@types/node': specifier: ^26.2.0 version: 26.2.0 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1840,6 +1876,9 @@ importers: better-sqlite3: specifier: ^13.0.3 version: 13.0.3 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -1871,6 +1910,9 @@ importers: '@types/node': specifier: ^26.2.0 version: 26.2.0 + tsx: + specifier: ^4.23.12 + version: 4.23.12 typescript: specifier: ^6.0.3 version: 6.0.3 diff --git a/scripts/check-type-check-coverage.mjs b/scripts/check-type-check-coverage.mjs index df3b0f68f4..30342a2941 100644 --- a/scripts/check-type-check-coverage.mjs +++ b/scripts/check-type-check-coverage.mjs @@ -658,10 +658,6 @@ const DEBT = { errors: 3, note: 'all code-tier (TS2769/TS18046).', }, - '@objectstack/knowledge-ragflow': { - errors: 4, - note: 'code-tier 3 (TS2353) + 1 config-tier (TS2550 lib).', - }, '@objectstack/metadata': { errors: 89, note: 'code-tier 30 (TS2345 x30); config-tier 25 (TS2835 x25); noise 34 (TS7006 x33, TS6133). ' @@ -911,33 +907,31 @@ const EXEMPT = { // the graduation message no longer offers the exclusion route without its // precondition. Re-measure before relying on the split: it moves with every // import a test file gains. +// +// ── #14062: three plugin entries GRADUATED, and what replaced them ─────────── +// +// `plugin-approvals` (345), `plugin-auth` (94) and `plugin-sharing` (3) left +// this ledger on 2026-09-02, and `knowledge-ragflow` (4) left DEBT above in the +// same change. ⛔ None of them was PAID DOWN — read that first, because a +// deleted debt entry normally means the errors are gone and here it does not. +// +// The director ruling of 2026-09-01 on #14062 (maintainer verbatim: 「同意」) +// onboarded all fourteen `packages/plugins/**` packages into the +// `check:test-typecheck` instrument: each has a `tsconfig.test.json` its +// `typecheck` script NAMES, so `hidesTests` is false for all of them and this +// gate's per-PACKAGE approximation of the debt has nothing left to approximate. +// The same errors are now held one level finer, per FILE and per SIGNATURE, in +// each package's own `test-typecheck-debt.json` — 324 / 94 / 3 / 3 respectively +// (approvals reads 324 rather than 345 because the test program uses vitest's +// module semantics, which subtracts 21 config-tier diagnostics that were never +// about the tests). That is the graduation this ledger's own message asks for: +// "the repair is the same one spec took -- put the file in a tsc program", and +// the entry goes when the program exists, not when the number reaches zero. +// +// So the shrink-only guarantee did not loosen here; it moved to a strictly +// sharper instrument, one that also reddens on a wholesale substitution of +// error IDENTITY at a constant total, which a per-package integer cannot see. const TEST_DEBT = { - '@objectstack/plugin-approvals': { - errors: 345, - note: 'TS2339 x296, TS2550 x20, TS2345 x16, TS18048 x10, plus 5 singletons (TS2554 x2, TS1470, ' - + 'TS2352, TS6133). LOWERED 347 -> 345 at ead731756 (#12723), in a sweep that re-measured all 31 ' - + 'ledger entries at once and found 4 of them carrying slack. The tally above was taken at 347 and ' - + 'is NOT re-tallied here: that sweep measured per-entry TOTALS only, so the -2 is unattributed, ' - + 'and an admitted gap beats an invented composition. ' - + 'Lowered 348 -> 347 at 0e0bf8049 (#11497): tsc against that tree reports the ' - + 'same seven codes at the same counts as the prior 348 composition, TO THE UNIT, minus the sole ' - + 'TS2353 -- a fully attributable single-error retirement, not a rescale. ' - + 'Was 547 (re-measured at 5ab08428, up from 467; TS2345 x213 then). ' - + 'Lowered 547 -> 348 at b5e09b21 (#7888), and the -199 is ONE CLASS COLLAPSING rather than a ' - + 'measured surface shrinking -- the distinction the surplus finding asked to be settled before a ' - + 'gap this size was written in as a floor. Three readings say collapse: (a) TS2339 x296, TS2550 ' - + 'x20 and TS18048 x10 are unchanged TO THE UNIT against the 547 composition and only TS2345 moved, ' - + '213 -> 16 -- a program that had DEGRADED instead (an unresolved import turning a type into any) ' - + 'would have wiped the 296 property errors first, since property access on any is legal; (b) all ' - + '21 test files are on disk and all 21 are in the program (tsc --listFiles), none deleted, and the ' - + 'package\'s other test files gained 406 lines and lost 204 over the window -- the set grew; (c) ' - + 'src/approval-service.test.ts, which holds 273 of the 348 as it held 443 of the 547, is ' - + 'BYTE-IDENTICAL between 5ab08428 and b5e09b21 (blob 3fc272f, 3335 lines both ends). Same bytes, ' - + '170 fewer errors, so the repair landed in a producer\'s types and no assertion was deleted to ' - + 'get it. The 16 TS2345 that survive are still reported against a fully-resolved approver-config ' - + 'union, so that parameter type is still strict -- the 197 that went were repaired, not loosened ' - + 'away. Still entirely test-only (src is clean), so nothing but this ledger has ever seen it.', - }, '@objectstack/runtime': { errors: 206, note: 'TS18048 x91 (possibly-undefined), TS18046 x27, TS2339 x17, TS2493 x15, TS2835 x13, TS2345 x10, ' @@ -997,67 +991,6 @@ const TEST_DEBT = { + 'RECORDED EXACTLY, no bootstrap margin: this layer has never been gated, so the first new error in ' + 'it should go red rather than be absorbed.', }, - '@objectstack/plugin-auth': { - errors: 94, - note: 'LOWERED 97 -> 94 at ead731756 (#12723), in a sweep that re-measured all 31 ledger entries at ' - + 'once. Everything below -- the tally, the per-file split, the 97 they sum to -- was taken at 97 ' - + 'and is NOT re-tallied here: that sweep measured per-entry TOTALS only, so the -3 is unattributed. ' - + 'RE-TALLIED from tsc at the 97 below (#10615), measured at cea8c7d867 with the workspace closure ' - + 'built by the same command lint.yml runs before this gate, so the composition, the per-file split ' - + 'and the total are ONE measurement rather than a rescale: TS2493 x36 (tuple index out of range), ' - + 'TS18048 x24, TS2322 x11, TS2532 x9, TS2345 x4, TS2339 x3, TS2554 x3, TS2741 x3, TS7006 x2, ' - + 'TS2769 x1, TS6133 x1 = 97, the number recorded at THAT time EXACTLY. The per-file split is ' - + 'COMPLETE at this measurement rather than a top-four: ' - + '43 in src/auth-manager.test.ts, 18 in src/admin-user-endpoints.test.ts, 12 in ' - + 'src/auth-plugin.test.ts, 11 in src/admin-import-users.test.ts, 3 each in ' - + 'src/objectql-adapter.test.ts and src/sso-client-secret-at-rest.test.ts, 2 each in ' - + 'src/auth-manager.jwt-eddsa-fallback.test.ts and src/reconcile-membership.test.ts, 1 each in ' - + 'src/better-auth-schema-parity.test.ts, src/last-admin-guard.test.ts and ' - + 'src/oauth-provider-schema-parity.test.ts -- 11 files, summing to 97. ' - + 'LOWERED 109 -> 97 here, and the -12 was MEASURED rather than subtracted, which is the whole point ' - + 'of the card: it was filed naming a surplus of 11 (a 98) off PR #10614\'s head, a later sweep at ' - + '3c6028f1b2 reported the surplus as 12, and 109 - 11 = 98 was the cheap wrong answer that looks ' - + 'right. Cross-tabbing the recorded measurement against this one by file AND code attributes all 12: ' - + '11 sit in ONE file, src/admin-import-users.test.ts (TS2339 5 -> 0, TS2493 13 -> 7), which is ' - + '#10614 giving two engine doubles real typed parameters -- a zero-parameter mock has a zero-length ' - + 'parameter tuple, so every call site reading `.mock.calls[0][1]` was a TS2493 and every ' - + '`options?.where` off it a TS2339. The 12th is one TS2345 that left ' - + 'src/auth-manager.test.ts(4086,46) after that PR (a vi.fn callback whose parameter tuple did not ' - + 'match its consumer), over three commits that rewrote 204 lines of that file, and it is NOT ' - + 'attributed further rather than guessed. ' - + 'CORRECTION, recorded because re-deriving the whole split is what caught it: the card predicted ' - + 'src/admin-import-users.test.ts AND src/admin-user-endpoints.test.ts as "exactly the two files ' - + 'that moved". admin-user-endpoints holds 18 at BOTH ends and did not move at all. Patching the two ' - + 'numbers a reader believes changed would have written a plausible and wrong split over a correct ' - + 'total -- the one failure this ledger cannot see, since nothing but prose records a split. ' - + 'ANCHOR, re-established BEFORE re-tallying rather than assumed: d5e7b9f5a1, the ref the 109 was ' - + 'measured on, still measures 109 today -- and not only in total, which is what makes it an anchor ' - + 'rather than a coincidence: the composition reproduces class for class (TS2493 x42, TS18048 x24, ' - + 'TS2322 x11, TS2532 x9, TS2339 x8, TS2345 x5, TS2554 x3, TS2741 x3, TS7006 x2, TS2769 x1, ' - + 'TS6133 x1) and the per-file split reproduces the 44/22/18/12 this note used to record. So the ' - + 'measuring stick did not drift under the entry and 97 is comparable to 109. Worth the check: this ' - + 'gate grew +1752/-81 over the same window and the re-measure path itself DID move -- ' - + '`measureTestDebt` now asks `tscErrorCount` to drop TS6059 (#10779) and the `include` roots moved ' - + 'into `includeRoot` (#10876) -- but neither reaches this package, whose output carries no TS6059 ' - + 'and whose `include` root reads the same under an expression that is the old inline one verbatim. ' - + 'NOT a graduation: 97 is not 0, so this entry stays and the package typecheck script is unchanged. ' - + 'History, still true: measured 124 -> 129 (5ab08428, composition unchanged in shape) -> 131 ' - + '(e8db1a230). Lowered 131 -> 111 at b16dcb45 (#7888); the intermediate 108 in that PR\'s first ' - + 'commit was measured at b5e09b21 and was already stale when the merge queue built it -- the ' - + 'package took +3 inside the hour, the same "a ledger number is a number about a moment" race that ' - + 'kicked #5278 three times, so 111 was the merge-queue run\'s own re-measure on the ref that PR ' - + 'actually landed on. Of the +2 that had made 131, half is a TS2554 in src/last-admin-guard.test.ts, ' - + 'a file added by #5941 / PR #5993 (the break-glass delete guard); the other 1 landed in a file that ' - + 'already existed and is not attributed further. Then 111 -> 110 in PR #10013 -- the number moved ' - + 'and the note did not, which is how a composition written at 131 was still sitting over an entry ' - + 'reading 110 -- and 110 -> 109 (#9694), where src/managed-extension-fields.test.ts stopped seeding ' - + 'from `import.meta.url` (a meta-property module: NodeNext forbids in this CJS-typed package) and ' - + 'now seeds from `__dirname`, which type-checks here AND is a spelling ' - + 'check:cross-package-test-inputs resolves -- that gate publishes the current set verbatim in its ' - + 'failure text, deliberately not restated as a count here because a count drifts silently (widened ' - + 'twice, #8995 and #9763) -- so that file\'s repo-wide *.object.ts walk stays visible to the gate ' - + 'holding plugin-auth\'s declared input radius. It contributes nothing to this pile any more.', - }, '@objectstack/mcp': { errors: 53, note: 'TS18046 x51 -- `json` is of type unknown, one `await res.json()` idiom repeated across four ' @@ -1174,7 +1107,6 @@ const TEST_DEBT = { + 'not because anything was suppressed.', }, '@objectstack/platform-objects': { errors: 3, note: 'TS2339 x2, TS7006 x1. Re-measured 3 at 5ab08428, exact.' }, - '@objectstack/plugin-sharing': { errors: 3, note: 'TS6133 x2, TS18048 x1. Re-measured 3 at 5ab08428, exact.' }, '@objectstack/service-sms': { errors: 1, note: 'TS2493 x1, in transports.test.ts. Re-measured 1 at 5ab08428 and still 1 at e8db1a230, after two more hidden test files: #5773 added sms-manifest-providers.contract.test.ts and #2814 / PR #6042 added sms-daily-quota.test.ts. The file count moved twice while the error count did not -- both new files are type-clean with the exclusion lifted.' }, '@objectstack/connector-rest': { errors: 1, note: 'TS6133 x1. Re-measured 1 at 5ab08428, exact.' }, }; diff --git a/scripts/check-type-source-resolution.mjs b/scripts/check-type-source-resolution.mjs index 58b961eee5..60d8a4dd5a 100644 --- a/scripts/check-type-source-resolution.mjs +++ b/scripts/check-type-source-resolution.mjs @@ -336,15 +336,72 @@ const KNOWN_DIST_RESOLVED_TYPE_IMPORTS = { '@objectstack/metadata-protocol', '@objectstack/spec', '@objectstack/types', ], '@objectstack/platform-objects': ['@objectstack/metadata-core', '@objectstack/spec'], + // ── #14062 re-baseline, on the onboarding limb above ───────────────────── + // + // The director ruling of 2026-09-01 on #14062 (maintainer verbatim: 「同意」) + // onboarded all fourteen `packages/plugins/**` packages into the + // `check:test-typecheck` instrument, so thirteen packages' `typecheck` + // scripts began naming a `tsconfig.test.json` they had never named before + // (`plugin-security` already did, from #13176). That MOVES THE PROGRAM SET, + // which #11490 made a package's prerogative and which this doc-block's + // onboarding limb is exactly about. + // + // Condition 1 — every dep admitted below is annotated `via tsconfig.test.json` + // by this gate's own failure text, i.e. reached ONLY through the program this + // change onboarded. Not one of them is newly reached through a program that + // was already counted, and nothing here launders such a case. + // + // Condition 2 — the numbers, `--list` on the same checkout with the workspace + // closure built, taken at this branch's merge base (`79b6a22a5`) and on the + // branch: + // + // before 98 programs / 77 packages, 54 entries, 242 package-dep pairs + // after 111 programs / 77 packages, 55 entries, 269 package-dep pairs + // + // so +13 programs (the thirteen new `tsconfig.test.json`), +1 entry + // (`plugin-dev`, which had none) and +27 pairs — the ones marked below and + // nothing else. The other nine onboarded packages add ZERO pairs: their test + // files import no workspace dep their `tsconfig.json` did not already reach. + // + // ⚠️ The program total moves under this branch for reasons that are NOT this + // change: measured against the earlier base `f7d92d364` the same pair read + // 96 -> 109, because `#13284` landed two `tsconfig.typecheck.json` on `main` + // in between. The DELTA is the invariant to read here (+13 programs, +1 + // entry, +27 pairs) — an absolute taken at one moment is a number about that + // moment, and re-deriving it after any merge is what keeps it honest. + // + // Condition 3 — reviewed as a re-baseline. `paths` is not the tool here, by + // the doc-block's own measurement on PR #12570 rather than by preference. + // [#14062] The five deps after `@objectstack/core` arrive from + // `tsconfig.test.json`: 35 test files that NO tsc program compiled (the build + // config's `exclude` named `**/*.test.ts`), carrying 324 measured errors. '@objectstack/plugin-approvals': [ '@objectstack/core', '@objectstack/formula', '@objectstack/spec', '@objectstack/types', + '@objectstack/driver-sql', '@objectstack/metadata-protocol', '@objectstack/objectql', + '@objectstack/service-automation', '@objectstack/trigger-record-change', ], '@objectstack/plugin-audit': ['@objectstack/core', '@objectstack/objectql', '@objectstack/spec'], // #11490 re-baseline: `@objectstack/plugin-hono-server` arrives from // `tsconfig.examples.json`. + // [#14062] The three deps after `@objectstack/types` arrive from + // `tsconfig.test.json`: 87 test files that NO tsc program compiled (the build + // config's `exclude` named `**/*.test.ts`), carrying 94 measured errors. '@objectstack/plugin-auth': [ '@objectstack/core', '@objectstack/platform-objects', '@objectstack/plugin-hono-server', '@objectstack/rest', '@objectstack/spec', '@objectstack/types', + '@objectstack/driver-sql', '@objectstack/objectql', '@objectstack/plugin-security', + ], + // [#14062] A NEW entry, and the only one this re-baseline adds. Every dep + // arrives from `tsconfig.test.json`; this package's `tsconfig.json` reaches no + // workspace dependency through `dist/` at all, which is why it had no entry. + // Its 6 test files measure ZERO errors, so it carries no debt ledger — this + // registry records reachability, never debt, and the two are independent. + '@objectstack/plugin-dev': [ + '@objectstack/core', '@objectstack/driver-memory', '@objectstack/objectql', + '@objectstack/plugin-auth', '@objectstack/plugin-hono-server', '@objectstack/plugin-security', + '@objectstack/rest', '@objectstack/runtime', '@objectstack/service-i18n', + '@objectstack/service-realtime', '@objectstack/service-storage', '@objectstack/spec', + '@objectstack/types', ], '@objectstack/plugin-email': [ '@objectstack/core', '@objectstack/formula', '@objectstack/objectql', '@objectstack/platform-objects', @@ -384,10 +441,24 @@ const KNOWN_DIST_RESOLVED_TYPE_IMPORTS = { '@objectstack/spec', ], // #11490 re-baseline: a NEW entry — reached only through `tsconfig.scripts.json`. - '@objectstack/plugin-webhooks': ['@objectstack/spec'], + // [#14062] The five after `@objectstack/spec` arrive from `tsconfig.test.json`. + // ⚠️ Note the shape here, which differs from approvals/auth/sharing: this + // package's build config never excluded its tests, so `tsc --noEmit` already + // compiled all 11 of them (measured: 0 errors). What was missing was not a + // compile but this gate's SIGHT of it — the program set moved, and these five + // deps were always reached, by a program nobody had named. + '@objectstack/plugin-webhooks': [ + '@objectstack/spec', + '@objectstack/core', '@objectstack/metadata-core', '@objectstack/objectql', + '@objectstack/platform-objects', '@objectstack/service-messaging', + ], + // [#14062] `@objectstack/driver-sql` arrives from `tsconfig.test.json`: 30 test + // files that NO tsc program compiled (the build config's `exclude` named + // `**/*.test.ts`), carrying 3 measured errors. '@objectstack/plugin-sharing': [ '@objectstack/core', '@objectstack/formula', '@objectstack/metadata-core', '@objectstack/objectql', '@objectstack/platform-objects', '@objectstack/spec', '@objectstack/types', + '@objectstack/driver-sql', ], // #12542: `packages/rest` had NO tsc program compiling any of its 149 test // files, and its new `tsconfig.test.json` (the #5286 sibling route) is the diff --git a/scripts/regen-artifacts.mjs b/scripts/regen-artifacts.mjs index eec9583ce3..e15667d1b0 100644 --- a/scripts/regen-artifacts.mjs +++ b/scripts/regen-artifacts.mjs @@ -469,6 +469,59 @@ export const NOT_DRIVER_MANAGED = Object.freeze([ + 'then, never a bound, and the per-(owner, script) key is exactly what lets a fourth one ' + 'arrive needing nothing but this row.', }, + // ── #14062: the `packages/plugins/**` family's starting ledgers ────────────── + // + // The director ruling of 2026-09-01 (maintainer verbatim: 「同意」) onboarded all + // fourteen plugin packages into the `check:test-typecheck` instrument family. Four + // of them measured non-zero and therefore carry a ledger and a + // `gen:test-typecheck-debt` script; the other ten measured ZERO and deliberately + // have NEITHER, because at zero residue a ledger holds nothing while a MISSING one + // is read by the gate as `{ entries: {} }` — under which any error is red + // immediately, with no entry to be added to. That is why this block adds four rows + // and not fourteen: `reconcileGenerators`'s population is the manifest SCRIPTS, so + // a package that defines no generator needs no disposition, and inventing one would + // record a decision about a file that does not exist. + { + path: 'packages/plugins/plugin-approvals/test-typecheck-debt.json', + gen: 'gen:test-typecheck-debt', + owner: '@objectstack/plugin-approvals', + why: + 'a SHRINK-ONLY ratchet — see `packages/client/test-typecheck-debt.json` above; same ' + + 'generator, same per-package ledger, same reason a merge must never recompute it: the ' + + 'half-merged tree is not the tree whose type errors this file records, so a file that ' + + 'GAINED errors would enter the ledger as merge noise instead of as red. This is also the ' + + 'largest of them (324 errors over 8 files), which makes the merge-noise route the most ' + + 'attractive and the most expensive one to take.', + }, + { + path: 'packages/plugins/plugin-auth/test-typecheck-debt.json', + gen: 'gen:test-typecheck-debt', + owner: '@objectstack/plugin-auth', + why: + 'a SHRINK-ONLY ratchet — see `packages/plugins/plugin-approvals/test-typecheck-debt.json` ' + + 'directly above; same generator, same per-package ledger, same reason a merge must never ' + + 'recompute it.', + }, + { + path: 'packages/plugins/plugin-sharing/test-typecheck-debt.json', + gen: 'gen:test-typecheck-debt', + owner: '@objectstack/plugin-sharing', + why: + 'a SHRINK-ONLY ratchet — see `packages/plugins/plugin-approvals/test-typecheck-debt.json` ' + + 'above; same generator, same per-package ledger, same reason a merge must never recompute ' + + 'it. Its residue is only 3 errors, and that makes it MORE exposed to the failure this row ' + + 'prevents rather than less: a recomputation on a half-merged tree can double a 3 without ' + + 'anyone noticing the number moved.', + }, + { + path: 'packages/plugins/knowledge-ragflow/test-typecheck-debt.json', + gen: 'gen:test-typecheck-debt', + owner: '@objectstack/knowledge-ragflow', + why: + 'a SHRINK-ONLY ratchet — see `packages/plugins/plugin-approvals/test-typecheck-debt.json` ' + + 'above; same generator, same per-package ledger, same reason a merge must never recompute ' + + 'it.', + }, { path: 'packages/sdui-parser/objectui-lockstep.json', gen: 'gen:sdui-lockstep',