Uh oh!
There was an error while loading. Please reload this page.
chore(deps): migrate to @changesets/cli v3 with the config its defaults require - #5307
Conversation
…ts require Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HDA9nN6nXQngoQUAAzRdMb
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HDA9nN6nXQngoQUAAzRdMb
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
os-project-manager
commented
Aug 19, 2026
PM review-of-record — checked against The card's own measurement was wrong, and this PR is right.#5296 stated that no pending changeset names the private Verified independently, three claims that the whole shape rests on:
Ruling on the one out-of-territory file. The decision not to move CI at Out of scope and correctly split out rather than ridden in: #5306 (root Generated by Claude Code |
os-project-manager
commented
Aug 19, 2026
PM review-of-record, part 2 — the The PR argues
privatePackages: json.privatePackages===false ? {tag: false,version: false}
: json.privatePackages ? {version: …??true,tag: …??false}
: {version: true,tag: false}// ← absent
if(typeofwrittenConfig.privatePackages!=="object")config.privatePackages={version: writtenConfig.privatePackages??false,tag: writtenConfig.privatePackages??false};So the same silence reads The remaining link is confirmed too: Same method on §2's claim: On the last check still running. Review passes. Marking ready and sending it through the merge queue; not merging by hand. Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#5296
@changesets/climoves from^2.31.1to^3.0.0(resolves to 3.0.1), together withevery
.changeset/config.jsonchange v3's defaults require. One PR on purpose: splitapart, each half is broken silently until the next release, and no PR workflow in this
repo runs
changeset statusorchangeset version— the only invocation is inside.github/workflows/changeset-release.yml, on push tomain. A green CI here proves theworkspace still installs and nothing more.
Rehearsal method
A throwaway clone with no remote at all, built by
git archivefrom this branch'sHEAD,
git init, and the two-commit.changesetscaffold recorded atobjectstack-ai/objectstack#9555 (base tree first, the pending changesets second). The
rehearsal tree hash is identical to the tree of the commit this PR ships
(
aac0c984a4e75c8c81670aec238a56c0b42f7b6b), so the evidence below is from exactly whatis being merged. The deepen-loop hang that scaffold exists for did not occur:
changeset versionfinished in 9 s. Worth recording anyway — the primary checkouthere is shallow (
git rev-parse --is-shallow-repository=true), so the trap islive for anyone who rehearses in a clone of it with the remote removed.
Evidence from the real stock
.changeset/holds 251.mdfiles on this branch:README.md, the 249 real pendingchangesets, and this PR's own. (Issue #5296 says 250 pending — that is the file count
including
README.md; changesets itself reportschangesets: 249.)changeset statusunder v3.0.1, final tree — exit 0:40 packages, all minor, no mixed-changeset error. Machine-readable plans were diffed:
the v3 plan is identical to the v2 plan, release for release — 45 releases (40 bumped
17.5.0 -> 17.6.0, 5nonefor the ignored packages), 249 changesets, same types.changeset versiondry run under v3.0.1, final tree — exit 0, 9 s:330 files changed: 40
package.jsonbumps (every one to17.6.0), 40CHANGELOG.mdfiles, 250 changesets consumed,
README.mdleft in place.apps/site,packages/test-supportandexamples/*were untouched (0 files each), the rootpackage.jsonandpnpm-lock.yamlwere untouched, and the privatepackages/vscode-extensionwent17.5.0 -> 17.6.0in lockstep with the rest — which isthe behaviour
privatePackageshas to be set explicitly to keep. The tree was thendiscarded; no release was performed, no tag written, no version PR touched.
The four v3 changes, one at a time
1.
privatePackages— the trap fires today, not hypotheticallyIssue #5296 states that of the pending changesets "none names" the private
object-ui, so "the trap does not fire today". That measurement is wrong..changeset/no-console-lint-rule.mdnames it beside four published packages:With the bump applied and
privatePackagesleft undeclared, that is fatal on the currentstock —
changeset statusexit 1:So the correction strengthens the card rather than weakening it: dependabot's bump alone
would have stopped the release lane on the very next push to
main, with PR CI green.{ "version": true, "tag": false }— the sibling repo's choice — is right here too, andfor a reason measured rather than inherited. Read out of
@changesets/config@4.0.0: anabsent key now defaults to
{ version: false, tag: false }(v2 defaulted to{ version: true, tag: false }), a boolean is shorthand for both fields, and each fieldof the object form defaults to
falseindividually.version: falsedoes not merely skipthe bump — it feeds
allowPrivatePackages: falseinto the assembler, i.e. the package istreated as ignored. Three settings were rehearsed on the real stock:
privatePackageschangeset status{ version: false, tag: false }{ version: true, tag: false }tag: falseis not cosmetic:getPublishPlan.mjsfilterspkg.packageJson.privateout ofthe npm publish set unconditionally, so
version: truenever publishes the extension;privatePackages.tagalone decides whether it gets a git tag, andfalsematches what v2did. Moving
object-uiintoignoreinstead was rejected —check-changeset-presence.mjsderives its guarded surface from
fixed, so ignoring the extension would silently stopdemanding a changeset for its source changes.
2. The experimental key — inert under v3, load-bearing under v2
___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH.onlyUpdatePeerDependentsWhenOutOfRangeis removed in the same commit as the bump. Measured both ways rather than assumed:
@changesets/assemble-release-plan@6.0.10(what v2 resolves) referencesonlyUpdatePeerDependentsWhenOutOfRange6 times in its dist;@7.0.0(what v3resolves) references it 0 times.
@changesets/config@4.0.0still parses and defaultsthe key, so it is accepted and dead rather than rejected — and a v3 run with the key
re-added produced a byte-identical release plan to the run without it.
3. ESM-only,
engines: ^22.11 || ^24 || >=26— the repo pin does not satisfy itMeasured from the installed package:
"engines": { "node": "^22.11 || ^24 || >=26", "npm": ">=10.9.0", "pnpm": ">=10.0.0", "yarn": ">=4.5.2" },"type": "module".This repo declares
"engines": { "node": ">=22", "pnpm": ">=9" }. Neither range is asubset of v3's:
>=22admits 22.0–22.10, 23.x and 25.x, all of which v3 rejects, and>=9admits pnpm 9. Nothing enforces it today — there is noengine-strictin.npmrc(it contains onlyauto-install-peers=true), the repo pinspackageManager: pnpm@10.31.0, and every workflow runsnode-version: '22.x', whichresolves to a 22.11+ release. So the migration is safe as it stands, but the declared
range is looser than what the toolchain now requires. Deliberately not changed here —
tightening
engines.nodeaffects every consumer of this workspace and is a decision, nota rider on a tooling bump. Filed separately as #5306.
4.
changeset versionon an empty plan — measured, and the workflow needs no changeThe exit-code change is real and reproduced:
warn No unreleased changesets found, exiting.No unreleased changesets found.That second row matters here, because an empty-frontmatter changeset is this repo's
declaration mechanism for changes that publish nothing — it is not an empty plan as far
as the exit code is concerned.
It is nevertheless unreachable through
changeset-release.yml. Rather than reasonabout it, the pinned action's source was read:
changesets/action@v1currently resolves tov1.9.0, whose
src/index.ts(and the compileddist/index.jsthat actually runs)branches before ever invoking the
version:input:The workflow supplies both
version:andpublish:, so an empty.changeset/takes thefirst branch and
pnpm changeset:versionis never run; a stock of only empty-frontmatterchangesets takes the second and it is never run either.
runVersionis reached only whenat least one changeset carries a release, i.e. exactly when the plan is non-empty. The
action reads the changesets with its own bundled
@changesets/*, so this bump cannotchange which branch it takes.
Conclusion:
.github/workflows/changeset-release.ymlis unchanged in this PR, and thecard's item 4 is answered "no real change" with the source to back it.
Gate scripts under v3
scripts/check-changeset-no-major.mjs— nothing in it models v2, deliberately: ithand-parses YAML frontmatter and may not import
@changesets/*, because.github/workflows/changeset-guard.ymlruns it on a bare checkout with no install. Itsself-test asserts on the parser, on repo state, and on the guard workflow; all of that is
version-agnostic. Run under v3: green, unchanged. (The header's "39 packages" was checked
against the config rather than trusted —
fixedholds 40 names, of which 39 arepublishable and one,
object-ui, is private. The comment is accurate.)scripts/check-changeset-fixed.mjs— this is the one that modelled v2. Its single rule("every workspace package is in
fixedorignore") was complete only while privacy didnot affect release membership, and it passes happily on precisely the config that makes
changeset statusexit 1. Two rules added, both derived from the failure measured above:privatePackagesmust be declared. Silence is no longer a safe default; v2 and v3read the same silence as opposite values.
fixedgroup must not be paired withprivatePackages.version: false. That combination is a contradiction changesets doesnot diagnose at config-read time — it surfaces later as the mixed-changeset error, from
whichever changeset happens to trip it first.
Reverse-verified on this branch, from the committed state: deleting the key turns the gate
red (rule 1) and setting
version: falseturns it red (rule 2) — and in that same statethe CLI itself fails with the mixed-changeset error, so the gate's verdict coincides with
the real one.
ignore/fixedmatching also became glob-aware, matching how changesetsexpands those lists when it reads the config and how
check-changeset-presence.mjsalready matched them; inert on today's config, wrong only later.
Beyond the claimed file territory:
scripts/__tests__/check-changeset-fixed.test.tsisnew. The card asks for both gate scripts' self-tests to pass and model v3; this script had
no self-test at all (only
check-changeset-no-majorandcheck-changeset-presencehave one), so the acceptance criterion could not otherwise be met. It drives the pure
helpers directly, pins the repo's own config, and pins the shape the rules exist for (a
private
object-uiinsidefixed). Verified live: with the key removed, 2 of its 13 testsfail with the intended messages.
Verification
All at
c488fd7, the commit this PR ships, working tree clean:pnpm exec vitest run --project unit scripts/__tests__/check-changeset-fixed.test.ts scripts/__tests__/check-changeset-no-major.test.ts scripts/__tests__/check-changeset-presence.test.ts scripts/__tests__/merge-queue-reporting.test.ts— 4 files, 66 tests, all passpnpm changeset:check— green, now also reportingprivatePackages declared: version=true, tag=falsenode scripts/check-changeset-presence.mjs— green (no source of a released package changed in this range; a changeset is added anyway, per the repo convention)pnpm check:control-bytes— green (4688 files)pnpm type-check:scripts,pnpm lint:coverage,eslinton both changed script files — greenNon-goals honoured
No release was performed: no
changeset publish, no version tag, no release-workflowdispatch, no version PR merged. Pre mode was not entered (
.changeset/pre.jsonstill doesnot exist). The
changesets/action@v1pin is untouched — its source was read, not changed,and whether objectstack-ai/objectstack#9208's reasoning applies here remains a separate
question.
.github/workflows/dependabot-auto-merge.ymland all 249 pre-existing changesetfiles are untouched. Dependabot's #4950 stays open and unmerged; dependabot retires it on
its own once
maincarries^3.0.0.Changeset
.changeset/changesets-cli-v3-migration-5296.md, empty frontmatter — this PR publishesnothing (root devDependency, changeset config, CI helper scripts).
objectuihas noskip-changesetlabel and none was minted.Generated by Claude Code