Skip to content

fix: keep an undeclared transitive the repo imports through the ERESOLVE retry (UPT-109) - #234

Merged
lucasbraum merged 1 commit into
mainfrom
lucasbraum/upt-109-keep-imported-transitive-deps
Oct 18, 2026
Merged

lucasbraum merged 1 commit into
mainfrom
lucasbraum/upt-109-keep-imported-transitive-deps

Conversation

@lucasbraum

Copy link
Copy Markdown
Collaborator

Closes UPT-109 once the enki check below is done. Refs UPT-107 (#224).

What and why

In the 0.15.1 pilot (#169), enki's Uptide PR installed and passed tests, but the type-check failed: 3 files import @react-types/datepicker, which enki uses without declaring it, and the new lockfile no longer had it.

Cause. The UPT-107 "moved entries" retry drops every package that declares react as a peer, and that includes @react-aria/datepicker. It re-resolved from 3.15.2 to 3.17.1, and 3.17.1 no longer depends on @react-types/datepicker. Nothing required that package any more, so npm pruned it.

Fix (managers/upgrade.ts, npm only):

  • After a retry step succeeds, compare the top level of the old and new lockfile (root and workspaces). Then scan tracked .[cm]?[jt]sx? files for bare from / import / require specifiers. A package that left the top level and is imported is a dropped import.
  • If there is one, the same step runs again. It keeps the dropped package and every locked package that requires it, transitively, at their locked versions. Moved packages are never kept.
  • If that retry hits ERESOLVE, the first retry's lockfile stands.
  • lockfile.undeclared ({ name, version, kept }) lists each one. The CLI summary and the PR body show it under "Imported but not declared": the package is imported but not declared in package.json, and it was kept at a version or the new lockfile no longer has it. Both suggest adding it to package.json.
  • The same report also covers a normal install with no retry, where the only possible outcome is reporting it.
  • package.json is never changed.

On enki this should keep @react-aria/datepicker (its react peer range already accepts 19) and its requirers at their old versions, and so keep @react-types/datepicker 3.13.2.

Tests

  • eresolve.test.ts, stand-in npm (now resolves dependencies transitively and prunes unrequired entries, like npm):
    • kept: picker peers on the moved ui, so the first retry drops it. picker 1.1.0 no longer brings picker-types, which src/date.ts imports. The second retry starts with picker and picker-types locked, and the lockfile keeps both at 1.0.0. The report has undeclared: [{ picker-types, 1.0.0, kept: true }], and package.json is unchanged.
    • cannot keep: picker 1.0.0 conflicts too, so the second retry hits ERESOLVE. The first retry's lockfile stands (picker 1.1.0, no picker-types), with kept: false.
    • Both failed on main before the fix.
  • format-fix.test.ts, report.test.ts: the summary and PR body lines for both kept and not kept.
  • Locally: pnpm lint (only the existing warning/info from main), pnpm typecheck, core 2296 passed, cli 517 passed (after pnpm build, which the notices and telemetry tests need).

Not done

  • enki not re-run. No bench runs for this PR, so the type-check result on enki is still unconfirmed. Running the bench: UpgradeBench v0 pilot harness (UPT-24) #169 harness's Uptide arm on enki would confirm it.
  • pnpm and yarn are not covered. The retry is npm only, and their strict layouts already break undeclared imports.
  • The import scan is a regex over JS/TS files. It does not read .vue / .svelte files or /// <reference types>.

🤖 Generated with Claude Code

…LVE retry (UPT-109)

When npm's ERESOLVE retry re-resolves the lockfile and a package the repo
imports without declaring it leaves the top level of node_modules, run
the same retry step again keeping that package and every locked package
that requires it. If that ERESOLVEs, the first retry stands. Either way
the report lists it as "Imported but not declared" and suggests adding it
to package.json; package.json is never changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lucas Braum <lucasbraum@gmail.com>
@lucasbraum
lucasbraum merged commit 066deab into main Oct 18, 2026
28 checks passed
@lucasbraum
lucasbraum deleted the lucasbraum/upt-109-keep-imported-transitive-deps branch October 18, 2026 18:11
@uptide-release uptide-release Bot mentioned this pull request Oct 18, 2026
lucasbraum pushed a commit that referenced this pull request Oct 18, 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.16.0

### Minor Changes

- [#237](#237)
[`717468a`](717468a)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `npx uptide fix`
gets the Agent SDK executor. The package stays as small as before:
`@anthropic-ai/claude-agent-sdk` is not installed with Uptide. An SDK
installed next to Uptide is used as it is; otherwise the first `fix`
that needs it installs the version Uptide is tested with into Uptide's
cache (`~/.cache/uptide/agent-sdk/<version>`), says so in one line with
its size, and later runs reuse it. When that install fails (offline, a
proxy) or the SDK cannot run, `fix` runs the patch executor and says so
on the first line of its output and at the top of the PR body, with the
reason and how to get the SDK executor. `report.json` records
`llm.executor` and, after a fallback, the reason in `llm.sdkMissing`.
The privacy notice names the SDK only when the SDK will run, and the LLM
line names the executor. `--agent sdk` without a usable SDK stops before
any work instead of failing mid-run.

- [#239](#239)
[`e1e8c40`](e1e8c40)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `uptide fix` runs
only with the Claude Agent SDK; if it can't, it doesn't run. Before the
first download, an interactive terminal asks once: `uptide fix needs the
Claude Agent SDK (about 300 MB, downloaded once to <cache>). Download
now? [Y/n]` (default yes). With `--yes`, or without a terminal, it
downloads and says so in one line. Once cached, it never asks again.
Answering `n`, an SDK that can't be fetched or loaded (offline, a proxy,
no binary for the platform), a missing `ANTHROPIC_API_KEY`, another
provider, or `llm.enabled: false` / `executor: patch` in `uptide.yml`
all stop `fix` with exit 2 before any clone or spending. The run prints
one message with the reason and the fix, and `--json` returns it as
`error.code: "SDK_UNAVAILABLE"`. There is no fallback to the patch
executor anywhere: the Uptide Action stops the run with the same
message. `--no-llm`, `--agent` and `--provider` are gone from help and
docs. `llm.sdkMissing` is gone from `report.json`, and `uptide init` no
longer writes `executor`.

### Patch Changes

- [#236](#236)
[`9b35b9d`](9b35b9d)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - A repository
build that fails on the final head is no longer published as a ready PR.
When it fails, `fix` builds the parent commit in the same clone to
compare. If the parent fails too, the build line says "already failing
before this upgrade" and nothing is blocked. If the parent passes, the
upgrade broke the build: verification fails, and the PR opens only as a
draft with "Build broken by this upgrade" at the top. If the parent
can't be checked out, installed or built, verification still fails and
the PR says "Build fails on this upgrade; the parent build could not be
checked" with the reason, never that the parent passed. The GitHub
Action opens these runs as draft PRs, the same way it opens agent-led
runs. The head build also skips workspaces already built on that head,
so a workspace whose output a consumer reads is no longer built twice.

- [#233](#233)
[`1ad8071`](1ad8071)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - The PR
description's build check now gives the build's actual result: passed,
failed with its first error, or not run and why. When a migration pack
doesn't require a build, `fix` still runs the repository's build once on
the final head, and `uptide verify` runs it again, and reports what
happened. "Not required by the pack" now appears next to that result
instead of replacing it. Before, the line read "build not required" even
when the repository's build failed. A build the pack doesn't require
still doesn't block verification or publishing.

- [#238](#238)
[`6f07d3f`](6f07d3f)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - An SDK session's
edits are no longer thrown away because of one flaky test. Before the
gate rejects a session on test failures, it runs the failing test files
once more, alone, with their runner and the same isolation as the full
run. A file that passes then is recorded as flaky (`llm.tasks[].flaky`
in `report.json`, and a line in the PR body's review list) and the edits
stay. A file that fails twice still rejects them, and a failure that
names no test file (a build, a timeout) is never rerun. Final
verification keeps its full gate: it runs the flaky files again, and if
one fails there, verification fails and the PR body says so. `fix` also
stops starting verification feedback sessions when what is left of
`--max-cost` is below the mean cost of the run's sessions so far, so it
no longer starts a session it can't afford; the PR's feedback line says
when this happened.

- [#234](#234)
[`066deab`](066deab)
Thanks [@lucasbraum](https://github.com/lucasbraum)! - `fix` on npm no
longer loses a package the repo imports without declaring it when the
ERESOLVE retry re-resolves the lockfile. If the retry drops such a
package from the top of `node_modules`, it runs again keeping that
package and the locked packages that require it at their old versions;
if that conflicts, the first retry stands. Either way the summary and
the PR body name the package under "Imported but not declared" and
suggest adding it to package.json. `fix` never adds it for you.

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