Repository navigation
fix(oracles): install the gap CLI's TypeScript under an alias, so it never changes a project's own - #18
Merged
Conversation
npm hoisted the plain typescript dependency to adopters' roots, which gave a project without TypeScript a typescript package and deduped a project's own range up to 5.9. The CLI now resolves typescript-for-tanstack-oracles (npm:typescript@^5.9.2), an unscoped name that sorts after typescript, so on a clean install the project's own typescript keeps its tsc bin. A test packs the package, installs it with npm, and runs the CLI where the project has no TypeScript. Co-authored-by: Isaac <no-reply@databricks.com>
…ct's TypeScript The owned project now installs typescript@5.4.5 first and the tarball second, the case where a plain dependency raised the root to 5.9.3, and checks the clean install with npm ci. The bin residue is asserted as documented behavior, and the changeset states that it lasts until a clean install. Co-authored-by: Isaac <no-reply@databricks.com>
🦋 Changeset detectedLatest commit: 361d268 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
commit: |
KyleAMathews
added a commit
that referenced
this pull request
Nov 11, 2026
Replace interim rules with what landed: the take-back check now fails at load (#15); lint reports empty tests, and the presets ignore tool configs, so a custom ignores must merge the preset's (#16); the gap check's TypeScript is an npm alias, with only a .bin/tsc residue (#18); enumerated sources declare states, and the reach test enforces them (#19). Co-authored-by: Isaac <no-reply@databricks.com>
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.
Summary
The gap CLI's TypeScript dependency is now the npm alias
"typescript-for-tanstack-oracles": "npm:typescript@^5.9.2". The CLI resolves it by that name withcreateRequire, and no code path in the package resolvestypescriptby its plain name.The problem
Since d8adfee,
@tanstack/oraclesdepends ontypescriptfor the gap CLI. Under npm, that dependency is hoisted into an adopter'snode_modules. I reproduced it offline from the packed tarball and the npm cache (npm 11.17.0):node_modules/typescriptat 5.9.3, plus.bin/tscand.bin/tsserver.npm i -D typescript@5.4.5and then installed the package, npm saved^5.4.5and deduped the project's root TypeScript up to 5.9.3. Bothrequire('typescript')andtscchanged. This is the mitt case.Why an unscoped alias name
The brief suggested
@tanstack/oracles-typescript. I tested it, and it makestscworse. npm links the bins of every package hoisted to the root. It resolves a bin conflict by the first package in sorted path order (@npmcli/arboristsortNodes,bin-linkslinkGently).node_modules/@tanstack/...sorts beforenode_modules/typescript. So with the scoped alias, even a clean install of a project with its owntypescript@5.4.5linked.bin/tscto the alias's 5.9.3. The nametypescript-for-tanstack-oraclessorts aftertypescript, so on a clean install the project's owntypescriptkeepstsc. Its scope cannot collide with a real package in the adopter's tree.Package managers: npm and pnpm both install an
npm:alias that a published package declares. pnpm puts nothing at the adopter's root and links only direct dependencies' bins. I checked this withpnpm add --offline <tarball>: there is notypescriptand notscat the root, and the CLI'screateRequireresolves the alias (5.9.3).pnpm packandnpm packboth keep the alias as written independencies, and the tarball bundles nonode_modules. pkg.pr.new (publish --pnpm) publishes that packed tarball, so previews keep working. publint--strictand sherif pass.Changes
package.json: the alias replaces the plain dependency. The lockfile changes only that importer entry.oracle-gaps/check.mjs: the CLI loadstypescript-for-tanstack-oracles. The API-less refusal is unchanged.gap-report-model-oracle.mjs, and the static, probe-form, and mutant-validity oracles) andtests/oracle-gaps-owns-through-calls.test.tsresolve the same alias. They use the CLI's TypeScript, not the workspace's.tests/package.test.ts: a new test builds and packs the package. It installs the tarball with npm (--prefer-offline) into two scratch projects. It works fully offline from this machine's npm cache.node_modules/typescriptis absent. The test writes a small oracle and source, and runs the CLI's analysis (oracle-gaps --source src/order.ts --contexts 1). The CLI exits 0 and finds mutants. The test also checks the known residue as documented behavior:.bin/tsclinks to the alias.typescript@5.4.5and then the tarball. This is the incremental case where a plain dependency deduped the root. The test checks that the roottypescriptis still 5.4.5 and that.bin/tsclinks to the alias. Afternpm ci, the root is still 5.4.5 and.bin/tsclinks to../typescript/bin/tsc.Evidence
This change is to packaging. No oracle owns how npm lays out an adopter's tree, and npm is the authority. So the focused install test checks the law, as the brief asked. The gap oracles'
apiLessTypescriptfault still covers the CLI side: the CLI never reads the package's TypeScript.@tanstack/oracleswith npm puts notypescriptpackage where the adopter resolves it. A project with its own TypeScript keeps its version forrequire, and on a clean install fortsctoo. The CLI's analysis works in a project with no TypeScript. Authority: maintainer brief F19 (2026-11-10), and the d8adfee decision that the CLI analyzes with its own TypeScript 5.npm ci. A fresh install of both together does not tell old from new, because npm nests a plain dependency there.typescriptdependency, plain resolution),pnpm exec vitest --run --maxWorkers=2 tests/package.test.ts -t "installs with npm"fails withexpected true to be false:node_modules/typescriptis present. With the same old-style tarball, the incremental half alone fails withexpected '5.9.3' to be '5.4.5': the roottypescriptwas deduped up to 5.9.3.tests/package.test.tsgives 6 passed. The default suite gives 56 passed. The gap oracles that now load the alias pass: static, classify, probe-form, and mutant-validity give 31249 passed. The end-to-end gap oracle's fixed seed, run under the e2e lock, gives 1 passed (216 s).tsc, eslint, publint--strict, and sherif are clean.@tanstack/oracles-typescript), fails withexpected '../@tanstack/oracles-typescript/bin/t…' to be '../typescript/bin/tsc'. M2, the alias dependency but plaintypescriptresolution in the CLI, fails because the CLI exits 3 in the project without TypeScript (expected 3 to be +0).tscandtsserverinto.binin two cases. The first is a project without TypeScript. The second is an incrementalnpm install @tanstack/oraclesinto a project that has TypeScript. There.bin/tscpoints at the alias until a clean install (npm ci, or removingnode_modules). A later plainnpm installleaves it there.typescriptitself from 5.4.5 to 5.9.3.typescript. So under PnP the alias may run unpatched. This is untested, and so are Yarn and Bun in general.typescript-for-tanstack-oraclesexists on the npm registry is unverified, because offlinenpm viewreturned ENOTCACHED. An alias does not fetch by its own name. So this matters only for a project that also depends on a real package of that name.Decisions for the maintainer
typescript-for-tanstack-oraclesover the brief's scoped example, for the bin-precedence reason above. Choose another name only if it sorts aftertypescript..bin/tsccases above remain, and bundling TypeScript, the only npm-side fix, is ruled out.This pull request and its description were written by Isaac.