Skip to content

docs(docs): generate the version compatibility table from the manifests - #232

Merged
pasevin merged 1 commit into
mainfrom
docs/compatibility-matrix
Sep 9, 2026
Merged

pasevin merged 1 commit into
mainfrom
docs/compatibility-matrix

Conversation

@pasevin

@pasevin pasevin commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Why, given I argued against it

My objection was that a hand-maintained matrix drifts and that #229 already checks the set
mechanically. The first half is answered outright: this table is generated from the package
manifests
, so it cannot drift. The second half was never a real objection — check-peers
only helps someone who already knows to run it, and a reader opening the repo had nothing
telling them the kit is one set. Both things can be true, so it is written.

What is in it

A generated ## Version compatibility section in the root README, placed immediately after
## Installation — which lists a pnpm add per package and says nothing about versions, so
it is exactly where the question arises and where the answer was missing.

Everything rendered comes out of packages/*/package.json:

Package Version Requires from this set
@openzeppelin/ui-types 3.5.2
@openzeppelin/ui-utils 4.0.1 ui-types
@openzeppelin/ui-components 3.9.0 ui-types, ui-utils
@openzeppelin/ui-storage 1.2.5 ui-types, ui-utils
@openzeppelin/ui-react 3.3.2 ui-components, ui-types, ui-utils
@openzeppelin/ui-renderer 3.4.2 ui-components, ui-react, ui-types, ui-utils

The set is not hand-picked: it is the connected component of the intra-kit dependency graph
containing ui-components. ui-styles and ui-cli carry no intra-kit edges, so they cannot
be split by a version mismatch and are left out rather than listed with nothing to say. That
also means the table includes ui-renderer and ui-storage, which are subject to the same
splitting problem as the four packages I was asked to cover.

Alongside the table, three short subsections:

  • Why the set is not optional — the packages depend on each other through dependencies,
    not peerDependencies (there is not one intra-kit peer range in the kit), so a mismatch
    resolves instead of failing: ui-components quietly gets a second nested ui-utils. Two
    copies of ui-utils is the case that bites, because appConfigService is a single instance
    and logger is a getInstance(), so the copy your app did not initialise answers with
    defaults and never throws. Two copies of ui-types give TS2322/TS2345 instead. It ends with
    the command to check the edges rather than take my word for them:
    npm view @openzeppelin/ui-components@3.9.0 dependencies --json | grep '@openzeppelin'
  • Read the major numbers as independent — the set does not share a major and that is not a
    mismatch. ui-utils leads at 4.x because it removed WalletConnect in feat(cli): stop scaffolding WalletConnect configuration #210, breaking for its
    own consumers and a dependency bump for everyone else. Explicitly: do not try to line the
    majors up.
  • Checking an installed tree — points at oz-ui-dev check-peers, so the doc says what to
    install and the tool says what actually resolved. They reinforce rather than compete.

Claims cannot outlive their evidence

The generator emits conditional prose only while the manifests still support it, which is the
part that makes a generated doc better than a written one rather than just cheaper. Verified
by mutating manifests and regenerating:

Mutation Result
ui-utils3.9.9 (majors align) the ui-utils 4.x-vs-3.x paragraph disappears; the majors section stays, correctly, because ui-storage is still 1.x
ui-utils5.0.0 the paragraph re-renders itself as "sits at 5.x while … is at 3.x"
add an intra-kit peerDependencies entry the whole "Why the set is not optional" section disappears, because its premise is gone

The release loop closes

A CI drift check alone would fail every chore(release): version packages PR, since the bot
bumps versions and would not regenerate. So the root version script — which is what
changesets/action runs — now regenerates as well:

-"version": "changeset version",
+"version": "changeset version && node scripts/generate-compatibility-matrix.cjs",

Simulated end to end by bumping ui-utils to 5.0.0: guard fails (exit 1), the version
script's regenerate runs, guard passes (exit 0). A release PR therefore carries the updated
table on its own.

Checks

Exit codes captured directly, not read through a pipe:

command exit
pnpm build 0
pnpm test 0 — 2027 tests across 8 packages
pnpm typecheck 0
pnpm lint 0
pnpm format:check 0
pnpm check-compatibility 0 — README matches the package manifests
pnpm check-licenses 0
pnpm check-changesets 0
drift check on a stale README 1, with the regenerate command in the message

The generated block is also Prettier-stable — the generator pads table columns the way
Prettier does, so prettier --write README.md leaves the block byte-identical and cannot
fight the generator. (README.md as a whole does not pass prettier --check on main either;
that is pre-existing and I have not touched it.)

No changeset. Nothing published changes — the root README, root scripts and CI are not in
any package's files array, so no package tarball is affected.

Judgement call worth flagging

I considered injecting the same generated block into each package README, since npm shows
those and never shows the root one, and that is where a consumer literally meets a package. I
did not, for two reasons: it would force a release of six packages for a documentation change,
and it would put six competing copies of a claim about the relationship between packages
into the packages themselves. The cross-package table belongs in the one cross-package place.
Say so if you would rather have it in the package READMEs too — the generator already has the
package list and the marker machinery, so it is a small change.

The README told a consumer how to install each package and nothing about which
versions go together, so the only way to learn that the kit is one set was to get it
wrong. The packages depend on each other through dependencies rather than peers, so a
mismatched set does not fail: it resolves a second nested copy and splits ui-utils'
module-level singletons.

The section is generated from the package manifests rather than written, so it cannot
drift from the versions it describes. Prose whose truth rests on a manifest fact is
emitted only while the manifests still support it: the coherence rationale disappears
if an intra-kit peer range ever appears, and the note explaining ui-utils' major gap
disappears if the gap closes.

The changesets version script regenerates the section, so a release PR carries the
updated table, and --check in CI fails if the two ever disagree.
@netlify

netlify Bot commented Sep 9, 2026

Copy link
Copy Markdown

Deploy Preview for openzeppelin-ui ready!

Name Link
🔨 Latest commit e972537
🔍 Latest deploy log https://app.netlify.com/projects/openzeppelin-ui/deploys/6aa155b9291b560008250d86
😎 Deploy Preview https://deploy-preview-232--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:53
@pasevin
pasevin requested a review from a team as a code owner September 9, 2026 12:53
@pasevin
pasevin merged commit da07764 into main Sep 9, 2026
14 checks passed
@pasevin
pasevin deleted the docs/compatibility-matrix branch September 9, 2026 12:54
@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