celilo/scripts is outside the typecheck gate — 18 type errors nobody has ever seen #52

Closed
opened 2026-08-17 21:25:46 +00:00 by forgejo-admin · 0 comments

Found while doing #51 (capabilities 2.0.0 upgrade). Out of that PR's scope, filing rather than parking in a summary.

What

bun run typecheck is four explicit project references:

tsc -p apps/lunacycle-server --noEmit &&
tsc -p apps/lunacycle-web/tsconfig.app.json --noEmit &&
tsc -p packages/shared/tsconfig.lib.json --noEmit &&
tsc -p packages/auth-client/tsconfig.lib.json --noEmit

celilo/scripts/ is in none of them, and has no tsconfig.json of its own. The
celilo hook scripts — the code that actually runs against the fleet during
install, health check, backup, and restore — have never been typechecked. bun test
runs them, but bun strips types without checking them, so a green test:hooks
proves nothing about types.

The errors

Ad-hoc run against the real dependency graph (capabilities 2.0.0 installed,
@types/bun + @types/node from the root):

cd celilo/scripts && ../../node_modules/.bin/tsc --ignoreConfig --noEmit --strict \
  --skipLibCheck --module preserve --moduleResolution bundler --target esnext \
  --types bun,node --typeRoots ../../node_modules/@types *.ts

18 errors. They fall into three groups:

Test spies that no longer match the type they claim to implement (12) —
FsOps gained writeFile and the spies in backup.test.ts / restore.test.ts
never did; LunacycleHealthCheckDeps and LunacycleSetupWebDeps gained secrets
and the call sites in health-check.test.ts / setup-web.test.ts still omit it;
IdpSpy is missing list_tokens and revoke_token. Every one of these is a spy
that has silently drifted from the interface it stands in for, which is exactly
the drift a spy is supposed to make impossible.

Real production-code type mismatches (3) — health-check.ts:410 and
smoke-handler.ts:100 assign a Browser that is missing bind/unbind
(two playwright-core Browser types in play), and health-check.ts:459 passes a
Fetcher where typeof fetch is expected (missing preconnect).

Bundled dependency source (3, in node_modules/@celilo/*) — resolved by
skipLibCheck plus a proper types field; noise from the ad-hoc invocation, not
a real defect.

Why it matters

These are hook scripts. When one throws at runtime it throws on celilo-mgr in the
middle of a deploy, and the feedback loop is a failed deploy rather than a red
gate. This is the same class of gap as celilo#455 ("Module TypeScript is never
typechecked") but for this repo's own module directory.

Related: the typecheck gate also misses scripts/ and tests/.

Fix

  1. Add celilo/scripts/tsconfig.json (strict, types: ["bun", "node"], skipLibCheck).
    @types/bun needs to become a devDependency of celilo/scripts/package.json — note
    the publish gate compares the bundled @celilo/* against the pinned version, so
    confirm a devDependency does not disturb it.
  2. Append tsc -p celilo/scripts --noEmit to the typecheck script so pr-validate covers it.
  3. Fix the 18 errors. Update the drifted spies to the current interfaces rather than
    widening the interfaces to accept them.

Do 3 before 2, or the gate lands red.

Found while doing #51 (capabilities 2.0.0 upgrade). Out of that PR's scope, filing rather than parking in a summary. ## What `bun run typecheck` is four explicit project references: ``` tsc -p apps/lunacycle-server --noEmit && tsc -p apps/lunacycle-web/tsconfig.app.json --noEmit && tsc -p packages/shared/tsconfig.lib.json --noEmit && tsc -p packages/auth-client/tsconfig.lib.json --noEmit ``` `celilo/scripts/` is in none of them, and has no `tsconfig.json` of its own. The celilo hook scripts — the code that actually runs against the fleet during install, health check, backup, and restore — have never been typechecked. `bun test` runs them, but bun strips types without checking them, so a green `test:hooks` proves nothing about types. ## The errors Ad-hoc run against the real dependency graph (capabilities 2.0.0 installed, `@types/bun` + `@types/node` from the root): ``` cd celilo/scripts && ../../node_modules/.bin/tsc --ignoreConfig --noEmit --strict \ --skipLibCheck --module preserve --moduleResolution bundler --target esnext \ --types bun,node --typeRoots ../../node_modules/@types *.ts ``` 18 errors. They fall into three groups: **Test spies that no longer match the type they claim to implement** (12) — `FsOps` gained `writeFile` and the spies in `backup.test.ts` / `restore.test.ts` never did; `LunacycleHealthCheckDeps` and `LunacycleSetupWebDeps` gained `secrets` and the call sites in `health-check.test.ts` / `setup-web.test.ts` still omit it; `IdpSpy` is missing `list_tokens` and `revoke_token`. Every one of these is a spy that has silently drifted from the interface it stands in for, which is exactly the drift a spy is supposed to make impossible. **Real production-code type mismatches** (3) — `health-check.ts:410` and `smoke-handler.ts:100` assign a `Browser` that is missing `bind`/`unbind` (two playwright-core `Browser` types in play), and `health-check.ts:459` passes a `Fetcher` where `typeof fetch` is expected (missing `preconnect`). **Bundled dependency source** (3, in `node_modules/@celilo/*`) — resolved by `skipLibCheck` plus a proper `types` field; noise from the ad-hoc invocation, not a real defect. ## Why it matters These are hook scripts. When one throws at runtime it throws on celilo-mgr in the middle of a deploy, and the feedback loop is a failed deploy rather than a red gate. This is the same class of gap as celilo#455 ("Module TypeScript is never typechecked") but for this repo's own module directory. Related: the typecheck gate also misses `scripts/` and `tests/`. ## Fix 1. Add `celilo/scripts/tsconfig.json` (strict, `types: ["bun", "node"]`, `skipLibCheck`). `@types/bun` needs to become a devDependency of `celilo/scripts/package.json` — note the publish gate compares the bundled `@celilo/*` against the pinned version, so confirm a devDependency does not disturb it. 2. Append `tsc -p celilo/scripts --noEmit` to the `typecheck` script so `pr-validate` covers it. 3. Fix the 18 errors. Update the drifted spies to the current interfaces rather than widening the interfaces to accept them. Do 3 before 2, or the gate lands red.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
celilo/lunacycle#52
No description provided.