1111// 5. The injected mirror stays within its size budget. Invariant 4 can only ever demand *more*
1212// text in a file that is loaded into every session; without a ceiling the map grows by
1313// accretion, because each extension appends and none ever cuts.
14- // 6. A branch does NOT change any version field. The bump is not a pull request's job: five
15- // manifest fields carry the version, so every concurrent PR used to conflict with every other
16- // one on the same five lines over something that was never the change itself. Instead
17- // scripts/release.mjs sets them on master after the merge (automatically, via
18- // .github/workflows/release.yml), which is what makes installed plugins pull the update.
14+ // 6. A branch does NOT change any version field, compared against its *merge base* with the base
15+ // branch. The bump is not a pull request's job: five manifest fields carry the version, so
16+ // every concurrent PR used to conflict with every other one on the same five lines over
17+ // something that was never the change itself. Instead scripts/release.mjs sets them on master
18+ // after the merge (automatically, via .github/workflows/release.yml), which is what makes
19+ // installed plugins pull the update.
1920// 7. Every `okf/...md` path a skill cites actually exists. Skills delegate their rules to the OKF
2021// rather than restating them, so a renamed or deleted topic would otherwise leave a skill
2122// pointing at nothing — and a reviewer that cannot read its rule source fails silently.
@@ -145,7 +146,11 @@ if (mapStart === -1 || mapEnd === -1 || mapEnd < mapStart) {
145146// ---- Invariant 6: a branch leaves the version alone ------------------------------------------
146147// The version is released, not authored: scripts/release.mjs writes all five fields on master once
147148// per release, so a pull request that also writes them conflicts with every other open PR for no
148- // reason. Compared base -> working tree, so a stray bump is caught before it is even committed.
149+ // reason. Compared merge base -> working tree, so a stray bump is caught before it is even
150+ // committed. The merge base and not the base branch's tip, because the question is what *this branch*
151+ // did: master keeps releasing while a branch is open, so a branch that forked at 1.1.7 and touched
152+ // nothing still differs from a master that has since reached 1.5.1 - measured against the tip, every
153+ // long-lived branch would be told to revert a bump it never made.
149154// Skipped, not failed, when the base ref is not fetched (a shallow clone, or a checkout with no
150155// remote) so the other invariants still run.
151156const git = ( args ) => {
@@ -162,7 +167,8 @@ const git = (args) => {
162167// On a PR the base is whatever it targets; otherwise assume the default branch.
163168const baseBranch = process . env . GITHUB_BASE_REF || "master" ;
164169const baseRef = `origin/${ baseBranch } ` ;
165- const baseSha = git ( [ "rev-parse" , "--verify" , "--quiet" , `${ baseRef } ^{commit}` ] ) ;
170+ const baseTip = git ( [ "rev-parse" , "--verify" , "--quiet" , `${ baseRef } ^{commit}` ] ) ;
171+ const baseSha = baseTip && git ( [ "merge-base" , baseTip , "HEAD" ] ) ;
166172const onBaseBranch = git ( [ "rev-parse" , "--abbrev-ref" , "HEAD" ] ) === baseBranch ;
167173if ( ! baseSha ) {
168174 console . log ( `validate.mjs: note - ${ baseRef } is not available, skipping the version-untouched check` ) ;
@@ -182,9 +188,10 @@ if (!baseSha) {
182188 errors . push (
183189 `This branch changes the plugin version (${ moved . join ( ", " ) } : ` +
184190 `${ baseVersions [ moved [ 0 ] ] } -> ${ versions [ moved [ 0 ] ] } ), but a pull request must not - it makes every ` +
185- `concurrent PR conflict. Revert the version fields to ${ baseRef } 's value; the release is cut on ` +
186- `${ baseBranch } by scripts/release.mjs. To force a minor/major for a change whose significance the ` +
187- `file list cannot show, put a 'Release-Bump: minor' (or major) trailer in a commit message instead`
191+ `concurrent PR conflict. Restore the version fields to the ${ baseVersions [ moved [ 0 ] ] } they have at ` +
192+ `the merge base with ${ baseBranch } (${ baseSha . slice ( 0 , 8 ) } ); the release is cut on ${ baseBranch } by ` +
193+ `scripts/release.mjs. To force a minor/major for a change whose significance the file list cannot ` +
194+ `show, put a 'Release-Bump: minor' (or major) trailer in a commit message instead`
188195 ) ;
189196 }
190197}
0 commit comments