#3333 · PR #3337 · milestone v10.0.0

The prerelease train

Three defects stood between 9.8.0 and a cuttable 10.0.0-alpha.1. Every number on this page was produced by running the thing, not by reasoning about it.

required check rejected 10.0.0-alpha.1 writer produced 10.0.0-alpha.2-alpha.1 reader read alpha.1 as 10.0.0 files changed 4

Where the train goes

Today's #3304 recomputes 10.0.0 on every merge to main. While the repo is GA shaped, any merge ships a major whose entire content is one rename.

9.8.0
today, on main
10.0.0-alpha.1
what #3337 enables
10.0.0-alpha.N
criticals land
10.0.0-beta.1
via Release-As footer
10.0.0
all 31 issues closed

At GA, flip prerelease: false but keep versioning: "prerelease". Dropping the strategy makes the next breaking commit bump to 11.0.0.

The config, read off the schema instead of remembered

The plan called these "three prerelease keys" as though they were one switch. The published schema says otherwise, and it also settles a spelling that would have failed silently.

KeyIn schemaWhat it actually does
versioningyespicks the bump strategy
prerelease-typeyessupplies the label when none is present
prereleaseyesmarks only the GitHub Release as prerelease
versioning-strategyno, absentrelease-please drops unknown keys silently, so this spelling yields GA versions from a config that reads as correct

Regex lab: the gate that could never go green

plugin-validation.yml:229 is a required check. Its old pattern had no prerelease branch at all, so no alpha could pass regardless of anything else in the repo. Type a version and watch both patterns decide.

before
 
^[0-9]+\.[0-9]+\.[0-9]+$
after
 
semver 2.0.0, anchored both ends

Measured, both directions

Must acceptBeforeAfter
Must still rejectBeforeAfter

The widening does not open a hole: everything the old pattern was written to catch is still refused, including a command substitution and a trailing space.

Stamp lab: the writer corrupted itself on the second alpha

scripts/stamp-counts.sh matched a bare X.Y.Z. That is harmless while versions are plain, and wrong the moment one carries a suffix: the pattern matches only the numeric head of the version already on the line and leaves the old suffix behind. Press the button to stamp the line, repeatedly, exactly as consecutive releases would.

before, bare X.Y.Z
after, semver aware

And the reader disagreed with the writer

bin/validate-counts.sh captured a bare X.Y.Z out of CLAUDE.md, so it read 10.0.0-alpha.1 as 10.0.0 and compared that truncated string against package.json's full one. The release was consistent; the gate said it was not.

file says   10.0.0-alpha.1
reader got  10.0.0            MISMATCH, release blocked

after the fix
  9.8.0                 -> 9.8.0                 ok
  10.0.0-alpha.1        -> 10.0.0-alpha.1        ok
  10.0.0-beta.2         -> 10.0.0-beta.2         ok
  1.0.0-alpha+build.5   -> 1.0.0-alpha+build.5   ok

Backward compatible: bash bin/validate-counts.sh passes on this tree at 9.8.0, CLAUDE.md included.

Deliberately not in this PR

None of these blocks cutting alpha.1, and each wants its own proof rather than a shared hand-wave.

GapMeasured behaviourWhen it bites
4 sort -V comparisons tail -1 of {10.0.0, 10.0.0-alpha.1} gives 10.0.0-alpha.1; semver says 10.0.0 alpha to GA transition
3 unescaped interpolations version dropped into a regex without escaping any version containing regex metacharacters
release-announce.yml:84 ${VERSION##*.} on 10.0.0-alpha.1 gives 1 first alpha announcement

scripts/bump-version.sh, named in the plan as a site to fix, does not exist.