Files
civitai__civitai/tsconfig.tests.json
Zachary Lowden 69b5ce5497 fix(typecheck): typecheck scripts/ — 15 non-test files now covered, scripts/__tests__ excluded like src/ (#4189)
* fix(typecheck): close the scripts/ blind spot — 31 files now checked, 5 quarantined behind a ratchet

The root tsconfig named `scripts/local-dev/*.ts` in BOTH `include` and
`exclude`. Exclude wins, so nothing under `scripts/` was typechecked at all —
not even the one directory the include list appeared to name.

Measured on 23cecb57c0: `tsc -p tsconfig.json --listFilesOnly` contained 0
files under `scripts/`, and a deliberate `const x: number = 'nope'` planted in
`scripts/oneoffs/parse_header.ts` produced `OK — 0 type errors`, exit 0. Both
CI tiers run that config, so the gap could not close on its own.

Adding `scripts/**/*.ts(x)` puts 36 files in the program and surfaces 198
pre-existing errors, all in 5 files. The other 31 are clean and are checked
from now on by the real `pnpm typecheck` in both tiers, as is every file added
under `scripts/` later.

The 5 are excluded BY NAME — enumerable, and shrinkable in a reviewable diff —
and are NOT left unchecked: `tsconfig.scripts.json` is the root config without
those entries, and `scripts/ci/typecheck-scripts-gate.mjs` ratchets their
per-file counts. Excluding them and walking away would recreate the very
defect being fixed.

164 of the 198 are one file with one cause: it imports an untyped `.mjs` with
no JSDoc, so under `allowJs` tsc infers `request({ worktree, args = [] } = {})`
as `{ args?: never[] }` (40x TS2353) and the run object's `null` initializers
as type `null` (123x TS18047/TS2531). Not 164 defects; typing that module is
the fix and is left to a follow-up.

The gate mirrors `typecheck-tests-gate.mjs` and IMPORTS its five controls
rather than copying them (`classifyEmptyAllowance` gains an `envName`/
`gateScript` parameter, defaulted, so both gates report their own). What is
genuinely different lives in `typecheck-scripts-compare.mjs`: the positive
control anchors at the repo root instead of matching the substring `/scripts/`,
because this repo pulls `.claude/skills/**/scripts/*.mjs` into the program
transitively and every vendored package has a `scripts/` directory — a
substring control could stay green with the whole measured tree gone.

`tsconfig.tests.json` is updated in step: the sibling gate's config-drift
control caught the base-exclude change immediately and refused to run, which
is the control working.

Verification
- positive control: planted error in scripts/oneoffs/ -> 1 error, exit 2 under
  the new config; the SAME error under main's config -> "OK — 0 type errors",
  exit 0.
- ratchet proven both ways against the real tsc: worsening gen_seed 2->3
  BLOCKS (exit 1, names the delta); clearing it PASSES (exit 0, "1 file(s) now
  clean").
- 42 new tests; 10 mutants (one per control) each killed by their specifically
  named test, with an unmutated green control on both ends of the battery.
- root `pnpm typecheck`: 0 errors. Both gate suites: 189 passed.

Known-unrelated: the sibling tests gate is already BLOCKED on main (869/160 vs
its 784/140 baseline) — verified identical at the base ref, not caused here,
and it is not wired into CI.

* fix(typecheck): exclude scripts/__tests__ from the root program; gate becomes a report, not a CI block

#4181 landed scripts/__tests__/dev-server-daemon-port.test.ts and turned both
the root typecheck and this PR's gate red. Reproduced locally on the merged
head: 4 errors, all in that one new file, all TS2345 "not assignable to
parameter of type 'ProcessEnv'".

The gate was working as designed. The design was wrong.

Root cause, read at the source rather than inferred: scripts/__tests__ exists
to test the untyped `.mjs` modules under .claude/skills and .claude/hooks by
importing them. None carries JSDoc, so under `allowJs` tsc infers their
signatures from the implementation and every caller inherits the result.
`daemonPortsGuarded(env = process.env)` infers as requiring a full ProcessEnv,
so `{ DEV_DAEMON_PORT: '9555' }` is an error. It is the same mechanism as the
164 errors already recorded for dev-server-test-queue.test.ts.

That makes the failure systemic, not a backlog: 5 of the 15 files there carry
this class, and ALL 15 were added within one month. Quarantining files
one-by-one would have fired several times a month, always for a defect in a
dependency the test author did not write, and the fastest remedy would have
been to add another exclude line — training the reflex the quarantine existed
to prevent.

So scripts/__tests__/** is now excluded as a DIRECTORY, exactly as
src/**/__tests__/** already is, and the gate is no longer wired into CI. Its
CI job is removed; .github/workflows/lint.yml is byte-identical to main again.

What this costs, stated plainly: scripts/__tests__/** is UNCHECKED. That is the
pre-existing state, not a regression, and it is measured rather than hidden —
tsconfig.scripts.json re-includes it and the gate reports per-file counts on
demand (202 across 6 files).

What it still buys, measured by --listFilesOnly rather than asserted: 15
non-test files under scripts/ (oneoffs 6, local-dev 3, test-perf 2, root 2,
metric-migration 2) go from unchecked to checked by the real `pnpm typecheck`
in BOTH tiers, along with any file added to those directories later. The
earlier claim of "31" was wrong — it counted scripts/__tests__ files and
transitively-imported .mjs.

gen_seed.ts stays excluded by name: its 2 errors are a genuinely broken import
(`~/server/db/notifDb`, deleted in 927e31bfee). notifDbWrite now lives in
apps/notifications behind a different API, so restoring it is a cross-workspace
migration, not a one-line fix.

Verification
- root typecheck on the merged head: 0 errors.
- positive control: planted error in scripts/oneoffs/ -> caught (1 error,
  exit 2), so the remaining coverage is real and not a vacuous glob.
- negative control: a NEW deliberately-broken test file dropped into
  scripts/__tests__/ -> 0 root errors. The tripwire is gone.
  The gate still reports that same file, so it is excluded, not invisible.
- ratchet both ways against real tsc: gen_seed 2->3 BLOCKS (exit 1, names the
  delta); untouched tree PASSES (exit 0).
- new invariant test, watched fail: a baseline entry for a root-COVERED file is
  rejected by name, so this baseline cannot be used to park a failure that
  `pnpm typecheck` is actually red on. Plus a negative control proving its
  predicate can reject.
- drift-control mutant re-run against the new glob-shaped quarantine: killed by
  3 tests including the end-to-end one.
- 190 tests pass across both gate suites; prettier and eslint clean.
2026-08-20 11:38:38 -05:00

32 lines
1.5 KiB
JSON

{
// Audit/measurement config: identical to tsconfig.json in every respect
// EXCEPT that it does not exclude `src/**/__tests__/**`.
//
// The delta from the base config is exactly one line, deliberately: a
// hand-rolled narrowed program (one that picks its own `include` or drops
// `src`) silently loses `src/types/global.d.ts`, which makes ambient names
// like `FileMetadata` resolve to TS2304 and collapses downstream generics
// into a FALSE all-clear on the files that matter. Extending the real config
// and subtracting one exclude entry is what keeps the program honest.
//
// 🔴 THIS LIST IS WRITTEN OUT VERBATIM, so it must be kept in step with
// `tsconfig.json`'s `exclude` by hand. `scripts/ci/typecheck-tests-gate.mjs`
// refuses to run (CANNOT MEASURE, exit 3) when the two stop differing by
// exactly `src/**/__tests__/**` — that is a control, not an inconvenience, and
// it is what caught the drift when the `scripts/` entries were added to the
// base config. There are THREE configs to keep in step: this one,
// `tsconfig.scripts.json`, and `tsconfig.json` itself, plus the QUARANTINE
// list in `scripts/ci/typecheck-scripts-gate.mjs`. Both gates fail loudly
// rather than silently mismeasuring when one is forgotten.
"extends": "./tsconfig.json",
"exclude": [
"node_modules",
"./node_modules",
"./node_modules/*",
"src/pages/api/dev-local/*.ts",
"packages/civitai-ui",
"scripts/__tests__/**",
"scripts/local-dev/gen_seed.ts"
]
}