Repository navigation
fix(fix): verify with the repository's own TypeScript; CLI tests stop writing to /repo - #40
Merged
Merged
Conversation
… NODE_PATH resolveCompiler required typescript from the repository with Node's resolution, which also searches NODE_PATH and the global folders: with a global TypeScript 6 on NODE_PATH, a repository without its own compiler was verified by it (TS5107 for moduleResolution node10, which CI, with no NODE_PATH, never saw). It now takes node_modules/typescript of the repository or an ancestor, else the bundled compiler. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B2T8GmEVnZwfNrugajEMqi Signed-off-by: Claude <noreply@anthropic.com>
fixReport's prBody was /repo/.uptide/pr-body.md, and fix writes the report page next to it: where tests run as root the write succeeds, so the verify summary test saw its own report path replaced, and /repo was left behind. A fresh temporary directory per report; the summary test asserts the absolute path of its own stored run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B2T8GmEVnZwfNrugajEMqi Signed-off-by: Claude <noreply@anthropic.com>
9 tasks done
lucasbraum
pushed a commit
that referenced
this pull request
Oct 7, 2026
main is this branch's base (#38, squash-merged) plus #40: the result keeps this branch's tree and applies #40's changes on top. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B2T8GmEVnZwfNrugajEMqi Signed-off-by: Claude <noreply@anthropic.com>
Merged
lucasbraum
pushed a commit
that referenced
this pull request
Oct 8, 2026
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and publish to npm yourself or [setup this action to publish automatically](https://github.com/changesets/action#with-publishing). If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## uptide@0.5.0 ### Minor Changes - [#39](#39) [`b9f9974`](b9f9974) Thanks [@lucasbraum](https://github.com/lucasbraum)! - A verified migration pack for the AI SDK (`ai`) 6 → 7: the renamed options (`system` → `instructions`, `onFinish` → `onEnd`, `onStepFinish` → `onStepEnd`, `experimental_telemetry` → `telemetry`), `stepCountIs` → `isStepCount`, `fullStream` → `stream`, `totalUsage` → `usage` and the removed `experimental_*` options are rewritten by rule; telemetry `metadata`, tool `context` and the stream result helpers go to the agent with the guide; what the compiler cannot see (telemetry registration, results that now cover every step, rejected system messages) is listed for review. Scored against vercel/chatbot and miurla/morphic at the commit before their own upgrade: no false positive. `uptide pack test` gains `--update-fixtures`, fixture markers take the compiler's `message`, and ground-truth repositories can use bun. - [#39](#39) [`b9f9974`](b9f9974) Thanks [@lucasbraum](https://github.com/lucasbraum)! - `check` and `fix` upgrade a package together with the packages that must move with it, using the groups `list` already draws (family, peer link, shared pin), each at the version that agrees with the target. `fix ai` also bumps `@ai-sdk/react`, `@ai-sdk/provider` and the installed `@ai-sdk/*` providers in one install and one commit; check's plan, the fix summary and the PR description say which and why, and `fix` stops before changing anything when a member has no release that agrees. npm and pnpm installs resolve the exact version first, so a `^` range keeps the version the target pins. Ground-truth entries take `with`, the packages the real upgrade moved, and `pack test` fails when check would leave one behind. - [#38](#38) [`adaf8f9`](adaf8f9) Thanks [@lucasbraum](https://github.com/lucasbraum)! - Migration packs are a public, testable contract (docs/packs.md). `uptide pack new` scaffolds a pack (an example rule, a fixture pair, a test, empty ground truth) and registers it; `uptide pack test` scores packs against their fixtures and against public repositories at the commit before their upgrade, with precision and recall per rule, every false positive and false negative, and `--json` for CI. A pack is labeled verified only with ground truth from at least two public repositories and no false positive among its breaking findings; otherwise it ships as a candidate and `check`, `list` and `fix` treat the dependency as generic. ### Patch Changes - [#44](#44) [`b4cc21f`](b4cc21f) Thanks [@lucasbraum](https://github.com/lucasbraum)! - `check` no longer dies with "Manipulation error: A syntax error was inserted." on packages whose type aliases give their type parameters defaults (`type-fest` 4 → 5, `i18next` 23 → 26): the alias body is read after the parameter list, not at the first default's ` = `, so these aliases are compared by the checker instead of breaking the comparison program. - [#40](#40) [`3e3a5fa`](3e3a5fa) Thanks [@lucasbraum](https://github.com/lucasbraum)! - `fix` verifies with the repository's own TypeScript (its `node_modules/typescript`, or an ancestor's) or the bundled one, and never with a TypeScript that `NODE_PATH` or Node's global folders happen to provide. A machine with a global TypeScript 6 made verification report TS5107 deprecations the repository never sees. - [#37](#37) [`3e7f744`](3e7f744) Thanks [@lucasbraum](https://github.com/lucasbraum)! - Gemini is labelled experimental: in `fix --help`, in the `LLM:` line `fix` prints, and in the docs. Its evaluation runs on the storefront fixture failed on service errors (HTTP 503/429), so its migration quality is not established yet. Co-authored-by: uptide-release[bot] <338861287+uptide-release[bot]@users.noreply.github.com>
7 tasks done
lucasbraum
added a commit
that referenced
this pull request
Oct 8, 2026
…y as fallback (#48) ## What and why `check`'s compile signal judged every repository with the TypeScript ts-morph bundles (6.0.2), whatever the repository installs. A repository on TypeScript 4.9 was read by TypeScript 6's rules and its error positions: a JSX child "not assignable to ReactNode" sits on the element's first line in 4.9 and on the child in 6, which alone accounted for 7 of the react pack's 11 remaining false positives in excalidraw. `check` now compiles with the repository's own TypeScript, found the way `fix`'s verification has found it since #40 (`node_modules/typescript` in the workspace or the nearest ancestor, never `NODE_PATH` or a global folder), and falls back to the bundled compiler only when the repository installs none. The coverage line says which one judged: ``` compiled 11 of 11 files in 2 workspaces with the repo's TypeScript 5.9.3 compiled 355 of 356 files in 5 workspaces with the repo's TypeScript 4.9.4 and 5.4.5 ``` How: - `adapters/typescript/compiler.ts` holds the resolver (moved from `fix/verify.ts`, same behavior, same tests) plus `repositoryCompiler` (loaded once per install directory) and `describeCompiler`. - With the repository's compiler, a baseline program is built once per workspace from the ts-morph program's root files and the options that compiler reads from the tsconfig (an option a newer compiler dropped or defaults differently is the repository's compiler's to read), with the same workspace-source `paths`; the overlay shares that baseline. With the bundled compiler the ts-morph program stays the baseline, as before. Signal A (usages) still runs on ts-morph. - The host resolver is installed both ways compilers ask: `resolveModuleNameLiterals` (TypeScript 5+) and `resolveModuleNames` (TypeScript 4). - The cause tracers take the compiler with the programs: node kinds and enum flags are the judging compiler's, not the bundled one's. - `CompileCoverage.compilers` records which compiler judged, merged across workspaces (one entry per distinct version); `coverageLine` prints it. - Found on the way: a workspace without a tsconfig of its own (excalidraw-app, covered by the root's `include`) got synthetic options. The bundled compiler's defaults papered over that (esModuleInterop, JSX); TypeScript 4.9 did not, and every default import and JSX element in that workspace errored at the target. Both programs now read the nearest ancestor tsconfig's options (never its file list) when the workspace has none. This also lifted excalidraw's coverage from 355 of 356 to 358 of 358 (the `with-script-in-browser` example resolves its imports now). - Security and privacy text: SECURITY.md, the CONTRIBUTING.md rules, the README privacy section and the CLI's `--help` privacy statement (kept word for word with the README) now say that `check` and `verify` load the `typescript` package the repository installs, resolved from its `node_modules`, to compile with, and never run the repository's scripts or other code outside `fix`'s verification step. Cost: a repository with its own TypeScript is parsed twice (ts-morph for Signal A, its compiler for Signal B). The react pack test went from about 12 to 9 minutes anyway, since the baseline is built once per workspace and shared. ## How it was verified New tests: `fix/compiler.test.ts` (compiler naming, bundled fallback, one load per install directory), `check/verdict.test.ts` (coverage line with one, several and mixed compilers), `check/check.test.ts` (compilers merged across workspaces), `adapters/typescript/compile.test.ts` (coverage names this repository's own TypeScript 5.9.3, which the fixture finds above it), `adapters/typescript/repo-inherited.test.ts` (inherited tsconfig options, own file list). `config-cause.test.ts` passes the compiler. The whole suite runs the overlay through the native path, since the fixtures sit under this repository's TypeScript. `pnpm lint && pnpm typecheck && pnpm test` pass (core 900 tests, cli 346). Storefront (`fixtures/repos/storefront`, built CLI): findings, counts and verdicts identical to main; only the coverage lines changed, to `compiled 11 of 11 files in 2 workspaces with the repo's TypeScript 5.9.3` and `compiled 7 of 7 files in 1 workspace with the repo's TypeScript 5.9.3`. README sample updated accordingly. Pack tests, before (main, same commit as #46's final numbers) and after, breaking findings: | pack | before | after | |---|---|---| | react (#45's pack, uncommitted here) | 88% precision / 64% recall, 11 FP, 46 FN | **96% / 69%, 4 FP, 40 FN** | | zod | 100% / 71% | 100% / 71%, identical | | stripe | 100% / 90% on 3 repos | 100% / 90%, identical | | ai | 100% / 36% | 100% / 36%, identical | react per repo: excalidraw 9 FP → 2 (predicted 61, expected 73), tldraw unchanged at 9 FP / 26 FN. The 6 "TS 6 vs 4.9 location" false positives in `packages/excalidraw` are gone, as is the `with-script-in-browser` one. The 4 remaining breaking false positives: `dev-docs/.../Homepage/index.tsx:52` (TS2322 at a JSX child in a workspace on the root's 4.9, same shape as before), `tldraw apps/docs/components/content/index.tsx:18` (`next-mdx-remote-client/rsc` after the companion move), and the two `useTransform(rSvg)` single-site-per-workspace `ref-object-nullable` findings. The other 7 of the 11 are deprecated or unverified, never counted as breaking. These go to #45. ## Checklist - [x] Tests for the change (a bug fix starts with a failing test) - [x] `pnpm lint && pnpm typecheck && pnpm test` pass - [x] README and docs updated if behavior changed - [x] Changeset added if a user would notice (`pnpm changeset`) - [x] No new dependency, or it was agreed in an issue - [x] No private code, names or paths in fixtures, tests or docs - [x] The rules in CONTRIBUTING.md ("Rules that do not bend") still hold 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_018u9b3Pp5H68DdYZGp5Qg1U --------- Signed-off-by: Lucas Braum <lucas.braum@deskfy.io> Co-authored-by: Lucas Braum <lucas.braum@deskfy.io> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.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.
What and why
Two tests failed in a cloud container, which runs as root with
NODE_PATHset, but not in CI. CI onmainis green. The latest run on 3e7f744 (#37) passed, and the last red run onmainwas 089f7b9 (#34), already followed by green runs. So no merge let a redmainthrough. Both failures were environment-dependent: CI passes them by accident rather than by design.fix.test.ts› checks workspace source under its own resolution mode — a code bug.resolveCompilerloadedtypescriptwithcreateRequire(...), and Node's resolution also searchesNODE_PATHand the global folders. In the containerNODE_PATHholds a global TypeScript 6.0.2, so a repository without its own compiler was verified with TS 6, which reports TS5107 (moduleResolution: node10deprecated). In CINODE_PATHis unset and the bundled 5.9 compiler is used, so the test passes there. The same thing would happen to any user with a global TypeScript onNODE_PATH. NowconsumerCompilerDirtakesnode_modules/typescriptfrom the repository or the nearest ancestor that has one, else the bundled compiler.cli.test.ts› uptide verify › ends with the summary and the next commands — a test bug.fixReport()setprBody: '/repo/.uptide/pr-body.md', andfixwritesreport.htmlnext to the stored run. On a CI runner (non-root) creating/repofails silently, so the engine'shtmlpath survives. As root the write succeeds, replaceshtml, the assertion fails, and/repo/.uptide/is left behind. Now each report gets a fresh temporary directory. The test asserts the absolute path of its own stored run outside the working directory. One formatter assertion now matches its line regardless of column padding, since the padding depends on path lengths.No test was skipped.
How it was verified
compiler.test.tscases: a workspace finds the root'snode_modules/typescript; a repository without TypeScript gets the bundled compiler. The second case fails on the oldresolveCompilerin the container (where it got the global 6.0.2) and passes now.NODE_PATHand runs as root: core 852 passed (3 files skipped, as before), CLI 343/343,pnpm lintandpnpm typecheckclean./repo/.uptide/report.htmlkept its old timestamp across the CLI run, so nothing writes there anymore.Checklist
pnpm lint && pnpm typecheck && pnpm testpass.changeset/consumer-compiler-only.md, patch)🤖 Generated with Claude Code
https://claude.ai/code/session_01B2T8GmEVnZwfNrugajEMqi
Generated by Claude Code