Skip to content

feat(common): warn when a declared ui-* peer range excludes the installed version - #229

Merged
pasevin merged 3 commits into
mainfrom
fix/check-peers-outdated-range
Sep 9, 2026
Merged

pasevin merged 3 commits into
mainfrom
fix/check-peers-outdated-range

Conversation

@pasevin

@pasevin pasevin commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Why

oz-ui-dev check-peers exists to catch "the one adapter/peer mismatch that no build step
catches". It compares the minimum each declared @openzeppelin/ui-* range admits against
the version actually installed, deliberately mirroring validatePeerVersions in
@openzeppelin/ui-utils.

That is right for the failure it was built for — an installed peer that is too old — but it
leaves the opposite drift completely invisible, and that drift is its own defect. An adapter
declaring ^2.0.0 against an installed 4.0.1:

  • passes its own runtime validatePeerVersions check, which only enforces >=2.0.0;
  • passes check-peers today, by design;
  • and still cannot be installed by a consumer app, because npm/pnpm read the declared
    range, not the baked minimum.

Nothing anywhere reported it. That is how every package in OpenZeppelin/openzeppelin-adapters
came to declare ui-components, ui-react and ui-utils on the v2 line while the kit shipped
components 3.9.0 / react 3.3.2 / utils 4.0.1 — for two majors, in silence. The existing test
adapterPeers.test.ts locked that exact case in as a pass (^2.0.0 declared, 4.0.0
installed), so the blind spot was documented rather than noticed.

What this does

Such pairs are now a warning, code outdated-range, naming the bump that fixes each one:

Adapter peer check passed for /path/to/app (4 adapter/peer pairs)
  [warning] outdated-range: @openzeppelin/adapter-evm-core declares @openzeppelin/ui-components ^2.0.0, which does not admit the installed 3.9.0. The adapter's own runtime check passes, but a package manager reads the range and refuses the install.
  [warning] outdated-range: @openzeppelin/adapter-evm-core declares @openzeppelin/ui-react ^2.0.1, which does not admit the installed 3.3.2. ...
  [warning] outdated-range: @openzeppelin/adapter-evm-core declares @openzeppelin/ui-utils ^2.0.0, which does not admit the installed 4.0.1. ...

Fix: raise the range in the adapter manifest to the major that is actually installed.
  - @openzeppelin/adapter-evm-core: @openzeppelin/ui-components ^2.0.0 -> ^3.9.0
  - @openzeppelin/adapter-evm-core: @openzeppelin/ui-react ^2.0.1 -> ^3.3.2
  - @openzeppelin/adapter-evm-core: @openzeppelin/ui-utils ^2.0.0 -> ^4.0.1

That output is from a fixture reproducing the adapters' pre-fix state exactly. ui-types
^3.5.0 against installed 3.5.2 stays quiet, as it should. The three bumps it names are the
three the adapters repo has since landed.

  • rangeAdmits(range, version) resolves a declared range with its upper bound intact:
    ^ (including the 0.x leftmost-non-zero rule), ~, the four inequalities, exact pins,
    wildcards, and || unions. Anything else returns null and is left unreported rather
    than guessed at — a false warning here would be worse than none.
  • AdapterPeerPair gains range (as declared) and rangeSatisfied (boolean | null).
  • printAdapterPeerResult printed the green line and returned early, so a warning-only result
    showed nothing. Warnings and remediation now print on both paths.

What this deliberately does not change

  • Error semantics are untouched. ok and the exit code are still driven by errors alone
    (issues.every(i => i.severity !== 'error'), matching localDev.ts). Adding this to a
    pipeline already running check-peers cannot change its result. A clean run prints exactly
    what it printed before.
  • A stale peer is reported once, as the error it is, not also as drift.
  • validatePeerVersions is not touched. Giving the runtime check an upper bound would turn
    today's benign over-install into a hard throw for consumers on a newer kit, and would need
    the adapters to pass the range rather than the baked minimum. Catching this statically, at
    install/CI time, is the cheaper and safer half; the runtime change is a separate decision.

Checks

Run at the repository root, exit codes captured directly:

command exit
pnpm build 0
pnpm test 0 — 2027 tests, 175 files (dev-cli 69 -> 82)
pnpm typecheck 0
pnpm lint 0
pnpm format:check 0

Also ran the built CLI against OpenZeppelin/openzeppelin-adapters post-fix: passes clean,
20 adapter/peer pairs, no warnings.

Context

This is the only change the UIKit side needed. The adapters' entire UIKit surface — 26
identifiers from ui-components, 6 from ui-react, 29 from ui-utils — has no breaking
change
across v2 -> v3; 29 of the 30 components and hooks are byte-identical source, and the
one exception (AddressDisplay) is purely additive and inert without injection. The defect was
the ranges, and the missing signal about them.

…d version

check-peers compared only the minimum a range admits, mirroring validatePeerVersions,
so drift in the other direction was invisible: an adapter declaring ^2.0.0 against an
installed 4.0.1 satisfies its own runtime check and still cannot be installed, because a
package manager reads the range rather than the baked minimum.

rangeAdmits resolves a declared range against a version with its upper bound intact,
returning null for syntax it does not model so nothing is guessed at. Such pairs become
a warning with code outdated-range; ok and the exit code stay driven by errors alone.
The summary returned early when the check passed, so a warning-only result printed the
green line and nothing else. Warnings and remediation now print in both branches, and
each issue carries its code.
@netlify

netlify Bot commented Sep 9, 2026

Copy link
Copy Markdown

Deploy Preview for openzeppelin-ui ready!

Name Link
🔨 Latest commit 9baf510
🔍 Latest deploy log https://app.netlify.com/projects/openzeppelin-ui/deploys/6aa14d348094370008c0e4c0
😎 Deploy Preview https://deploy-preview-229--openzeppelin-ui.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@pasevin
pasevin marked this pull request as ready for review September 9, 2026 12:33
@pasevin
pasevin requested a review from a team as a code owner September 9, 2026 12:33
@pasevin
pasevin merged commit 4e7e728 into main Sep 9, 2026
14 checks passed
@pasevin
pasevin deleted the fix/check-peers-outdated-range branch September 9, 2026 12:33
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 9, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant