Skip to content

docs: correct the release-process docs against the real release-please setup - #285

Merged
StefanSteiner merged 1 commit into
tableau:mainfrom
StefanSteiner:docs/release-process-hardening
Sep 6, 2026
Merged

docs: correct the release-process docs against the real release-please setup#285
StefanSteiner merged 1 commit into
tableau:mainfrom
StefanSteiner:docs/release-process-hardening

Conversation

@StefanSteiner

Copy link
Copy Markdown
Contributor

Docs-only. No config, workflow, version, or changelog file is touched — git diff --name-only is exactly AGENTS.md, CONTRIBUTING.md, docs/GITHUB_OPERATIONS.md.

Related: #283 (the rc.3 release tripwire, filed from this work). This PR does not add a Release-As: footer and does not touch #282.

What was wrong

docs/GITHUB_OPERATIONS.md described a release pipeline that does not exist. Each claim was checked against release-please-config.json, the workflow files, and the file lists of the last two release PRs (#282, #255) before being rewritten.

1. Lockstep was attributed to a plugin that isn't configured

The doc said lockstep is "enforced by the linked-versions plugin in release-please-config.json". That file has no plugins key at all. Lockstep falls out of the config declaring exactly one package (".", release-type: simple) whose version is fanned out by extra-files: a type: toml entry patches [workspace.package] version (the 8 members inherit via version.workspace = true) and five type: generic entries patch the x-release-please-start-version marker blocks holding the = "X.Y.Z" inter-crate pins plus hyperdb-compile-check's own version.

This one was actively dangerous: "fixing" the discrepancy by adding the plugin would push a working single-package setup toward the multi-package layout it deliberately avoids. The rewrite documents the real mechanism in a table and adds an explicit do not add this plugin warning.

2. Per-crate changelogs are not written by release-please, and nothing rolls them over

The doc promised "a new dated section in each crate's CHANGELOG.md". changelog-path is set on the . package only; neither #282 nor #255 touches a per-crate changelog, and a dry run lists 9 updated files with no per-crate changelog among them.

That makes it a process gap, not just a doc error. AGENTS.md reminder 8 asks contributors to append to nine per-crate ## [Unreleased] sections, and nothing ever dates them. Measured backlog:

Crate Unreleased bullets Last dated section
hyperdb-mcp 42 0.5.0 (2026-06-07)
hyperdb-api 31 0.1.1 (2026-05-13)
hyperdb-bootstrap 12 0.1.1
hyperdb-api-core 11 0.1.1
hyperdb-api-node 4 0.1.1
hyperdb-api-derive 3 none
hyperdb-api-salesforce 3 0.1.1
hyperdb-compile-check 3 none
sea-query-hyperdb 1 0.1.1
Total 110

110 bullets, most describing work shipped as far back as v0.1.1 — 23 tags ago.

Three options were considered. Configure release-please to manage all nine means adding nine packages to the config, i.e. exactly the multi-package layout item 1 warns against, and it would also fragment the root changelog — a large change to a working pipeline for bookkeeping worth minutes per release. Drop the convention loses genuinely useful per-crate history that contributors are already maintaining well. A documented manual step is the cheapest correct answer, so this PR adds Rolling over the per-crate changelogs to the release checklist (step 4 after tagging) and cross-links it from AGENTS.md reminder 8 and CONTRIBUTING.md.

Clearing the existing 110-bullet backlog is deliberately not in this PR — it is mechanical, touches nine files, and belongs with a real release cut, not a docs change.

3. Stale count

"All 8 workspace members share a single version number" undercounts the lockstep set: it is 9 path crates, because hyperdb-compile-check declares its own [workspace] yet is still version-managed via extra-files and published explicitly by release.yml. Corrected.

The file's other two counts were checked and are already right, so they are unchanged: "publish the 8 Rust crates to crates.io" (7 publishable workspace members + hyperdb-compile-check; hyperdb-api-node is publish = false) and "9 path crates in all".

4. bump-minor-pre-major: true is inert

It appears twice in the config but release-please only consults it when version.isPreMajor, defined as major < 1. The workspace has been at major 1 since 1.0.0-rc.1, so neither copy has done anything since — and a9fe1b0's commit message already said so.

Annotated rather than removed. Removal is behaviour-neutral, which is precisely why it isn't worth doing here: it would put a diff on the file that drives releases, inside a docs PR, while a release PR is open and a human is about to cut rc.3. JSON takes no comments, so the annotation lives next to the bump table. If it is removed later, it should ride along with the prerelease-keys change so there is one reviewed config PR with one dry run.

Bonus: CONTRIBUTING.md contradicted GITHUB_OPERATIONS.md

CONTRIBUTING said maintainers must "manually trigger the publish workflows"; GITHUB_OPERATIONS said they fire from the Release. The workflows are right (on: release: types: [published]), so CONTRIBUTING was stale — following it would mean waiting for a publish that already happened. Fixed; gh workflow run is now described as the re-run path.

Also corrected in the same step: the claim that the release PR bumps package.json versions and optionalDependencies. No package.json in the tree carries either field; npm-build-publish.yml materializes both with npm pkg set at publish time.

Verified, not assumed: would prerelease keys automate the rc line?

Yes, and exiting the rc line stays easy. Run with npx release-please@17.11.2 release-pr --dry-run — 17.11.2 is what release-please-action@v5 pins, per fa35a45's recorded note.

Fidelity first: the harness reproduces PR #282's live 1.0.1-rc.2 exactly, against both the real repo and a fork mirror. Only then were variants run, each against a real config file on a branch (the release-pr CLI has no --prerelease flag — only github-release does — so config-file testing was the only faithful route).

Config Highest-precedence commit Computed
current (control) fix: — today's actual state 1.0.1-rc.2 ✅ matches #282
current feat: 1.1.0-rc.2
current feat!: 2.0.0-rc.2
proposed fix: 1.0.0-rc.3
proposed feat: 1.0.0-rc.3
proposed feat!: 1.0.0-rc.3
proposed + Release-As: 1.0.0 any 1.0.0
proposed, "prerelease": false any 1.0.0
proposed, left in place after 1.0.0 shipped fix: 1.0.1-rc ⚠️

Proposed = "prerelease": true, "prerelease-type": "rc", "versioning": "prerelease".

All three commit shapes collapse to 1.0.0-rc.3, so the footer stops being load-bearing. Termination is not harder: flipping "prerelease" to false graduates to 1.0.0, and Release-As: still short-circuits everything. The one real caveat is the last row — the keys must be removed once 1.0.0 ships or every stable release becomes an rc; that failure is visible in the PR title, unlike today's.

Recommendation: adopt, as its own reviewed PR with the dry run attached. Deliberately not done here — this is a docs PR, and changing release-versioning behaviour while a release PR is open is not something to slip in alongside prose. The full matrix and rationale are written up in Automating the rc line.

Checks

  • npx markdownlint-cli2 (no args): 0 issues in 68 files, identical to the pre-change baseline on upstream/main. One MD013 I introduced in AGENTS.md was fixed by restructuring rather than by loosening the rule.
  • All internal anchor links in the three edited files resolve, including the new sections.
  • No cargo build / cargo test run (not needed for a docs change).

Latent traps found along the way

  • The tag regexes cannot catch a wrong version. release.yml and npm-build-publish.yml both accept ^v?[0-9]+\.[0-9]+\.[0-9]+(-(rc|alpha|beta)\.[0-9]+)?$ and otherwise only check tag-vs-Cargo.toml. Since the release PR writes the bad version into Cargo.toml itself, a wrong-but-well-formed version is self-consistent and sails straight through to crates.io. The release PR title is the only gate.
  • Squash merges silently eat Release-As: footers. Both prior rc footers survived on real merge commits (fa35a45, 567f819); every commit on main since is single-parent. Covered in Release tripwire: rc.3 needs a Release-As footer on main, in the squash commit body #283.
  • prerelease is an overloaded config key — documented in the schema as "create the GitHub release as prerelease", but also read by PrereleaseVersioningStrategy to decide whether to keep the suffix. Anyone reading the schema alone would not expect it to change computed versions.

…e setup

Four claims in docs/GITHUB_OPERATIONS.md described a release pipeline that
does not exist. Each was checked against the config, the workflows, and the
last two release PRs before being rewritten.

1. Lockstep versioning was attributed to a `linked-versions` plugin.
   release-please-config.json has no `plugins` key at all. Lockstep falls out
   of the config declaring exactly one package whose version is fanned out
   through `extra-files` and `x-release-please-start-version` markers.
   Documented the real mechanism and added an explicit warning not to "fix"
   the discrepancy by adding the plugin, which would push the repo toward a
   multi-package layout it does not want.

2. Step 2 promised "a new dated section in each crate's CHANGELOG.md".
   `changelog-path` is set on the `.` package only, and neither tableau#282 nor tableau#255
   touches a per-crate changelog. Since AGENTS.md reminder 8 still asks
   contributors to append to those files, nothing ever rolls them over: 110
   bullets across the nine crates currently sit under `## [Unreleased]`
   describing work shipped as far back as v0.1.1. Added a documented manual
   rollover step to the release checklist rather than moving the files under
   release-please, which would require the nine-package layout.

   The same step also claimed package.json versions and optionalDependencies
   are bumped in the release PR. No package.json in the tree carries either
   field; npm-build-publish.yml materializes both at publish time.

3. "All 8 workspace members share a single version number" undercounts the
   lockstep set, which is 9 path crates — hyperdb-compile-check is outside
   the workspace but is still version-managed and published. The other two
   counts in the file ("8 Rust crates" published, "9 path crates in all")
   were already right and are unchanged.

4. `bump-minor-pre-major: true` is gated on `version.isPreMajor`, i.e.
   `major < 1`, so it has been inert since 1.0.0-rc.1. Annotated rather than
   removed: it is behaviour-neutral either way, and editing the file that
   drives releases while a release PR is open buys nothing.

Also documents the rc tripwire, verified with `release-please@17.11.2`
dry runs (the version release-please-action@v5 pins): during an rc line a
`Release-As:` footer is required on every release, and without one a `fix:`
computes 1.0.1-rc.2, a `feat:` 1.1.0-rc.2, and a breaking change 2.0.0-rc.2 —
all well-formed enough to pass both publish workflows' tag validation, and
all sorting above 1.0.0.

CONTRIBUTING.md contradicted GITHUB_OPERATIONS.md on whether the publish
workflows must be triggered by hand. They fire from `release: published`;
`gh workflow run` is only for re-runs.
@StefanSteiner
StefanSteiner merged commit 964ea46 into tableau:main Sep 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant