Skip to content

feat(packs): candidate typescript 5 to 6 pack, judged by the target compiler (UPT-56) - #150

Merged
lucasbraum merged 9 commits into
mainfrom
lucasbraum/upt-56-pack-typescript-5-6
Oct 15, 2026
Merged

lucasbraum merged 9 commits into
mainfrom
lucasbraum/upt-56-pack-typescript-5-6

Conversation

@lucasbraum

@lucasbraum lucasbraum commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Pack

typescript >=5 <6 → >=6 <7 (default 6.0.3), for UPT-56. Candidate, by choice: under today's gate the run measures verified (7 public repositories, 0 breaking false positives). The stricter gate (UPT-48) is landing separately, so verification.json keeps its candidate record until this branch is rebased on UPT-48 and re-scored with --write.

The upgraded package is the compiler itself, so this also changes the engine. How check resolves the compiler for this upgrade:

  • Installed side: the repository's own node_modules/typescript, the nearest one from the workspace up.
  • Target side: the typescript copy check fetched at the target, the release fix installs, loaded from that directory.
  • Never the bundled compiler (ts-morph's 6.0.2). With no TypeScript installed, the compile is skipped and the report says why. A target with no JavaScript API (TypeScript 7) is skipped and named the same way.
  • What is compiled: every project of the workspace (its tsconfig, its references, every nested tsconfig.json), all files, not only importers of typescript. The coverage line names both compilers: "compiled 13 of 13 files … with the repo's TypeScript 5.9.3 and 6.0.3".
  • tsconfig diagnostics (TS5101/TS5107/TS5011) are pack findings from the inventory, reported in the file that sets the option, not compile findings. So the UPT-49 project scope (fix(check): respect TypeScript project compile scope (UPT-49) #138) does not drop them. packs/typescript/check.test.ts pins this with a tsconfig outside every include.

Engine changes, in their own commit:

  • compileCompilerUpgrade in adapters/typescript/compile.ts.
  • loadCompiler drops Node's cached module when the version on disk changed, and the compiler cache is keyed by version. Without this, fix would verify a TypeScript 6 install with the 5.x module loaded earlier from the same path.
  • A workspace that imports nothing is still checked when a named pack's inventory matches.
  • companionsOf reports a peer conflict even when list does not group the peer with the lead. Before, @typescript-eslint/parser 8.56.0 (typescript <6.0.0) was planned as a conflict and then dropped from the report; it is now listed as possible impact and left where it is.
  • packs:truth:
    • reads tsconfig*.json in the upgrade diff and lists tsconfig option errors;
    • anchors insertions in JSON;
    • loads the linked target compiler by its real path. Node's cached resolution kept handing back the installed 5.x, so the first drafts silently compiled 5.x twice.

Sources

Read 2026-10-14, pinned in RESEARCH.md: the TypeScript 6.0 release notes (TypeScript-Website 119f931), Announcing TypeScript 6.0 (2026-03-23), Announcing TypeScript 7.0 (2026-07-08), and tags v5.9.3 / v6.0.3. Every diagnostic code was read from 6.0.3 itself.

Range decision: two packs. 6.0 deprecates (errors unless ignoreDeprecations: "6.0" is set) what 7.0 removes. packs/queue.json gets 5 → 6 (candidate) and 6 → 7, blocked: typescript@7.0.2 exports no compiler API (a new one is planned for 7.1).

Rules and behavior notes

Mechanical, each with an exact replacement from the notes and unchanged behavior:

  • downlevel-iteration: removes the line. Declined with an ES3/ES5 target, with ignoreDeprecations set, or when the property shares its line.
  • module-keyword: TS1540, module Foo { → namespace Foo {. Declined for a quoted ambient module.
  • import-assertions: TS2880, assert { → with {. Declined unless { or : follows.

Assisted, reported where set, with a guide:

  • base-url: the paths rewrite is exact, but bare-import lookup and bundlers that read baseUrl can change.
  • module-resolution-node10, module-resolution-classic: bundler vs nodenext is the owner's call.
  • target-es5, module-format-removed, out-file, interop-false, always-strict-false: each changes emit.
  • root-dir: TS5011 at outDir when include is one directory and rootDir is unset.

Behavior note changed-defaults (a decision): lists, per tsconfig, the 6.0 defaults it leaves unset through in-repo extends (strict, types, noUncheckedSideEffectImports). The owner pins or keeps each. Defaults are not pinned by rule: a static pin would hit every tsconfig that leaves them unset, and most of those compile cleanly. The code errors those defaults cause are the compiler's findings.

requiresBuild: true. The instructions forbid any, @ts-ignore/@ts-expect-error/@ts-nocheck, ignoreDeprecations, skipLibCheck and loosening strictness.

Ground-truth repositories

Committed in 2699e8c, the first commit of this branch, before the first scoring run; nothing was changed after scoring. Drafted with pnpm packs:truth (6.0.3 on every tsconfig.json, plus the upgrade diff), then assigned by hand.

Repository Before Upgrade Expected
m-lyon/recipe (client/) f6e44b5 (5.6.2) pull request 113 (merged) 1
robrechtme/recipes 0853747 pull request 7 (merged) 2
JosephMaynard/dependency-radar 1920eb3 pull request 46 (merged) 116
CroffZ/github-release-notifier d9353f2 pull request 5 (merged) 12
SignalK/signalk-derived-data 02f635e pull request 239 (merged) 418
shogo82148/typescript-action 0f03405 pull request 487 (merged) 3
Borewit/music-metadata 783509b pull request 2661 (merged) 851

Most expected sites are generic compiler sites, which mostly come from the types: [] and strict defaults.

uptide pack test output

uptide pack test typescript · verified, recorded candidate
fixtures      7 cases, 14 sites · pass
ground truth
  m-lyon/recipe@f6e44b530c4d                   typescript 5.6.2 → 6.0.3  predicted 1, expected 1, false positives 0, false negatives 0
  robrechtme/recipes@0853747427b7              typescript 5.9.3 → 6.0.3  predicted 2, expected 2, false positives 0, false negatives 0
  JosephMaynard/dependency-radar@1920eb3217b7  typescript 5.9.3 → 6.0.3  predicted 115, expected 116, false positives 0, false negatives 1
  CroffZ/github-release-notifier@d9353f2471c5  typescript 5.9.3 → 6.0.3  predicted 11, expected 12, false positives 0, false negatives 1
  SignalK/signalk-derived-data@02f635e8232a    typescript 5.9.3 → 6.0.3  predicted 417, expected 418, false positives 0, false negatives 1
  shogo82148/typescript-action@0f03405c7267    typescript 5.9.3 → 6.0.3  predicted 2, expected 3, false positives 0, false negatives 1
  Borewit/music-metadata@783509b27bac          typescript 5.9.3 → 6.0.3  predicted 831, expected 851, false positives 0, false negatives 20

  rule                         precision  recall    tp   fp   fn
  base-url                          100%    100%     4    0    0
  changed-defaults                   n/a      0%     0    0    4
  generic                           100%     99%  1371    0   18
  module-resolution-node10          100%     67%     2    0    1
  root-dir                          100%     50%     1    0    1
  target-es5                        100%    100%     1    0    0
  overall (sites)                   100%     98%  1379    0   24
  behavior notes (sites)             n/a      0%     0    0    4
  breaking (sites)                  100%     99%  1379    0   20

It exits 1 only because verification.json still holds the candidate record, which is the point. The 24 false negatives are explained in RESEARCH.md:

  • 18 second-round Borewit lines (17 tightened test lines and a TS6385 deprecation);
  • 2 same-change tsconfig lines no rule predicts;
  • 4 changed-defaults decision sites, which are behavior-only, not missed breaks.

Under UPT-48 as specified:

  • 7 repositories and 1,399 expected breaking sites: both meet the minimums.
  • Real-world true positives per rule: base-url 4, module-resolution-node10 2, target-es5 1, root-dir 1.
  • The three mechanical rewrites met no real site. They become unexercised and run as assisted; their only evidence is the fixtures.

Checklist

  • Every rule and note comes from a source listed in meta.sources
  • Every rule that rewrites or detects has a fixture case, with a site it must leave alone (keep): 7 cases, 14 sites
  • Ground truth: public repositories at the commit before their upgrade; expected findings read from their own upgrade commit and the compiler, never copied from Uptide's output
  • At least two public repositories for verified: 7, held at candidate until UPT-48
  • verification.json written with --write: deliberately not yet, after the rebase on UPT-48
  • pnpm lint && pnpm typecheck && pnpm test pass locally (1,731 core and 454 CLI tests)
  • Changeset added
  • No private code, names or paths: fixtures are synthetic, ground truth is public

To check before merge:

🤖 Generated with Claude Code

@lucasbraum
lucasbraum force-pushed the lucasbraum/upt-56-pack-typescript-5-6 branch from fd8ba58 to 7a768e7 Compare October 15, 2026 06:09
@lucasbraum

Copy link
Copy Markdown
Collaborator Author

Rebased on main after #138 (UPT-49). Both behaviors kept:

  • compileCompilerUpgrade now takes its projects from fix(check): respect TypeScript project compile scope (UPT-49) #138's projectScope, and a compiler diagnostic counts only in a file a project covers.
  • Pack findings in tsconfig files are never scoped. The new check test pins an extended base config outside every include, in an excluded directory, still reported. The network test pins an uncovered file's compiler error dropped.
  • The target compiler is still loaded by real path in loadCompiler and packs:truth.

Focused tests pass (69, including #138's scope tests and the 6.0.3 network test), as does typecheck.

Left as draft on purpose: the re-score now has 14 false positives, all in shogo82148/typescript-action __tests__/. #138's scope also compiles tsconfig.eslint.json, and packs:truth only reads tsconfig.json. The errors are real 6.0 errors (jest globals under types: []); that repo's upgrade added types: ["jest", "node"] there. Fixing the ground-truth method after scoring is a maintainer call, so it is recorded in RESEARCH.md, not done. verification.json stays candidate.

lucasbraum added a commit that referenced this pull request Oct 15, 2026
After UPT-49 (#138) check compiles every project of the TypeScript project
scope, tsconfig*.json included, while packs:truth still compiled tsconfig.json
alone. #150's Pack test failed on that gap: 14 breaking false positives in
shogo82148/typescript-action __tests__, type-checked through
tsconfig.eslint.json (its jest.config.js runs ts-jest with it), where the
repository's own upgrade added types ["jest", "node"].

packs:truth now drafts on projectScope, the same project list check uses.
All seven typescript repositories were redrafted with it, before re-scoring:
shogo gains those 14 compiler sites under generic; the other new diagnostics
are inherited options on newly compiled leaf configs (signalk
tsconfig.build.json, Borewit lib/tsconfig.prod.json), expected where the
option is set as before. Nothing else changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lucas Braum <lucasbraum@gmail.com>
@lucasbraum

Copy link
Copy Markdown
Collaborator Author

Pack test failure after the #138 rebase (run 38690803983, pack-test.json):

  • Failing pack: typescript, the only failure.
  • Not an overclaim (recorded candidate) and not with/blocker (problems: []).
  • Score: 14 breaking false positives in shogo82148/typescript-action __tests__/.

#138's scope compiles tsconfig.eslint.json. packs:truth only read tsconfig.json, so the truth missed real 6.0 errors there: ts-jest type-checks the tests with that config, and the repo's upgrade added types: ["jest", "node"] to it.

Fixed in this PR (d0e6092): packs:truth now drafts on projectScope, the same projects check compiles. All seven repos were redrafted before re-scoring; only shogo gains sites (those 14). Re-score: PASS, 0 FP, breaking recall 99% (1393/1413). It measures verified; the record stays candidate by choice.

@lucasbraum

Copy link
Copy Markdown
Collaborator Author

Reverted the ground-truth redraft (f07cdaa): ground-truth.json is back to the original commit d128198. The packs:truth scope change stays, for future packs only.

Engine fix (26d4be7):

  • The typescript pack's new foldFindings hook folds errors from the 6.0 types: [] default into one changed-defaults finding at the covering tsconfig that leaves types unset, as fix(check): fold implicit-any errors inside a removed option into its pack finding #136 does for TS7006 cascades.
  • Folded: TS2580–2593 "install type definitions" errors, and TS2304/TS2503 for a global declared by an @types package that 5.x included automatically.
  • Tested on the shogo shape (14 test errors → one finding at tsconfig.eslint.json) and the Borewit shape.

Re-score on the original truth: PASS, 0 breaking FP. Two trade-offs, in RESEARCH.md:

  • The anchor uses the note's severity (deprecated). A breaking anchor would be a breaking FP where the truth has no site for that edit, e.g. dependency-radar.
  • Breaking recall drops to 17%: 1,159 truth lines (one per error) are now evidence of one tsconfig finding each. There are also 8 non-breaking changed-defaults FPs, because the anchor line (the config's root {) differs from the diff-shaped truth lines.

@lucasbraum
lucasbraum marked this pull request as ready for review October 15, 2026 16:08
lucasbraum and others added 9 commits October 15, 2026 09:10
…T-56)

Seven public repositories at the commit before their TypeScript 6.0.3 upgrade,
drafted with packs:truth (the target compiler on every tsconfig.json, and the
upgrade commit) and assigned by rule before the pack was scored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lucas Braum <lucasbraum@gmail.com>
…r (UPT-56)

When the upgraded package is `typescript`, no overlay can swap it: it judges
every file. compileCompilerUpgrade compiles each project of the workspace (its
tsconfig, references, nested tsconfig.json) with the installed TypeScript and
with the target's, loaded from the copy check fetched; new diagnostics are the
findings. The bundled compiler never stands in, and a target without a
JavaScript API (TypeScript 7) is reported as not compiled.

- loadCompiler drops Node's cached module when the version on disk changed,
  and the compiler cache is keyed by version, so fix verifies with the
  TypeScript it just installed at the same path.
- A workspace that imports nothing is still checked when a named pack's
  inventory matches; resolvePackageDir finds a package nothing imports.
- companionsOf reports a peer conflict even when list does not group the
  peer with the lead (typescript-eslint on typescript).
- packs:truth reads tsconfig*.json in the upgrade diff, lists tsconfig option
  errors, anchors insertions in JSON, and loads the linked target compiler by
  its real path instead of Node's cached resolution.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lucas Braum <lucasbraum@gmail.com>
Tsconfig options 6.0 deprecates, reported where they are set (baseUrl,
moduleResolution node and classic, target es5, legacy module formats, outFile,
downlevelIteration, interop and alwaysStrict false), the rootDir default,
module-keyword namespaces and import assertions; changed defaults as a
decision. Code errors come from check's compile with the target compiler.

Scored against seven public upgrades fixed before scoring: 0 false positives,
breaking recall 99% (1379 of 1399). Held as a candidate until the stricter
verified gate (UPT-48) lands; RESEARCH.md has the evidence and the limits.
packs/queue.json gains the 5 to 6 entry and 6 to 7, blocked on TypeScript 7's
missing JavaScript API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lucas Braum <lucasbraum@gmail.com>
…PT-49 (UPT-56)

compileCompilerUpgrade now takes its projects from #138's projectScope and
counts a compiler diagnostic only in a file a project covers, as for any
package. Pack findings in tsconfig files are not compiler diagnostics: the
check test pins an extended base config outside every include, in an
excluded directory, still reported. The network test pins an uncovered file's
compiler error dropped. Docs and RESEARCH.md say so; the re-score on the new
scope and its 14 open false positives are recorded there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lucas Braum <lucasbraum@gmail.com>
After UPT-49 (#138) check compiles every project of the TypeScript project
scope, tsconfig*.json included, while packs:truth still compiled tsconfig.json
alone. #150's Pack test failed on that gap: 14 breaking false positives in
shogo82148/typescript-action __tests__, type-checked through
tsconfig.eslint.json (its jest.config.js runs ts-jest with it), where the
repository's own upgrade added types ["jest", "node"].

packs:truth now drafts on projectScope, the same project list check uses.
All seven typescript repositories were redrafted with it, before re-scoring:
shogo gains those 14 compiler sites under generic; the other new diagnostics
are inherited options on newly compiled leaf configs (signalk
tsconfig.build.json, Borewit lib/tsconfig.prod.json), expected where the
option is set as before. Nothing else changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lucas Braum <lucasbraum@gmail.com>
…roject scope (UPT-56)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lucas Braum <lucasbraum@gmail.com>
The ground truth was committed before scoring and does not change to make a
run pass, even under a uniform method. ground-truth.json is back to its
original commit (d128198). The packs:truth change (draft on the same project
scope as check) stays, for packs drafted from now on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lucas Braum <lucasbraum@gmail.com>
…g finding (UPT-56)

A person fixes the 6.0 `types: []` default with one line in a tsconfig, not at
each use: shogo82148/typescript-action added "types": ["jest", "node"] to
tsconfig.eslint.json, and its 14 describe/it/expect errors went with it. As
#136 folds implicit-any cascades into their option, the typescript pack's new
foldFindings hook (fold.ts) folds TS2580-2593 "install type definitions"
errors, and TS2304/TS2503 for a global an @types package 5.x included
declares, into one changed-defaults finding at the covering project that
leaves `types` unset, as anchorOnly evidence.

- MigrationPack/definePack gain foldFindings; check runs it after option
  cascades. A note reported as a finding may come from it instead of detect.
- The finding carries the note's severity (deprecated): a breaking anchor
  would be a breaking false positive where the original truth has no site for
  that tsconfig edit.
- Tested on the shogo shape and on Borewit's (a nearer project that lists its
  types inside a root that does not).

Re-scored on the original ground truth: 0 breaking false positives, PASS;
breaking recall 17%, since 1,159 truth lines are now evidence of one tsconfig
finding each (RESEARCH.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lucas Braum <lucasbraum@gmail.com>
…e (UPT-56)

The record carries the gate's fields as pack test measures them on the
current ground truth: class breaking, 1,399 real breaking sites, 4
behavior-note sites, and three unexercised rewrites (downlevel-iteration,
import-assertions, module-keyword). It stays candidate by choice: the run
measures verified (0 breaking false positives, recall 17%), and promoting
it is the maintainer's call. README table regenerated with docs:packs; the
registry is what renderRegistry produces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lucas Braum <lucasbraum@gmail.com>
@lucasbraum
lucasbraum force-pushed the lucasbraum/upt-56-pack-typescript-5-6 branch from 26d4be7 to 8b91752 Compare October 15, 2026 16:13
@lucasbraum

Copy link
Copy Markdown
Collaborator Author

Rebased on main after #155 (force-pushed with lease from 26d4be7). The only conflict was the generated README table: I took main's README and regenerated the table with pnpm docs:packs. The registry already matched renderRegistry, so it is unchanged. 8b91752 writes the typescript record from a fresh pack test: class breaking, 1,399 real breaking sites, 4 behavior-note sites, and downlevel-iteration, import-assertions, module-keyword unexercised (assisted). It stays candidate by choice, although the run measures verified (0 breaking false positives, recall 17%). Focused tests pass, apart from the local-only scaffold.test formatted check.

@lucasbraum
lucasbraum merged commit 4c3212b into main Oct 15, 2026
9 of 10 checks passed
@lucasbraum
lucasbraum deleted the lucasbraum/upt-56-pack-typescript-5-6 branch October 15, 2026 16:15
@uptide-release uptide-release Bot mentioned this pull request Oct 15, 2026
lucasbraum pushed a commit that referenced this pull request Oct 15, 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.13.0

### Minor Changes

- [#134](#134)
[`b795705`](b795705)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Packs can name
alternate leads: packages a repository declares instead of the pack's
own (`react-router-dom` for `react-router`). `check` and `fix` asked for
either name use the pack; where only the alternate is declared, the lead
is analyzed at the version installed through it, pnpm stores included,
and `fix` declares it beside the alternate at the target before
upgrading both.

- [#149](#149)
[`3303118`](3303118)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Add a candidate
express 4 to 5 migration pack. Route strings that path-to-regexp 8
rejects or reads differently are found on calls of an Express app or
router (including lists registered in a loop); `req.params` values
widened to `string | string[]`, `req.param`, `res.sendfile`,
`express.static.mime` and `express.query` are claimed from the compiler;
`res.redirect(url, status)`, `app.param(fn)`, `res.redirect('back')` and
`res.send(<number>)` are found in the source; runtime defaults (async
errors, `req.body`, the query parser, `urlencoded`, dotfiles, Node 18)
go to decisions. No rule rewrites. With the pack in use, `check` no
longer adds its text-matched express 5 runtime findings.

- [#148](#148)
[`5143c46`](5143c46)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Add a candidate
joi 17 to 18 migration pack. `new ValidationError(message, {},
original)`, which stops compiling for code written against joi
17.0–17.6, is rewritten to pass `[]`; the Node.js 20 requirement and the
top-level domains joi 18 no longer accepts in `email()`, `domain()` and
`uri()` are reported as decisions. Scored against two public
repositories, one of them a negative control.

- [#131](#131)
[`413d3da`](413d3da)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Add a verified
lucide-react 0.x to 1.x migration pack. Brand icons removed in 1.x are
found at their imports and every use, with a guide whose replacement
choice goes to the owner; icon names dropped during 0.x are renamed at
the import or member; deep `dist/` imports, untyped icon lookups, the
`absoluteStrokeWidth` and `IconNode` deprecations, and the `aria-hidden`
default for repositories before 0.489.0 are reported. Lucide's lockstep
packages move together and the consumer's build is required. Verified
against three public repositories, one of them a negative control.

- [#132](#132)
[`107c107`](107c107)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Add a verified
React Router 6 → 7 migration pack, which also runs for applications that
declare only `react-router-dom`. It moves `react-router-dom` imports to
`react-router`. It reports, with a guide for the agent, the rest of the
upgrade: the removed `future` prop and router option,
`react-router-dom/server`, lowercase `formMethod` comparisons and
`json`/`defer` calls (found by syntax where the compiler is blind), the
other removed exports, and `generatePath` calls that pass `null` for a
required parameter. The six v6 future flags that become defaults are
reported as decisions where the repository's router setup has not
enabled them. React Router 7 → 8 is a separate upgrade.

- [#142](#142)
[`9c57934`](9c57934)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `check` and `fix`
plan what the target version requires: a package the target, or anything
moving with it, declares as a peer or dependency at a range the
installed copy rejects moves to the lowest release of its major that
satisfies it (openai 7 moves zod 3.24.2 to 3.25.0), shown apart from
release-group companions ("moved because openai 7.4.0 requires zod ^3.25
|| ^4.0"). A move only a new major makes is never made: it is reported
as a blocker with the exact range in `check`, the PR body and `pack
test`. The npm install scope guard no longer lets a declared root
dependency change because a moved package peers on it.

- [#128](#128)
[`06f11ab`](06f11ab)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Add verified
Sentry JavaScript SDK 10 to 11 migration packs for `@sentry/nextjs` and
`@sentry/browser`, with the SDK's lockstep release group, a required
build for Next.js, and inventory-scoped decisions for data collection,
span streaming, sampling and platform minimums. Mechanical rules move
`withSentryConfig` to `@sentry/nextjs/config` and the removed build
options under `webpack`, remove `enableLogs`/`enableMetrics: true`, and
rename exports, integration names and `httpIntegration` options;
privacy, sampling, profiling and OpenTelemetry choices stay assisted and
are reported for the owner. Fix `uptide pack new` dropping registry
entries long enough to be wrapped.

- [#155](#155)
[`922c5ab`](922c5ab)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `uptide pack
test` applies a stricter verified gate: at least five expected breaking
sites across the public ground-truth repositories, besides two
repositories and no breaking false positive. Upgrades the compiler
cannot see are gated on their behavior notes instead. Mechanical rules
no real site exercises are recorded as unexercised, and `check` and
`fix` run their sites as assisted. `@sentry/browser` and `@sentry/react`
become candidates (fewer than five real breaking sites). A pack can
lower the minimum only with a written reason in its RESEARCH.md. The
README packs table shows each pack's breaking-site count. The output
shows the gate's class, site counts and every reason a pack is a
candidate.

- [#147](#147)
[`0b88170`](0b88170)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `check` and `fix`
remove a deprecated `@types` stub instead of upgrading to it. When the
release the upgrade would move `@types/<pkg>` to is deprecated on npm,
and `<pkg>`'s target declares its own types (`types`, `typings` or a
`types` export), the plan removes it: "Removed: @types/ioredis, ioredis
5 ships its own types", in `check` and in the PR body. `check` now diffs
such a package against its own target types instead of failing on a stub
with no declarations, and `fix` removes the entry in the same install,
with the install scope guard allowing exactly that removal.

- [#150](#150)
[`4c3212b`](4c3212b)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `check
typescript` judges a TypeScript 5 to 6 upgrade with both compilers:
every project of the workspace is compiled with the installed TypeScript
and with the target's, and what is new at the target is a finding; the
bundled compiler never stands in, and a target without a JavaScript API
(TypeScript 7) is reported as not compiled. A candidate typescript 5 to
6 pack reports the tsconfig options 6.0 deprecates where they are set,
the rootDir default, module-keyword namespaces and import assertions. A
peer that rejects the target (typescript-eslint on TypeScript 6) is now
reported as a peer conflict even when it is not grouped with the
package.

- [#137](#137)
[`21894d7`](21894d7)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Add
`verify.build` to uptide.yml: the package.json script a migration pack's
required build runs. Unset, Uptide runs `build:ci`, then `build-ci`,
then `build`. When a build fails before the framework's build starts
because it needs an environment variable or a database (`prisma db push`
without `DATABASE_URL`), the pull request and the report say so ("build
needs DATABASE_URL; set verify.build") instead of a bare "build failed".
`uptide init` writes the setting as a comment.

### Patch Changes

- [#141](#141)
[`9debb6d`](9debb6d)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `check` no longer
reports a pre-existing type error as a breaking site when the upgrade
only changes its wording, such as a type the message prints in full. An
error at the same place with a different reason is still reported.

- [#129](#129)
[`e796e4c`](e796e4c)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Add a candidate
ioredis 5 to 6 migration pack: client constructions that inherit the
RESP3, reconnect and keep-alive defaults ioredis 6 changed,
compiler-blind sites (`mode === 'subscriber'`, commands in a `connect`
listener with the offline queue off, AUTH recognized by command name),
dependents that bundle ioredis 5, instrumentation that stops patching
ioredis 6, and Node 20. It is scored against five public upgrades and
stays a candidate: none of them has a breaking site to verify it with.

- [#139](#139)
[`9ba005a`](9ba005a)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Allow local check
and fix smoke tests of registered candidate packs with
--allow-candidate, with an explicit unverified banner. Reject candidate
opt-in in the Action and with publication flags, and prevent stored
candidate runs from being published. Label pack-claimed assisted sites
by rule id even with --no-llm.

- [#157](#157)
[`f3af6a1`](f3af6a1)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `check` no longer
reports a blocker for a direct dependency whose plain dependency range
rejects the target (`@azure/ai-projects` on `openai ^6`, verdaccio
pinning express 4): the package manager gives it its own nested copy, so
it is listed as staying, with the new major that would accept the target
when there is one. `pack test` counts a `with` move that `check` leaves
and explains (a blocker, a new-major stay or a peer conflict) as
explained, and one of a package that does not depend on the lead as the
repository's choice; neither fails the run.

- [#130](#130)
[`5ced450`](5ced450)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Add a candidate
openai 4 to 7 migration pack: named path parameters, `del` → `delete`,
promoted beta chat helpers, renamed runner events, removed entry points
and request-option overloads are rewritten where unambiguous; tool-call
unions, `httpAgent`, `fileFromPath` and the other removals get agent
guides; `APIError.headers`, Web `Response` bodies and double-encoded
path ids are detected even in code typed `any`; Node 22, zod, fetch and
client-subclass decisions carry repository evidence. It stays a
candidate (the dependency is still checked and fixed as generic) until
two engine gaps its ground truth exposed are closed.

- [#136](#136)
[`578a042`](578a042)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Fold implicit-any
errors (TS7006, TS7031, TS7019) inside an option the target removed into
the pack finding on that option, as downstream evidence: the callbacks
lost the types the option gave them, and the same edit resolves them.
They no longer stand as separate breaking sites.

- [#143](#143)
[`883e587`](883e587)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `uptide pack
test` scores each expected site at the severity of the rule or behavior
note it belongs to, so a missed note that only needs a look, or a
decision, no longer counts as a missed break. Behavior-note sites get
their own precision and recall in the output and in `verification.json`
(`behavior`, with the counts behind each rate), false negatives show
their severity, and a rate with nothing to measure prints `n/a` instead
of 100%, in `pack test` and in the README's packs table.

- [#154](#154)
[`7aa3d58`](7aa3d58)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `uptide pack
test` fails a pack's `verification.json` only when it claims more than
the run measures (recorded verified, measured candidate). A pack
recorded as candidate on purpose passes, with `recorded candidate by
choice; measures verified`, and a record whose numbers differ gets a
note instead of a failure. A `generic` ground-truth site now counts as a
true positive for the rule that claims it.

- [#152](#152)
[`ca31aee`](ca31aee)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `uptide pack
test` takes several packs: `uptide pack test zod ai`.

- [#159](#159)
[`1e157fd`](1e157fd)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `uptide pack test
--json` times each ground-truth repository: `timing` gives the fetch,
install and check wall time and the process's peak memory.

- [#144](#144)
[`0881185`](0881185)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Ground truth can
name a site for an upgrade that only adds lines inside an existing call,
such as an option added to a constructor: the site is the call's start
line, so a pack finding there scores as a true positive instead of a
false positive. `pnpm packs:truth` drafts these anchors from insert-only
hunks for review, and docs/packs.md and CONTRIBUTING describe the rule.

- [#156](#156)
[`9039e3c`](9039e3c)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Public ground
truth now exercises three rules that ran as assisted: zod
`error-params`, stripe `api-version-unpinned` and next
`stable-cache-exports`. Their rewrites run mechanically again. All three
packs stay verified.

- [#138](#138)
[`0db5640`](0db5640)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Respect
repository tsconfig file selection, recursive project references, and
workspace project options when checking dependency upgrades. Compiler
diagnostics outside every TypeScript project no longer produce breaking
findings; pack rules and build-configuration findings retain their own
scope. Repositories without a tsconfig retain importer-based
compilation, with that fallback stated in the report.
  
Anchor missing members supplied by dependency augmentations at their
setup import, retaining affected calls as evidence instead of counting
each call as a separate breaking edit.

- [#151](#151)
[`9ddaaff`](9ddaaff)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Add a candidate
redis (node-redis) 4 to 5 and 5 to 6 migration pack, one rule set per
major: an upgrade gets the rules of the majors it crosses, so 4 to 6
gets both. 4 to 5 covers `legacyMode`, `commandOptions` and isolation,
scan iterators that yield batches, string SCAN cursors, boolean replies
that became numbers, enums that became constants, `keepAlive`,
`@redis/graph` and internal `dist` imports; 5 to 6 covers the RESP3
client type, `unstableResp3`, and the client defaults 6 changes (RESP3,
command timeout, keep-alive delay, maintenance notifications) with a
decision per client. Scored against five public upgrades; it stays a
candidate until the stricter verified gate lands, since the core 4 to 5
API changes have no real site yet.

- [#135](#135)
[`42a3b54`](42a3b54)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Move only
packages released with the upgraded one. A pack's declared release group
now bounds the lead's npm scope, and without one a same-scope package
moves only when a pin, a peer or a release at the target relates it to
the group. Packages of the scope that are versioned on their own
(`@sentry/vite-plugin` 5.x, `@sentry/cli`, the old `@sentry/utils` 8.x)
are reported as "stays at X" in `check`, the pull request and `pack
test` instead of making `fix` refuse the whole upgrade. Registers the
verified `@sentry/react` 10 to 11 pack.

- [#146](#146)
[`09b8682`](09b8682)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Report Stripe
clients pinned to different API versions at the top of `check` and of
the PR body, as a decision for the owner: every `new Stripe(...)` in
TypeScript and JavaScript sources, scripts included, with the version it
speaks after the upgrade (an unpinned client speaks the SDK default).
The PR's decisions list, for each client behind the target, the
changelog entries it would cross for the resources it calls. No pin is
rewritten.

- [#140](#140)
[`bc428d1`](bc428d1)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - Keep migration PR
bodies within their size budget while preserving summaries,
representative diffs, decisions, review warnings and verification ahead
of changelog and transitive detail. Keep every evidenced Stripe change
visible and uncapped; group and cap only other changes to used
resources, link the full changelog, and identify omitted text in the
retained report.

- [#145](#145)
[`3c8902d`](3c8902d)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - The zod pack
migrates `ZodError#errors` to `.issues` by rule: reads
(`error.errors[0].message`, `error?.errors`) and destructuring (`const {
errors } = error` becomes `const { issues: errors } = error`) where the
type checker resolves the receiver to `ZodError`, and reads off an
untyped catch binding of a zod parse. Writes are left to the agent.

- [#127](#127)
[`c4ead4f`](c4ead4f)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - zod: `check` now
reports `ZodError#formErrors` and `#errors` read off an untyped catch
binding of a zod `parse`/`parseAsync` (`catch (error: any) { return
error.formErrors.fieldErrors }`), which zod 4 removed and the compiler
cannot see. Files that only import a schema from the repository's own
module (`@/lib/zod`) are covered too. `fix` rewrites
`<err>.formErrors.fieldErrors` and `<err>.formErrors.formErrors` to
`z.flattenError(<err>)`, importing `z` where it is missing; every other
read goes to the agent.

Co-authored-by: uptide-release[bot] <338861287+uptide-release[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant