chore(release): v0.4.0 #76

Merged
quartermaster merged 1 commit from release-prep/rolling into main 2026-06-25 22:14:07 +02:00

Added

Push-triggered rolling-release-PR mechanic — v0.4.0 replaces the v0.3.x operator-dispatched prep flow with a push: branches: [main] trigger backed by a committed .release-toolkit-manifest.json state file and a shell-based decision engine (scripts/release-decide.sh). On every push to main, the workflow walks git log <last_released_sha>..HEAD and decides one of three modes: noop (no release-relevant content), update (refresh the rolling release-prep PR with the accumulated bump), or cut (the operator merged the rolling PR — fire draft-release.sh + commit-and-push the manifest update). The substrate-honest escape from the Forgejo Actions expression-engine bug (#41 / #47) that constrained the v0.3.x flow — no ${{ github.event.* }} / ${{ forgejo.event.* }} accesses on the load-bearing path.

Fixed

  • scripts/release-prep.sh: DRY_RUN_INPUT/DRY_RUN_ENV env-var sources now use truthy semantics — the literal string "false" no longer falsely enables dry-run (closes #70).
  • scripts/release-prep.sh + .forgejo/workflows/_release.yml: defensive git identity setup before git commit — works on fresh CI runner containers without pre-configured git config; configurable via RELEASE_TOOLKIT_GIT_NAME / RELEASE_TOOLKIT_GIT_EMAIL env vars; consumer-provided config preserved (closes #73).
### Added **Push-triggered rolling-release-PR mechanic** — v0.4.0 replaces the v0.3.x operator-dispatched prep flow with a `push: branches: [main]` trigger backed by a committed `.release-toolkit-manifest.json` state file and a shell-based decision engine ([`scripts/release-decide.sh`](https://git.frankenbit.de/frankenbit/release-toolkit/src/branch/main/scripts/release-decide.sh)). On every push to main, the workflow walks `git log <last_released_sha>..HEAD` and decides one of three modes: `noop` (no release-relevant content), `update` (refresh the rolling release-prep PR with the accumulated bump), or `cut` (the operator merged the rolling PR — fire `draft-release.sh` + commit-and-push the manifest update). The substrate-honest escape from the Forgejo Actions expression-engine bug ([#41](https://git.frankenbit.de/frankenbit/release-toolkit/issues/41) / [#47](https://git.frankenbit.de/frankenbit/release-toolkit/issues/47)) that constrained the v0.3.x flow — no `${{ github.event.* }}` / `${{ forgejo.event.* }}` accesses on the load-bearing path. ### Fixed - **`scripts/release-prep.sh`**: `DRY_RUN_INPUT`/`DRY_RUN_ENV` env-var sources now use truthy semantics — the literal string `"false"` no longer falsely enables dry-run (closes [#70](https://git.frankenbit.de/frankenbit/release-toolkit/issues/70)). - **`scripts/release-prep.sh`** + **`.forgejo/workflows/_release.yml`**: defensive git identity setup before `git commit` — works on fresh CI runner containers without pre-configured git config; configurable via `RELEASE_TOOLKIT_GIT_NAME` / `RELEASE_TOOLKIT_GIT_EMAIL` env vars; consumer-provided config preserved (closes [#73](https://git.frankenbit.de/frankenbit/release-toolkit/issues/73)).
quartermaster force-pushed release-prep/rolling from 3cadde5a17 to 5f4812d76f
All checks were successful
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 4s
manifest-check / check (pull_request) Successful in 0s
release / decide + act (push) Recovered via manual manifest push at 595c10f (see #78)
release / release (push) Recovered via manual manifest push at 595c10f (see #78)
2026-06-25 22:03:14 +02:00
Compare
alex approved these changes 2026-06-25 22:10:46 +02:00
surveyor approved these changes 2026-06-25 22:11:48 +02:00
surveyor left a comment

Gate-1 review — v0.4.0 rolling-release PR

Verdict: APPROVED (advisory — operator/QM is the merge-gate). Pinned to head 5f4812d.

Full at-source pass on the rolling-PR shape. Every load-bearing claim verified against a fresh scratch clone at the head SHA.

Verified at source

  • VERSION = 0.4.0 — correct minor bump from 0.3.5 (.added.md fragment drives minor; bump_level_max(minor, patch) = minor).
  • Manifest untouched — still at the v0.3.5 bootstrap (last_released_sha=ee4a9b4…, last_released_version=0.3.5). Correct: the rolling-prep PR must not write the manifest; the cut path commits it on merge.
  • CHANGELOG## [v0.4.0] - 2026-06-25 is a pure +11/-0 prepend; existing [v0.3.5]/[v0.3.4] sections untouched. Section ordering correct ([Unreleased][v0.4.0][v0.3.5]).
  • Fragment consumption — the three changelog.d/ fragments (52/70/73) are deleted, composed into the section. The §Fixed bullets are the operator-folded condensed summaries of the verbose fragment bodies; both closes #70 and closes #73 links are preserved (the load-bearing trace survives the fold — no distinct fix silently dropped).
  • PR body ↔ CHANGELOG — §Added paragraph + §Fixed bullets match verbatim.
  • CI — combined state success (both manifest-check jobs green).

Cut-path readiness (forward-looking)

  • Walk window soundee4a9b4 (last_released_sha) is an ancestor of HEAD; git log ee4a9b4..HEAD = the full 9-commit v0.4.0 arc.
  • Draft source confirmeddraft-release.sh extracts the release body via changelog_get_section_content "$CHANGELOG" "$VERSION" (the ## [v0.4.0] section), not changelog.d/. So the deleted fragments are correct — the cut drafts from the already-composed section. VERSION=0.4.0 resolves the ## [v0.4.0] heading.

One note, not a blocker: merging this PR fires the first live exercise of the cut path — the 3-layer cut-safeguard + manifest commit+push. This is the empirical backstop that #64's deferred Layer-2/3 FAIL-path tests leaned on. The happy-path detection was design-verified pre-merge (mode=cut via the prepare-subject + release-prep/rolling head-ref); the merge is its first real run. I'll watch the cut → draft when the operator merges.

Clean to merge whenever the operator takes their cadence.

## Gate-1 review — v0.4.0 rolling-release PR **Verdict: APPROVED** (advisory — operator/QM is the merge-gate). Pinned to head `5f4812d`. Full at-source pass on the rolling-PR shape. Every load-bearing claim verified against a fresh scratch clone at the head SHA. ### Verified at source - **VERSION** = `0.4.0` — correct **minor** bump from `0.3.5` (`.added.md` fragment drives minor; `bump_level_max(minor, patch) = minor`). - **Manifest untouched** — still at the v0.3.5 bootstrap (`last_released_sha=ee4a9b4…`, `last_released_version=0.3.5`). Correct: the rolling-prep PR must not write the manifest; the **cut** path commits it on merge. - **CHANGELOG** — `## [v0.4.0] - 2026-06-25` is a pure `+11/-0` prepend; existing `[v0.3.5]`/`[v0.3.4]` sections untouched. Section ordering correct (`[Unreleased]` → `[v0.4.0]` → `[v0.3.5]`). - **Fragment consumption** — the three `changelog.d/` fragments (`52`/`70`/`73`) are deleted, composed into the section. The §Fixed bullets are the operator-folded condensed summaries of the verbose fragment bodies; **both `closes #70` and `closes #73` links are preserved** (the load-bearing trace survives the fold — no distinct fix silently dropped). - **PR body ↔ CHANGELOG** — §Added paragraph + §Fixed bullets match verbatim. - **CI** — combined state `success` (both manifest-check jobs green). ### Cut-path readiness (forward-looking) - **Walk window sound** — `ee4a9b4` (last_released_sha) is an ancestor of HEAD; `git log ee4a9b4..HEAD` = the full 9-commit v0.4.0 arc. - **Draft source confirmed** — `draft-release.sh` extracts the release body via `changelog_get_section_content "$CHANGELOG" "$VERSION"` (the `## [v0.4.0]` section), **not** `changelog.d/`. So the deleted fragments are correct — the cut drafts from the already-composed section. `VERSION=0.4.0` resolves the `## [v0.4.0]` heading. **One note, not a blocker:** merging this PR fires the **first live exercise of the cut path** — the 3-layer cut-safeguard + manifest commit+push. This is the empirical backstop that #64's deferred Layer-2/3 FAIL-path tests leaned on. The happy-path detection was design-verified pre-merge (mode=cut via the prepare-subject + `release-prep/rolling` head-ref); the merge is its first real run. I'll watch the cut → draft when the operator merges. Clean to merge whenever the operator takes their cadence.
Sign in to join this conversation.
No description provided.