Found while doing a prose-only docblock fix in packages/core/src/security/authz-store-unavailable.ts (#14006), when the dispatched always-run pnpm --filter @objectstack/core typecheck turned out not to exist. Recorded for triage; no severity asserted, and nothing here is caused by that card's diff.
The shape
packages/core/package.json declares exactly three scripts:
"build": "tsup && node ../../scripts/check-dts-emitted.mjs",
"test": "vitest run",
"test:watch": "vitest"
There is no typecheck and no type-check. Around twenty sibling packages declare one — @objectstack/types, @objectstack/spec, @objectstack/objectql, @objectstack/rest, @objectstack/runtime, @objectstack/cli, @objectstack/lint, @objectstack/metadata-protocol, @objectstack/platform-objects, @objectstack/client, @objectstack/client-react, @objectstack/mcp, @objectstack/formula, @objectstack/verify, @objectstack/sdui-parser, @objectstack/metadata-core, @objectstack/metadata-fs, create-objectstack, @objectstack/account, @objectstack/setup — so the lint workflow's typecheck job, which drives packages through that script, has no way to reach @objectstack/core. The package's types ship anyway: build emits dist/index.d.ts at 233 KB via tsup's DTS rollup, and @objectstack/core is imported by rest, runtime, mcp, services and plugins.
Measured, on this box
Node 22.22.2, worktree off origin/main at d15ecd855, pnpm install clean, running the package's own tsconfig:
$ pnpm --filter @objectstack/core exec tsc --noEmit -p tsconfig.json > /tmp/tc.log 2>&1; echo "EXIT=$?"
EXIT=2
$ grep -cE '^src/.*error TS' /tmp/tc.log
98
98 errors across 12 files, and every one of them is a .test.ts:
src/fallbacks/fallbacks.test.ts src/security/auth-gate.test.ts
src/kernel.test.ts src/security/plugin-permission-enforcer.test.ts
src/lite-kernel.test.ts src/utils/bulk-write.test.ts
src/logger.test.ts src/utils/env.test.ts
src/plugin-loader.test.ts src/utils/filter-tokens.test.ts
src/plugin-order.test.ts src/utils/migration-journal.test.ts
By error code: 71 × TS7006 (parameter implicitly any), 22 × TS2835, and one each of TS18046, TS2347, TS2352, TS2739, TS6133. Zero errors in any non-test source file, so the published surface itself type-checks clean today — what is unmeasured is whether it stays that way.
Why it is worth recording rather than shrugging at
packages/core/tsconfig.json is not a stub. It carries a paragraph of comment explaining that rootDir was widened to .. because rootDir "is enforced over every program file even under --noEmit", and a second paragraph redirecting @objectstack/types to source so that "a stale dist would make this package's type verdict a function of build state rather than of the source in the checkout". Both paragraphs are reasoning about a --noEmit pass that nothing currently runs. The config was tuned for a gate that is not wired.
The gap is asymmetric in a way that hides it: build is green because tsup's DTS rollup is not a full-program check of the test files, and test is green because vitest transpiles without type-checking. So both existing jobs pass while the program the tsconfig describes is red — the package looks covered from every direction anyone currently looks from.
Suggested shape of the repair, and the fork in it
Two routes, and the choice is a judgement call rather than a mechanical one:
- Wire the script and fix the 98. Add
"typecheck": "tsc --noEmit" and clear the test-file errors (the bulk is 71 × implicit-any parameters, mostly mechanical). Brings core in line with its ~20 siblings and makes the tsconfig's own stated reasoning true.
- Wire the script scoped to non-test sources, if type-checking this package's tests is deliberately not wanted — but then the tsconfig comments about
--noEmit should say so, because today they read as describing a pass that covers everything.
⛔ What should NOT happen is adding the script without deciding: pnpm --filter @objectstack/core typecheck would go red on main on the first run.
Note also that a dispatched task already assumed this script exists, which is the propagation cost — the absence is invisible until something tries to run it, and pnpm --filter reports a missing script as ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT, which is loud, but only for whoever runs it by hand.
Found while doing a prose-only docblock fix in
packages/core/src/security/authz-store-unavailable.ts(#14006), when the dispatched always-runpnpm --filter @objectstack/core typecheckturned out not to exist. Recorded for triage; no severity asserted, and nothing here is caused by that card's diff.The shape
packages/core/package.jsondeclares exactly three scripts:There is no
typecheckand notype-check. Around twenty sibling packages declare one —@objectstack/types,@objectstack/spec,@objectstack/objectql,@objectstack/rest,@objectstack/runtime,@objectstack/cli,@objectstack/lint,@objectstack/metadata-protocol,@objectstack/platform-objects,@objectstack/client,@objectstack/client-react,@objectstack/mcp,@objectstack/formula,@objectstack/verify,@objectstack/sdui-parser,@objectstack/metadata-core,@objectstack/metadata-fs,create-objectstack,@objectstack/account,@objectstack/setup— so the lint workflow'stypecheckjob, which drives packages through that script, has no way to reach@objectstack/core. The package's types ship anyway:buildemitsdist/index.d.tsat 233 KB via tsup's DTS rollup, and@objectstack/coreis imported by rest, runtime, mcp, services and plugins.Measured, on this box
Node 22.22.2, worktree off
origin/mainatd15ecd855,pnpm installclean, running the package's own tsconfig:98 errors across 12 files, and every one of them is a
.test.ts:By error code: 71 × TS7006 (parameter implicitly
any), 22 × TS2835, and one each of TS18046, TS2347, TS2352, TS2739, TS6133. Zero errors in any non-test source file, so the published surface itself type-checks clean today — what is unmeasured is whether it stays that way.Why it is worth recording rather than shrugging at
packages/core/tsconfig.jsonis not a stub. It carries a paragraph of comment explaining thatrootDirwas widened to..becauserootDir"is enforced over every program file even under--noEmit", and a second paragraph redirecting@objectstack/typesto source so that "a stale dist would make this package's type verdict a function of build state rather than of the source in the checkout". Both paragraphs are reasoning about a--noEmitpass that nothing currently runs. The config was tuned for a gate that is not wired.The gap is asymmetric in a way that hides it:
buildis green because tsup's DTS rollup is not a full-program check of the test files, andtestis green because vitest transpiles without type-checking. So both existing jobs pass while the program the tsconfig describes is red — the package looks covered from every direction anyone currently looks from.Suggested shape of the repair, and the fork in it
Two routes, and the choice is a judgement call rather than a mechanical one:
"typecheck": "tsc --noEmit"and clear the test-file errors (the bulk is 71 × implicit-anyparameters, mostly mechanical). Brings core in line with its ~20 siblings and makes the tsconfig's own stated reasoning true.--noEmitshould say so, because today they read as describing a pass that covers everything.⛔ What should NOT happen is adding the script without deciding:
pnpm --filter @objectstack/core typecheckwould go red onmainon the first run.Note also that a dispatched task already assumed this script exists, which is the propagation cost — the absence is invisible until something tries to run it, and
pnpm --filterreports a missing script asERR_PNPM_RECURSIVE_RUN_NO_SCRIPT, which is loud, but only for whoever runs it by hand.