Found while working on #14270 (which edits one of the nine files below). Out of that card's scope, filed rather than fixed.
⚠️ Corrected after filing. The first version of this issue claimed "nothing in CI reads their types at all". That is false, and I measured it false an hour later on my own branch — see What actually reads them below. The structural fact is real; the consequence I drew from it was not. The correction is kept in place rather than silently edited away, because the wrong version is the more tempting reading of the same tsconfig.
The structural fact
packages/verify/tsconfig.json carries:
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.test.ts"]
and packages/verify/package.json's typecheck is a bare tsc --noEmit, with no check:test-typecheck script and no tsconfig.test.json beside it.
Measured with --listFiles on the real project, at e37456eb03:
npx tsc --noEmit --listFiles -p packages/verify/tsconfig.json | grep -c 'harness.host-resolution.test.ts$'
0
npx tsc --noEmit --listFiles -p packages/verify/tsconfig.json | grep -c 'packages/verify/src/harness.ts$'
1
The source file is in the program; the test beside it is not. Nine files are affected — every packages/verify/src/*.test.ts:
automation-trigger-paused-run.test.ts
automation-trigger-terminal-messages.test.ts
derive.test.ts
erasure-transaction-authorization.test.ts
harness.app-default-profile.test.ts
harness.host-resolution.test.ts
harness.org-context.test.ts
harness.posture-only.test.ts
harness.posture.test.ts
So pnpm --filter @objectstack/verify typecheck reports green over a test layer it never read, and a ts-expect-error written in any of the nine is a phantom check under that script.
What actually reads them — the correction
pnpm check:type-check-debt does, and it is not lenient about it. @objectstack/verify carries a TEST_DEBT entry in scripts/check-type-check-coverage.mjs:
'@objectstack/verify': { errors: 3, note: 'TS2835 x3 -- `harness.host-resolution`, `harness.posture-only` and
`harness.posture` each import `./harness` without the `.js` extension. ...' }
and --re-measure re-runs tsc per ledger entry with the exclusion lifted. On my #14270 branch it caught a real drift of mine within one run:
check-type-check-coverage --re-measure: 1 ledger entr(ies) drifted upward
• @objectstack/verify: TEST_DEBT records 3 raw tsc error(s), `tsc --noEmit` now reports 5 (+2).
Two .then(onFulfilled, onRejected) callbacks I had added were implicitly-any parameters — precisely because the unresolved ./harness specifier makes every symbol it names any, which is the mechanism the ledger note already describes. So the ratchet works, it is shrink-only, and it is doing its job.
That downgrades this from "unmeasured" to "measured centrally as frozen debt, rather than wired the way the rest of the repo wires it". Still worth closing, for two reasons that survive the correction:
- The package's own advertised
typecheck is green over source nothing read — the shape AGENTS.md names in the type-check-coverage section ("a green gate over source nothing read"), and the reason ts-expect-error in those nine files is phantom. The central ratchet catches counts; it does not make the package's own script honest.
- The debt is three diagnostics with a one-line fix each, named in the ledger note itself:
import { bootStack } from './harness' needs './harness.js' in harness.host-resolution.test.ts, harness.posture-only.test.ts and harness.posture.test.ts. The note says so outright — "the same one-line fix graduates this entry".
Suggested shape
- Add the
.js extension to the three ./harness imports. Per the ledger note this is expected to take the entry to 0 — and re-measuring is what proves it, not this issue.
- Delete the
@objectstack/verify TEST_DEBT entry in the same PR (a package that graduates deletes its entry in the same PR — AGENTS.md).
- Lift
**/*.test.ts out of packages/verify/tsconfig.json's exclude, or — if the build config must keep it — add packages/verify/tsconfig.test.json and name it in the typecheck script via scripts/check-test-typecheck.mts --package packages/verify --project tsconfig.test.json, the way packages/cli, packages/spec and 21 other packages already do. Onboard by wiring, never by copying another package's ledger.
⚠️ Steps 1 and 2 must be measured, not assumed: run pnpm check:type-check-debt before deleting the entry. If the three TS2835 were masking further diagnostics in files that currently resolve to any, the count goes UP when the imports are fixed, and the honest move is then to re-tally the entry rather than delete it.
Not fixed in #14270: different defect class (type-check wiring, not the remedy branch), different file surface, and graduating a ledger entry is not something to ride on a message fix. That card took the narrow path instead — it rewrote its two new cases as try/catch so they add no diagnostics, and left the three pre-existing ones alone.
Generated by Claude Code
Found while working on #14270 (which edits one of the nine files below). Out of that card's scope, filed rather than fixed.
The structural fact
packages/verify/tsconfig.jsoncarries:and
packages/verify/package.json'stypecheckis a baretsc --noEmit, with nocheck:test-typecheckscript and notsconfig.test.jsonbeside it.Measured with
--listFileson the real project, ate37456eb03:The source file is in the program; the test beside it is not. Nine files are affected — every
packages/verify/src/*.test.ts:So
pnpm --filter @objectstack/verify typecheckreports green over a test layer it never read, and ats-expect-errorwritten in any of the nine is a phantom check under that script.What actually reads them — the correction
pnpm check:type-check-debtdoes, and it is not lenient about it.@objectstack/verifycarries a TEST_DEBT entry inscripts/check-type-check-coverage.mjs:and
--re-measurere-runs tsc per ledger entry with the exclusion lifted. On my #14270 branch it caught a real drift of mine within one run:Two
.then(onFulfilled, onRejected)callbacks I had added were implicitly-any parameters — precisely because the unresolved./harnessspecifier makes every symbol it namesany, which is the mechanism the ledger note already describes. So the ratchet works, it is shrink-only, and it is doing its job.That downgrades this from "unmeasured" to "measured centrally as frozen debt, rather than wired the way the rest of the repo wires it". Still worth closing, for two reasons that survive the correction:
typecheckis green over source nothing read — the shape AGENTS.md names in the type-check-coverage section ("a green gate over source nothing read"), and the reasonts-expect-errorin those nine files is phantom. The central ratchet catches counts; it does not make the package's own script honest.import { bootStack } from './harness'needs'./harness.js'inharness.host-resolution.test.ts,harness.posture-only.test.tsandharness.posture.test.ts. The note says so outright — "the same one-line fix graduates this entry".Suggested shape
.jsextension to the three./harnessimports. Per the ledger note this is expected to take the entry to 0 — and re-measuring is what proves it, not this issue.@objectstack/verifyTEST_DEBT entry in the same PR (a package that graduates deletes its entry in the same PR — AGENTS.md).**/*.test.tsout ofpackages/verify/tsconfig.json'sexclude, or — if the build config must keep it — addpackages/verify/tsconfig.test.jsonand name it in thetypecheckscript viascripts/check-test-typecheck.mts --package packages/verify --project tsconfig.test.json, the waypackages/cli,packages/specand 21 other packages already do. Onboard by wiring, never by copying another package's ledger.pnpm check:type-check-debtbefore deleting the entry. If the three TS2835 were masking further diagnostics in files that currently resolve toany, the count goes UP when the imports are fixed, and the honest move is then to re-tally the entry rather than delete it.Not fixed in #14270: different defect class (type-check wiring, not the remedy branch), different file surface, and graduating a ledger entry is not something to ride on a message fix. That card took the narrow path instead — it rewrote its two new cases as try/catch so they add no diagnostics, and left the three pre-existing ones alone.
Generated by Claude Code