fix(verify): wire the test layer into typecheck and graduate its TEST_DEBT entry - #15623
Merged
Merged
Conversation
Under `moduleResolution: NodeNext` a relative specifier without its `.js` extension does not resolve, and every symbol it names becomes `any`. These three are the whole of the `@objectstack/verify` TEST_DEBT entry (TS2835 x3). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N
…T_DEBT entry
`packages/verify/tsconfig.json` excludes `**/*.test.ts` and the package's
`typecheck` was a bare `tsc --noEmit` against it, so the script was green over
a layer no tsc program read. Add the sibling `tsconfig.test.json` the other 30
packages use and name it in the `typecheck` chain via
`scripts/check-test-typecheck.mts`.
With the three `./harness` imports fixed the ledger re-measures the entry at 0
("TEST_DEBT records 3, and tsc now reports 0 -- graduation candidate"), so the
entry is deleted here rather than re-tallied, and the residue is zero: no
`test-typecheck-debt.json` is seeded.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N
…rify-test-typecheck-wiring
…generator `check:merge-driver` requires every manifest generator to carry a merge disposition in `scripts/regen-artifacts.mjs`, and #14062's note there refuses to invent one for a ledger that does not exist. The pairing is 1:1 across all 30 sibling configs: 16 with a `test-typecheck-debt.json` declare the generator, 14 without one declare nothing. `check:test-typecheck` is what names the project, and it stays. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D47qPfEWVPmhguWgBZCi5N
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Sep 5, 2026
os-litant
marked this pull request as ready for review
September 5, 2026 01:04
os-litant
enabled auto-merge
September 5, 2026 01:04
os-litant
deleted the
claude/issue-15145-verify-test-typecheck-wiring
branch
September 5, 2026 01:32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #15145
packages/verify/tsconfig.jsonexcludes**/*.test.tsand the package'stypecheckwas a baretsc --noEmitagainst that config, so the script was green over a layer no tsc program read. This wires the layer in the way 30 sibling packages already do, and the@objectstack/verifyTEST_DEBT entry graduates in the same PR.1. Baseline, then the fix, then the re-measure — in that order
Ruling on the card was that steps 1 and 2 be measured, not assumed: the three
TS2835make every symbol those imports name resolve toany, so fixing them can reveal diagnostics and the honest move on an upward count is to re-tally, never to delete.pnpm check:type-check-debtverdict, quoted from the gatef1d787294f0OK — 13 ledger entr(ies) re-measured in 108.6s, 143 raw tsc error(s) total, none above its recorded number./surplus: none — every entry sits exactly at its measurement.jsextensions, at1d671305858ℹ @objectstack/verify: TEST_DEBT records 3, and tsc now reports 0 -- graduation candidate.02b1bdcde2dOK — 12 ledger entr(ies) re-measured in 142.9s, 140 raw tsc error(s) total, none above its recorded number./surplus: noneThe count went DOWN, to zero. So ruling 2's first branch applies and the entry is deleted here, not re-tallied. The prediction in the entry's own note ("the same one-line fix graduates this entry") turned out right — but it was a prediction, and only the middle row above could say so.
check:type-check-coveragemoves consistently with that:test layer: 9 package(s) still hide their own tests from tsc (118 files hidden ..., 90 frozen raw errors in TEST_DEBT)becomes8 package(s) ... (108 files hidden ..., 87 frozen raw errors). Minus one package, minus ten files, minus three errors.2. The wiring route, and why route (b) was declined although it was available
Route (a), the #5286 sibling:
packages/verify/tsconfig.test.jsonpluscheck:test-typecheck --package packages/verify --project tsconfig.test.jsonnamed in thetypecheckchain.tsconfig.jsonis untouched.Route (b) — dropping
**/*.test.tsfromtsconfig.json'sexclude— was measured available here, which is worth stating because the gate's own graduation text says to assume it is not ("Measured red on 14 of the 18 entries that have an exclusion to drop, so assume (b) is unavailable until that gate says otherwise"). Under a trap-restored mutation oftsconfig.json,pnpm check:type-source-resolutioncame back exit 0 (124 tsc program(s) across 78 packages), and the restore was proved by blob-hash equality against the HEAD blob plus an emptygit diff HEAD. The #11491 note inside the ledger script already listedverifyas one of the four that stay green; that still holds.It was declined on module semantics, not availability.
tsconfig.jsoninheritsNodeNextfrom the repo root, so route (b) would hold the test layer to a resolver vitest never runs it under and demand.json every relative specifier in it — the config-tier noise the shared gate's header attributes 108 of spec's 842 raw errors to. 28 of the 30 sibling configs overridemodule/moduleResolutionfor exactly this reason;packages/runtimeis the closest structural analogue (tests undersrc, tsup build, exclusion in the build config) and this config copies its shape.3. The wiring is not vacuous — two independent proofs
--listFiles, on the tree at1d671305858with the workspace closure built:packages/verify/src/*.test.tsin itsrc/**in ittsc -p tsconfig.json(whattypecheckused to be, alone)tsc -p tsconfig.test.jsonSo the zero is the
excludeline, not a probe that sees nothing.Ablation. A deliberate type error was appended to
src/derive.test.ts— a file already in both programs, compiled from source by each, so no rebuild leg applies. Predicted direction: the old program stays green, the wired script reddens. Measured, exactly that:tsc --noEmit -p tsconfig.json: exit 0, 0 errorspnpm --filter @objectstack/verify typecheck: exit 1 —src/derive.test.ts: 1 type error(s) in a file the ledger does not cover.The mutation was proved on disk before either run (injected marker counted 1, injected statement counted 1,
git diff --numstat4 added lines) and the restore was proved by blob hash against the HEAD blob and an emptygit diff HEAD.4. Findings
Zero phantom pins, and that is the finding. The card's sharpest line is that any
ts-expect-errorin those files is currently a phantom check. Grepped with a positive control (the same grep hitspackages/spec/src), this package's test layer holds zerots-expect-errorand zerots-ignoredirectives. So no pin was silently dead — the statement was about what would happen. That matches whatpackages/cli's graduation recorded for its own 115 files. What the gap actually cost was the other half: no way to write a type-level pin in this layer at all, and nothing reading it.The card's file count was stale. Re-derived on
origin/main: tensrc/*.test.ts, not the card's nine. The tenth isartifact-collections.test.ts. Triage had already caught this; it is re-derived here rather than carried over.Adding
gen:test-typecheck-debtredscheck:merge-driver, and the right answer is not to add a disposition. The first draft declared that generator alongsidecheck:test-typecheck, and the gate refused:generator(s) with NO recorded merge disposition: gen:test-typecheck-debt [@objectstack/verify]. The pairing is 1:1 across all 30 sibling configs — 16 with atest-typecheck-debt.jsondeclare the generator, 14 without one declare nothing — and #14062's note inscripts/regen-artifacts.mjsrefuses to invent a disposition for a ledger that does not exist. The script was dropped rather than routed. If this layer ever measures non-zero, the ledger, the generator and itsregen-artifactsrow arrive together in that one PR.5. No changeset —
skip-changesetJudged from the rule text in
.github/workflows/pr-automation.yml, Check Changeset step: route 2, "It releases nothing ... tests-only, and the like". This diff is build-config and test-layer wiring plus repo tooling. It adds no exported symbol, no accepted key or value, and no runtime behaviour:tsconfig.test.jsonis not in the package'sfiles, the three edited files are tests that tsup never bundles, andscripts/check-type-check-coverage.mjsis not published. Under the WHICH LEVEL rule a bump would have to be at leastminoronly for a purely additive widening of a published surface, and there is none — so the label, not a changeset written to be safe.6. Verification
Gate union re-derived from the real changed paths with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(the tool reads its own change set from the merge base; the first derivation warned STALE and was re-run after mergingorigin/main).Run to a verdict, all green, on head
02b1bdcde2dunless noted:check:type-check-coverage,check:type-check-debt— both to a verdict, never leftPREREQUISITE NOT MET; closure built first withpnpm exec turbo run build --filter=./packages/* --filter=./packages/*/*pnpm --filter @objectstack/verify typecheck—check:test-typecheck: OK — @objectstack/verify's test layer compiles under packages/verify/tsconfig.test.json; 0 file(s) / 0 error(s) / 0 pinned signature(s)pnpm --filter @objectstack/verify test—Test Files 10 passed (10)/Tests 58 passed (58)agent-test-spellingbash32-floorcli-command-idscross-package-test-inputsdoc-authoringdual-build-cjs-loadsentry-guardlogger-receiver-detachmerge-driverobjectql-double-limitorg-identifieroverride-consistencypage-declaration-shapeparse-guardpnpm-filter-targetspublished-filesratchet-remedy-authorityservice-providersslot-lookuptest-source-aliasturbo-task-graphtype-source-resolutionwhere-matcherworkspace-manifest-cycles, plusspec run check:llms-txtnul-bytesengine-double-contractdriver-memory-censusrefd-timer-probewatch-hint-literalquery-options-erasurepm-dispatch-gatespublished-list-mirrors(and its self-test)authz-resolverconsole-injectionerror-code-casingfilter-alias-parityi18n-stale-fillpublished-readme-exportssingle-claim-pathspartof-closing-keywordci-filter-parity --self-testpm-governed-prosepnpm lint— the full repo scan,eslint . --no-inline-config, exit 0 in 1m20s. No narrowing was needed, so none is claimed.Exit codes were captured after redirection, never through a pipe.
🤖 Generated with Claude Code
Generated by Claude Code