Measured on origin/main at 1a540e82b while working #12970, in that card's own package. Filed unassigned, for triage.
What was measured
packages/plugins/plugin-security/tsconfig.json carries "exclude": ["dist", "node_modules", "**/*.test.ts"], and the package's sibling program tsconfig.scripts.json selects only scripts/**. So no tsc program in this package reads a single one of its test files, while package.json advertises "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json".
Measurement, not inference — tsc --noEmit --listFiles over the package's own tsconfig.json:
$ pnpm --filter @objectstack/plugin-security exec tsc --noEmit --listFiles | grep -c '\.test\.ts'
0
Zero. Not "my two files were missing" — no .test.ts file at all is in the program, against 89 test files carrying 1625 tests.
What is hiding there
Re-running the identical program with only **/*.test.ts dropped from exclude (a throwaway sibling config, nothing committed) surfaces 11 errors across 6 files:
5 src/explain-engine.test.ts
2 src/rls-pushdown-limits.test.ts
1 src/permission-set-projection.test.ts
1 src/objects/default-permission-sets.test.ts
1 src/authz-matrix-gate.test.ts
1 src/audience-anchor-set-claims.pin.test.ts
pnpm --filter @objectstack/plugin-security typecheck exits 0 over all of it, and so does pnpm check:type-check-coverage — the package declares a typecheck script, which is what that ratchet asks for.
Why this is the shape AGENTS.md names
AGENTS.md, "Build & Test", states the rule and the reason verbatim: "Never exclude *.test.ts / *.spec.ts from a package's tsconfig.json — tsc --noEmit reads that config, so the exclusion hides the tests from the very check the typecheck script advertises (a green gate over source nothing read)", and the paragraph after it names the consequence this package is exposed to: "A @ts-expect-error in a file no tsc program compiles is a phantom check". This is a security package whose suites pin refusal behaviour, so a compile-time pin that silently evaluates never is worth more here than in most places.
The prescribed repair is in the same section and does not require touching the build config: add a sibling tsconfig.test.json and name it in the typecheck script (the packages/spec pattern), with the residue recorded in the per-file, shrink-only test-typecheck-debt.json (pnpm --filter <package> gen:test-typecheck-debt, gate scripts/check-test-typecheck.mts --package <dir>). This package has no such ledger file and no gen:test-typecheck-debt script — it is simply not onboarded.
Relationship to existing cards — checked before filing
Not a duplicate of any of the three: none of them names plugin-security, and the 11 errors above are specific to it.
Out of scope of the card that found it
#12970 is a behaviour fix in two of this package's modules. Its own two test files were checked against the package's real strictness through the same throwaway config and are clean (0 of the 11 errors), so nothing about this blocks it.
Measured on
origin/mainat1a540e82bwhile working #12970, in that card's own package. Filed unassigned, for triage.What was measured
packages/plugins/plugin-security/tsconfig.jsoncarries"exclude": ["dist", "node_modules", "**/*.test.ts"], and the package's sibling programtsconfig.scripts.jsonselects onlyscripts/**. So no tsc program in this package reads a single one of its test files, whilepackage.jsonadvertises"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json".Measurement, not inference —
tsc --noEmit --listFilesover the package's owntsconfig.json:Zero. Not "my two files were missing" — no
.test.tsfile at all is in the program, against 89 test files carrying 1625 tests.What is hiding there
Re-running the identical program with only
**/*.test.tsdropped fromexclude(a throwaway sibling config, nothing committed) surfaces 11 errors across 6 files:pnpm --filter @objectstack/plugin-security typecheckexits 0 over all of it, and so doespnpm check:type-check-coverage— the package declares atypecheckscript, which is what that ratchet asks for.Why this is the shape AGENTS.md names
AGENTS.md, "Build & Test", states the rule and the reason verbatim: "Never
exclude*.test.ts/*.spec.tsfrom a package'stsconfig.json—tsc --noEmitreads that config, so the exclusion hides the tests from the very check thetypecheckscript advertises (a green gate over source nothing read)", and the paragraph after it names the consequence this package is exposed to: "A@ts-expect-errorin a file no tsc program compiles is a phantom check". This is a security package whose suites pin refusal behaviour, so a compile-time pin that silently evaluates never is worth more here than in most places.The prescribed repair is in the same section and does not require touching the build config: add a sibling
tsconfig.test.jsonand name it in thetypecheckscript (thepackages/specpattern), with the residue recorded in the per-file, shrink-onlytest-typecheck-debt.json(pnpm --filter <package> gen:test-typecheck-debt, gatescripts/check-test-typecheck.mts --package <dir>). This package has no such ledger file and nogen:test-typecheck-debtscript — it is simply not onboarded.Relationship to existing cards — checked before filing
typecheckand discoverable only by a full-closure build — ~9 minutes of a dev round, 19 packages in that state #12511 (open) is the umbrella: "A type error in a ledgered package's tests is invisible to its owntypecheck… 19 packages in that state". This is one of those packages, named and measured.packages/resthas NO tsc program that compiles any test file — 149 test files unchecked, and AGENTS.md names this exact shape as how a@ts-expect-errorbecomes a phantom check #12542 (closed) and@objectstack/service-analyticshas notypecheckscript — src and its 100+ in-src test files are tsc-checked by nothing, with 10 standing errors behind the unwired gate #12939 (open) are the same finding filed per-package forpackages/restand@objectstack/service-analytics. Per-package cards are the established treatment for this class, which is why this is filed rather than folded into [finding] A type error in a ledgered package's tests is invisible to its owntypecheckand discoverable only by a full-closure build — ~9 minutes of a dev round, 19 packages in that state #12511.Not a duplicate of any of the three: none of them names
plugin-security, and the 11 errors above are specific to it.Out of scope of the card that found it
#12970 is a behaviour fix in two of this package's modules. Its own two test files were checked against the package's real strictness through the same throwaway config and are clean (0 of the 11 errors), so nothing about this blocks it.