Skip to content

fix(runtime): wire the test layer into check:test-typecheck, so its 214 test files are type-checked at all (#14504) - #14785

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-14504-runtime-test-typecheck
Sep 3, 2026
Merged

fix(runtime): wire the test layer into check:test-typecheck, so its 214 test files are type-checked at all (#14504)#14785
os-trump merged 2 commits into
mainfrom
claude/issue-14504-runtime-test-typecheck

Conversation

@os-trump

@os-trump os-trump commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes #14504

packages/runtime/tsconfig.json excluded **/*.test.ts and **/*.spec.ts, and the package's typecheck script was a bare tsc --noEmit against that very config — so no tsc program anywhere read a runtime test file, while pnpm --filter @objectstack/runtime typecheck exited 0 and read as a pass.

The premise, re-measured on current main rather than taken from the card

The card and its triage both counted 208 test files at ed44512; four packages/runtime PRs landed since, and the population is now 214. Everything else in the filing holds exactly. Measured at 224f8ea4a0 with the workspace closure built first — an error count taken against an unbuilt closure is not a reading:

probe program files runtime *.test.ts in program
tsc --noEmit --listFiles -p packages/runtime/tsconfig.json (build config) 899 0 of 214
same, with -p tsconfig.test.json (this PR) 1148 214 of 214

The zero is the exclude line and not a probe that sees nothing: 79 non-test src/** files ARE in the build program. Directional control — packages/drivers/driver-memory, whose tsconfig carries no test exclusion — puts 40 of its 40 test files in.

Scope taken: wire and ledger, no repair — and the count that justifies it

191 errors across 27 files. The ruling is the card's own triage, not a narrowing invented here: "⛔ Do not fix the type errors the first measurement finds. Seed the ledger and let the ratchet shrink." Repairing 191 errors in the PR that opens the gate would bury the gate, which is how an onboarding stops landing. No test file is edited in this PR, so no file held by another open PR is touched.

Precedent followed: the wiring shape of objectql, rest, lint and the fourteen packages/plugins/** — the shared scripts/check-test-typecheck.mts is called, never copied.

What changed

  • packages/runtime/tsconfig.test.json (new) — module semantics only, plus lib: module: esnext, moduleResolution: bundler, lib: ["ES2022"], matching how vitest actually executes these files. ⛔ Strictness is untouched and inherited; rootDir stays ./src (measured: this layer produces no TS6059, unlike client and rest). Not one any and not one @ts-expect-error was added to any test file to open the gate.
  • packages/runtime/test-typecheck-debt.json (new, generated) — 27 files / 191 errors / 69 signatures, EXACT and shrink-only. The other 187 test files carry no entry, so an error arriving in any of them is red on the PR that introduces it. Carries an authored _note with the composition and the attribution.
  • packages/runtime/package.jsontypecheck becomes tsc --noEmit && pnpm check:test-typecheck, plus check:test-typecheck and gen:test-typecheck-debt beside it. No new devDependency: tsx resolves from the workspace-root bin, the same way packages/lint invokes it (verified by reading the script PATH, not assumed).
  • scripts/check-type-check-coverage.mjs — the @objectstack/runtime TEST_DEBT entry (errors: 206) graduates, with the graduation documented in the block comment beside the four that graduated under [finding] No plugin package has a tsc program that compiles its tests — plugin-approvals alone hides 345 type errors, and 0 of 14 are in the test-typecheck ledger #14062 / [finding] packages/lint has no tsc program that compiles its tests — the 2,700-line rule pin file, receiver scan included, is type-checked by nobody #14173. ⛔ Nothing was paid down; the same population moved to a sharper instrument.
  • scripts/check-type-source-resolution.mjs — a re-baseline on that registry's own onboarding limb (see below).
  • scripts/regen-artifacts.mjs — the sixth test-typecheck-debt.json row, so a merge never recomputes this ledger on a half-merged tree.
  • .changeset/runtime-test-typecheck-wiring.md.

206 to 191, attributed in both directions with no remainder

The same program under the build config's inherited NodeNext reports 206 — exactly the number the coverage gate already held for this package. So this is a conversion, not a new debt-opening decision.

  • minus 19 dissolve under vitest-matching module semantics and were about the CHECK, never the code: TS2835 x13 (extension-less relative imports), the TS7006 x4 cascading above them, TS2550 x2 (Array.prototype.at).
  • plus 4 that collapsing the cascade EXPOSED: TS2322 x4 in src/seed-loader.test.ts, previously masked by an any from the unresolved import.

206 - 19 + 4 = 191.

The registry re-baseline, on its own three conditions

Onboarding a tsconfig.test.json moves the package's PROGRAM SET, which since #11490 a package may do, and check:type-source-resolution names that case explicitly as a reviewed re-baseline rather than a widening.

  1. Provenance. Nine deps become visible, every one annotated (via tsconfig.test.json) by the gate itself, and a --list taken with the wiring reverted as the ONLY difference between the two trees reports the entry without any of the nine.
  2. Numbers stated in place, both from --list on the same checkout: 114 to 115 programs, 270 to 279 package-dep pairs, +0 entries, +0 non-clean packages. Shrink-only from 279.
  3. paths is deliberately not the tool, on the onboarding limb's measured grounds (PR build(rest): give the package a test-layer tsc program and ledger its 37 errors #12570): it would bill other packages' source diagnostics into a ledger those packages cannot see.

One thing the card overstated, measured

Its sharpest line — "a @ts-expect-error written in any packages/runtime test today is a phantom check" — is about what WOULD happen, not an existing pin. This layer holds zero @ts-expect-error directives across all 214 files, and none reports TS2578 under the new program. The cost of the gap was the 191 unreported errors and the fact that a type-level pin could not be written in this package at all.

Verification

Everything below on the final tree, 0a492f6bb6.

Red-first, both ratchet directions, with the mutations proved on disk and the restores proved by blob identity under a trap ... EXIT INT TERM on absolute paths:

  • Leg A — unledgered file gains an error. src/domains/actions-validation-envelope.test.ts, pure append (injected-marker-count=1, removed-text-count=0, bytes 6706 -> 6852, blob 81345b00d727 -> be093dd04637). Gate EXIT=1: "1 type error(s) in a file the ledger does not cover ... ⛔ MAINTAINER-ONLY, NOT a co-equal option: add the file to test-typecheck-debt.json."
  • Leg B — ledgered file gains a signature. src/observability/metrics.test.ts, same discipline (blob 9384d284b0a8 -> 2b15c61ad383). Gate EXIT=1: "1 type error(s) carrying a signature the ledger does not record — ARRIVED: TS2322 ..."
  • Restores. Both files back to their HEAD blob by hash equality (81345b00d727, 9384d284b0a8), marker count 0, git diff HEAD empty.
  • Control. Restored tree, same command, EXIT=0: "check:test-typecheck: OK — @objectstack/runtime's test layer compiles under packages/runtime/tsconfig.test.json; 27 file(s) / 191 error(s) / 69 pinned signature(s)."

Gates. node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derives 49 commands at 0a492f6bb6 (7 paths vs merge base 224f8ea4a). All 49 run with each exit captured before any pipe; 47 exit 0. The two non-zero are prerequisite verdicts in the gates' own words and are NOT MEASURED, neither a pass nor a red:

  • check-test-completeness.mjs — EXIT=3, "Nothing was measured: this gate exited before parsing a single summary line ... ⛔ It is NOT a finding" (it needs a saved turbo run test log).
  • scripts/pm/check-half-states.mjs — EXIT=3, "Treat this exit as an unread instrument, never as a quiet board" (repo-scoped GitHub REST is 403 for this session).

check:type-check-debt and check:dual-build-cjs-loads first returned their own prerequisite verdict ("Run pnpm build first. ⛔ This is NOT a pass"); the full closure was then built (turbo run build --filter='./packages/*' and --filter='./packages/*/*', 57 + 70 tasks, exit 0) and both re-run green--re-measure: OK — 21 ledger entr(ies) re-measured in 157.8s, 549 raw tsc error(s) total, none above its recorded number.

Package. pnpm --filter @objectstack/runtime typecheck exit 0 — the full new chain, self-test included. vitest run --maxWorkers=2: 214 test files / 3121 tests, all passing.

Whole repo. pnpm lint (eslint . --no-inline-config) exit 0, unnarrowed. check:nul-bytes OK over 8055 tracked text files.

All heavy runs went through scripts/pm/os-verify-lock.sh; verdicts read from its VERDICT line, never a bare $?.

🤖 Generated with Claude Code

https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza


Generated by Claude Code

…14 test files are type-checked at all (#14504)

packages/runtime/tsconfig.json excluded **/*.test.ts and **/*.spec.ts while the
package's typecheck script was a bare `tsc --noEmit` against that very config,
so no tsc program anywhere read a runtime test file. Measured at 224f8ea with
the closure built: the build config puts 899 files in the program and 0 of the
package's 214 test files among them, while 79 non-test src/** files ARE there;
the directional control (packages/drivers/driver-memory, no test exclusion) puts
40 of its 40 in. Under the new tsconfig.test.json the count is 214 of 214.

Wired to the shared scripts/check-test-typecheck.mts, never copied, the way
objectql / rest / lint / packages/plugins/** are wired. Strictness and rootDir
inherited untouched; no test file is edited and no `any` or @ts-expect-error was
added to open the gate.

Seeded, not repaired, per this card's triage ruling: 191 errors over 27 files
recorded EXACT and shrink-only in the new test-typecheck-debt.json; the other
187 test files carry no entry, so an error arriving in one of them is red. This
is a CONVERSION of the coverage gate's existing @objectstack/runtime TEST_DEBT
entry (errors: 206), which graduates here as the pairing forces: 206 - 19
config-tier + 4 newly exposed = 191, attributed with no remainder.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
… onboarded test program

Onboarding `tsconfig.test.json` moves this package's PROGRAM SET, which since
#11490 a package may do, so check:type-source-resolution's registry entry is
re-measured rather than widened. Nine deps become visible, every one annotated
`(via tsconfig.test.json)` by the gate itself and absent from a `--list` taken
with the wiring reverted as the only difference between the two trees.

Numbers stated in place per the registry's own condition 2, both from `--list`
on the same checkout: 114 -> 115 programs, 270 -> 279 package-dep pairs, +0
entries, +0 non-clean packages. `paths` is deliberately not the tool here on the
onboarding limb's measured grounds (PR #12570).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016yfqQh2dBgPAymYd7xipza
@github-actions github-actions Bot added the size/m label Sep 3, 2026
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/runtime/test-typecheck-debt.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/runtime/test-typecheck-debt.json) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 24 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json dee4dd4ba33f8b98ff90e240327b7567adecc017packageMentionDocs.

@github-actions github-actions Bot added dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation tooling labels Sep 3, 2026
@os-trump
os-trump marked this pull request as ready for review September 3, 2026 01:23
@os-trump
os-trump enabled auto-merge September 3, 2026 01:23
@os-trump
os-trump added this pull request to the merge queue Sep 3, 2026
Merged via the queue into main with commit e6ac0c6 Sep 3, 2026
35 of 36 checks passed
@os-trump
os-trump deleted the claude/issue-14504-runtime-test-typecheck branch September 3, 2026 02:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] packages/runtime type-checks none of its 208 test files — tsconfig excludes **/*.test.ts and no test-typecheck wiring exists

2 participants