docs(book): teach the derived release version, and move the template onto it
All checks were successful
PR Checks / prose (pull_request) Successful in 7s
PR Checks / template (pull_request) Successful in 33s

The template shipped the declared-version release engine the reference module
has just abandoned: publish when a push to `main` leaves `module.json` at a
version with no release yet. Both flavours of the workflow move to the engine
`link`, `installer` and now Module-uo run - feat!/BREAKING CHANGE -> major,
feat -> minor, fix|perf -> patch - with `module.json` kept as a floor and a
`workflow_dispatch` backdoor for a manifest change with no releasable code
behind it. The tag is the number that ships, and the job writes it into the
`module.json` inside the bundle.

The chapter keeps the declared model in view rather than deleting it, because
the reason it was abandoned is the part a reader needs: its cost is paid on
every release, and the drift it prevents is something review catches anyway. A
week of merged work in the reference module produced no bundle at all.

Also carried over from the same pass: a tag pushed without a release behind it
is recovered instead of standing down forever, and the changelog moved into the
plan step (so assemble clears `$OUT`, not `dist/`).

Kept: the `# CHANGE THESE` banner, the exclusion list from the acceptance run's
F4, and the GitHub twin's `MODULE_SOURCE_HOSTS` note.

checkLinks, checkRenameSites and checkChapterPaths pass.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-19 13:01:51 -05:00
parent 67aff992a4
commit 3979fa5abf
3 changed files with 448 additions and 145 deletions

View File

@@ -650,11 +650,30 @@ installed, the schema fragment, the OpenAPI fragment. Core downloads the tarball
verifies it against the `sha256` in the install manifest, and unpacks it. Nothing
runs `npm` on the way.
**The version is declared in `module.json`, not computed from commit subjects.**
You already have one authoritative version — it is what core records and what the
admin panel shows — and two sources for one number is how they drift. A release
happens when a push to `main` leaves a version that has no release yet, so
bumping is an ordinary reviewed change and publishing is the workflow's business.
**The version is computed from your commit subjects, and `module.json`'s is a
floor.** Every push to `main` carrying a `feat:`, `fix:` or `perf:` publishes a
bundle — `feat!:` and `BREAKING CHANGE` make it a major, `feat:` a minor, the
rest a patch — and a `main` that gained none of those cuts no release. The number
that ships is the **tag**, which the workflow writes into the `module.json` inside
the bundle.
The alternative is tempting and it is what this project's own reference module
did first: let `module.json`'s version decide, and release whenever a push leaves
it at a version with no release yet. You already have that number, it is what core
records and what the admin panel shows, and two sources for one number is how they
drift. It was abandoned on 2026-08-19 for a reason worth knowing before you copy
either shape — **its cost is paid on every release, and the drift it prevents is
something review catches anyway.** A week of merged work produced no bundle at
all, because none of it happened to touch that line, and shipping it meant first
merging a pull request whose entire content was a number.
So the declaration is kept, demoted to a floor: name a version in `module.json`
above the newest tag and *that* is what releases. It is still how you say "this
one is a minor" when a `coreApi` bump forces the question. And for a change with
nothing releasable behind it — a widened `coreApi`, a new mount, a new capability
— run the workflow by hand: leave `version` blank to bump the newest tag by
`bump`, or type an exact version.
The workflow tags and publishes and never writes to a branch, so a protected
`main` needs no exception.